Overview
Welcome to the Clearmind Subscriptions API. This guide documents version 1 of the partner-facing subscription endpoints. All operations share a single resource path and behave differently based on the HTTP method you choose, and POST will create a subscriber record (with credentials you distribute) whenever one does not already exist. Accounts may be provisioned with email addresses, phone numbers, or PII-free alphanumeric usernames, and you can opt into passwordless onboarding simply by omitting the password field.
Both sandbox and production traffic use the same base URL: https://v1.api.clearmindmeditation.app/subscriptions. We issue separate partner credential pairs (ID + auth token) for sandbox and production access—IDs stay the same, so updating credentials only requires rotating the relevant token. A lightweight HEAD health check is available before you send traffic with either credential pair.
Health check (no authentication required)
curl -I "https://v1.api.clearmindmeditation.app/subscriptions"
const response = await fetch("https://v1.api.clearmindmeditation.app/subscriptions", {
method: "HEAD"
});
console.log(response.status);
using System.Net.Http;
using var client = new HttpClient();
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://v1.api.clearmindmeditation.app/subscriptions"));
Console.WriteLine(response.StatusCode);
<?php
use GuzzleHttp\\Client;
$client = new Client();
$response = $client->head('https://v1.api.clearmindmeditation.app/subscriptions');
echo $response->getStatusCode();
Quick Start
- Pick an identifier (
msisdn,email, orusername) and stick to a single value per request. - Send the appropriate method to
/subscriptionswith the sandbox or production partner headers (x-partner-id,x-auth-token). POSTautomatically provisions a Clearmind user if one does not already exist. The implementation partner is responsible for delivering all subscriber credentials and onboarding messages.- Handle JSON responses. Successful mutations return a human-readable
message, a stableresult, whether the lifecycle changed, the resulting status, and the relevant lifecycleevent. - Treat any non-2xx status as an error; the body follows
{ "error": "Human-readable message", "code": "invalid_email" }. Comparecode, never the message text.
Create subscription via MSISDN
curl -X POST "https://v1.api.clearmindmeditation.app/subscriptions" \
-H "x-partner-id: $PARTNER_ID" \
-H "x-auth-token: $PARTNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"msisdn": "+447123456789",
"country": "GB",
"password": "clearmind1",
"metadata": {
"price": { "amount": "100", "currency": "TRY" }
}
}'
const partnerId = process.env.PARTNER_ID;
const partnerToken = process.env.PARTNER_TOKEN;
const response = await fetch(
"https://v1.api.clearmindmeditation.app/subscriptions",
{
method: "POST",
headers: {
"x-partner-id": partnerId,
"x-auth-token": partnerToken,
"Content-Type": "application/json"
},
body: JSON.stringify({
msisdn: "+447123456789",
country: "GB",
password: "clearmind1",
metadata: {
price: { amount: "100", currency: "TRY" }
}
})
}
);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
console.log(await response.json());
using System.Net.Http;
using System.Net.Http.Json;
var partnerId = Environment.GetEnvironmentVariable("PARTNER_ID");
var partnerToken = Environment.GetEnvironmentVariable("PARTNER_TOKEN");
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://v1.api.clearmindmeditation.app/subscriptions");
request.Headers.Add("x-partner-id", partnerId);
request.Headers.Add("x-auth-token", partnerToken);
request.Content = JsonContent.Create(new
{
msisdn = "+447123456789",
country = "GB",
password = "clearmind1",
metadata = new
{
price = new { amount = "100", currency = "TRY" }
}
});
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());
<?php
use GuzzleHttp\\Client;
$client = new Client();
$response = $client->post('https://v1.api.clearmindmeditation.app/subscriptions', [
'headers' => [
'x-partner-id' => getenv('PARTNER_ID'),
'x-auth-token' => getenv('PARTNER_TOKEN'),
'Content-Type' => 'application/json'
],
'json' => [
'msisdn' => '+447123456789',
'country' => 'GB',
'password' => 'clearmind1',
'metadata' => [
'price' => [ 'amount' => '100', 'currency' => 'TRY' ]
]
]
]);
echo $response->getBody();
Subscription Flow
- POST – Creates a new auto-renewing subscription. If the subscriber previously canceled, the same call reactivates the existing record.
- DELETE – Cancels an active subscription and appends a
canceledevent. - PUT – Explicitly reactivates a previously canceled subscription when you want a separate reactivation call.
- GET – Returns the current lifecycle status plus the immutable event history.
- HEAD – Verifies the API is online; no authentication headers required.
Identifier Checklist
| Identifier | Format | Notes |
|---|---|---|
msisdn |
E.164 (e.g. +447123456789) |
Only digits after the leading +. 8–15 digits supported. |
email |
RFC 5322 compliant address | Stored and compared in lowercase. |
username |
^[A-Za-z0-9]{4,12}$ |
Case-insensitive; normalized to lowercase on ingest. |
Common Response Headers
| Header | Description |
|---|---|
X-API-Version |
Semantic version of the API (e.g. v1). |
X-API-Revision |
Internal documentation revision stamp (YYYYMMDD). |
Access-Control-Allow-Origin |
Always *. |
Authentication
Every mutating and read call (POST, PUT, DELETE, GET) requires the partner credentials we issued. Pass the headers with each request.
Authenticated request template
curl "https://v1.api.clearmindmeditation.app/subscriptions" \
-H "x-partner-id: $PARTNER_ID" \
-H "x-auth-token: $PARTNER_TOKEN"
| Header | Required | Description |
|---|---|---|
x-partner-id |
Always | Clearmind-issued partner UUID (one static ID for sandbox, another for production). |
x-auth-token |
Always | Shared secret associated with the partner UUID. Rotate per environment without changing the ID. |
The unauthenticated HEAD health probe is the only exception.
Partner IDs are long-lived identifiers; use them to target the correct dataset (sandbox vs. production). Auth tokens can be rotated or revoked independently—request a new token, update your secure store, and future calls will immediately use the replacement with no URL changes.
Request Identifiers
Exactly one identifier must be supplied per request. Providing multiple identifiers or omitting all identifiers returns 400 Bad Request.
| Field | Applies to | Notes |
|---|---|---|
msisdn |
POST, PUT, GET, DELETE | Mutually exclusive with email and username. |
email |
POST, PUT, GET, DELETE | Mutually exclusive with msisdn and username. |
username |
POST, PUT, GET, DELETE | Mutually exclusive with msisdn and email. |
You can create accounts with phone numbers or emails, or choose alphanumeric usernames when privacy rules prevent sharing personally identifiable information. This gives you flexibility to align with partner data-sharing requirements.
Subscription Events
Mutation endpoints emit immutable lifecycle events that appear in subsequent GET responses.
| Event | Description |
|---|---|
created |
Initial subscription creation for a subscriber. |
reactivated |
Subscription resumed after a cancellation. |
canceled |
Subscription terminated and auto-renew disabled. |
Effective Timing
Mutating endpoints support an optional effective_at timestamp. When omitted, Clearmind uses the request insertion time for both created_at and effective_at.
Use effective_at when you need the lifecycle change to take effect in the future:
- Future-dated subscription starts on
POST - Future-dated renewals or reactivations on
PUT - Future-dated cancellations on
DELETE
effective_at must be a valid ISO 8601 datetime string such as 2026-05-01T00:00:00Z.
VAS User Onboarding & Delivery
The Subscriptions API provisions the Clearmind account and subscription only. It does not send an OTP or magic link, and it does not deliver credentials to the subscriber. The implementation partner is responsible for the complete end-user onboarding, fulfillment, and credential-delivery flow.
After a successful POST:
- Deliver the exact identifier you used (
email,username, ormsisdn) to the subscriber. - If you supplied
password, deliver that initial password through an appropriately secure channel. - Optionally set
generate_login_tokentotrueand include the returnedlogin_urlin the welcome SMS or email. The link signs the subscriber in automatically, expires after 72 hours, and works only in the Clearmind web app. - Optionally append
&hl={language}to the returnedlogin_urlto select the language for the subscriber's first web onboarding. Without a login token, usehttps://web.clearmindmeditation.app/?hl={language}. This parameter affects the web app only.
Supported Clearmind language codes are:
| Code | Language |
|---|---|
en |
English |
es |
Spanish |
tr |
Turkish |
ar |
Arabic |
fr |
French |
pt |
Portuguese |
bn |
Bengali |
For example:
https://web.clearmindmeditation.app/login?token={login_token}&hl=es
Treat login_token and the complete login_url as bearer credentials: anyone who has the link can use it until it expires. Send it only through a private channel and do not store it in analytics or application logs.
Backward compatibility:
generate_login_tokenis optional and defaults tofalse. Existing integrations can continue sending the same request payloads. Login-token fields are added only when token generation is requested and succeeds.
Endpoints
All endpoints share the path https://v1.api.clearmindmeditation.app/subscriptions.
Create Subscription (POST)
Makes the subscriber's auto-renewing subscription active. A new subscriber, or an existing subscriber without subscription events, receives a new created event. A canceled subscription receives a reactivated event. Repeating the request for an active subscription returns 200 OK without writing a duplicate event. When the identifier is brand new, Clearmind provisions the user account alongside the subscription; see VAS User Onboarding & Delivery and Idempotency.
Create subscription
curl -X POST "https://v1.api.clearmindmeditation.app/subscriptions" \
-H "x-partner-id: $PARTNER_ID" \
-H "x-auth-token: $PARTNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "listener@example.com",
"country": "US",
"effective_at": "2026-05-01T00:00:00Z",
"password": "clearmind1",
"generate_login_token": true,
"metadata": {
"campaign": "summer_launch",
"price": { "amount": "9.99", "currency": "USD" }
}
}'
const response = await fetch(
"https://v1.api.clearmindmeditation.app/subscriptions",
{
method: "POST",
headers: {
"x-partner-id": process.env.PARTNER_ID,
"x-auth-token": process.env.PARTNER_TOKEN,
"Content-Type": "application/json"
},
body: JSON.stringify({
email: "listener@example.com",
country: "US",
effective_at: "2026-05-01T00:00:00Z",
password: "clearmind1",
generate_login_token: true,
metadata: {
campaign: "summer_launch",
price: { amount: "9.99", currency: "USD" }
}
})
}
);
console.log(await response.json());
using System.Net.Http;
using System.Net.Http.Json;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://v1.api.clearmindmeditation.app/subscriptions");
request.Headers.Add("x-partner-id", Environment.GetEnvironmentVariable("PARTNER_ID"));
request.Headers.Add("x-auth-token", Environment.GetEnvironmentVariable("PARTNER_TOKEN"));
request.Content = JsonContent.Create(new
{
email = "listener@example.com",
country = "US",
effective_at = "2026-05-01T00:00:00Z",
password = "clearmind1",
generate_login_token = true,
metadata = new
{
campaign = "summer_launch",
price = new { amount = "9.99", currency = "USD" }
}
});
using var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
<?php
use GuzzleHttp\\Client;
$client = new Client();
$response = $client->post('https://v1.api.clearmindmeditation.app/subscriptions', [
'headers' => [
'x-partner-id' => getenv('PARTNER_ID'),
'x-auth-token' => getenv('PARTNER_TOKEN'),
'Content-Type' => 'application/json'
],
'json' => [
'email' => 'listener@example.com',
'country' => 'US',
'effective_at' => '2026-05-01T00:00:00Z',
'password' => 'clearmind1',
'generate_login_token' => true,
'metadata' => [
'campaign' => 'summer_launch',
'price' => [ 'amount' => '9.99', 'currency' => 'USD' ]
]
]
]);
echo $response->getBody();
HTTP Request
POST /subscriptions
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
msisdn |
string | Conditional | Subscriber phone number in strict E.164 format. |
email |
string | Conditional | Subscriber email address. |
username |
string | Conditional | 4–12 character alphanumeric username. |
country |
string | Yes | ISO 3166-1 alpha-2 country code; stored lowercase. |
effective_at |
string | No | Optional ISO 8601 timestamp for a future-dated subscription start or reactivation. Defaults to the request insertion time when omitted. |
password |
string | No | Optional account password (≥6 characters). Omit for passwordless. |
generate_login_token |
boolean | No | When true, requests a signed web auto-login token with a 72-hour lifetime. Defaults to false. |
metadata |
object | No | Free-form JSON persisted with the event and user profile. |
Exactly one of msisdn, email, or username must be present. Omitting password creates a passwordless account. See VAS User Onboarding & Delivery for the implementation partner's delivery responsibilities.
When generate_login_token is true, a successful response can also include:
| Field | Description |
|---|---|
login_token |
RS256-signed web auto-login JWT. This is a bearer credential. |
login_token_expires_at |
ISO 8601 expiry timestamp, 72 hours after issuance. |
login_url |
Ready-to-send Clearmind web URL containing the token. Returned when the API web base URL is configured. |
For password-based accounts, the signed token contains the password needed for web auto-login. JWT payloads are signed but not encrypted, so use a private delivery channel and avoid logging either the token or URL.
Responses
| Status | Description |
|---|---|
201 Created |
Subscription created (result: created, changed: true, current_status: active), including when the subscriber account already exists without subscription events. |
200 OK |
Canceled subscription reactivated (result: reactivated, changed: true, current_status: active), or active subscription left unchanged (result: already_active, changed: false, current_status: active). |
400 Bad Request |
Request validation failed. Inspect the error code. |
403 Forbidden |
Partner credentials missing or rejected. |
500 Internal Server Error |
Unexpected failure while creating/reactivating (e.g., missing historical country data or event persistence failure). |
201 Created response
{
"message": "Auto-renewing subscription created successfully",
"result": "created",
"changed": true,
"current_status": "active",
"event": {
"id": "a5d60299-d4e0-4bb9-bfe8-d336c27bcc57",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "created",
"created_at": "2025-07-29T11:13:56.846989+00:00",
"effective_at": "2026-05-01T00:00:00.000Z",
"metadata": {
"price": {
"amount": "100",
"currency": "TRY"
}
},
"country": "tr"
}
}
201 Created response with
generate_login_token: true
{
"message": "Auto-renewing subscription created successfully",
"result": "created",
"changed": true,
"current_status": "active",
"event": {
"id": "a5d60299-d4e0-4bb9-bfe8-d336c27bcc57",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "created",
"created_at": "2026-07-31T12:00:00.000Z",
"effective_at": "2026-07-31T12:00:00.000Z",
"metadata": {
"login_token_issued": true
},
"country": "us"
},
"login_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"login_token_expires_at": "2026-08-03T12:00:00.000Z",
"login_url": "https://web.clearmindmeditation.app/login?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
200 OK response (reactivated)
{
"message": "Subscription reactivated successfully",
"result": "reactivated",
"changed": true,
"current_status": "active",
"event": {
"id": "210e4258-fbf1-4e43-a270-b94d27654d85",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "reactivated",
"created_at": "2025-07-29T11:24:39.260584+00:00",
"effective_at": "2026-06-01T00:00:00.000Z",
"metadata": {},
"country": "tr"
}
}
200 OK response (already active)
{
"message": "Subscription is already active",
"result": "already_active",
"changed": false,
"current_status": "active",
"event": {
"id": "210e4258-fbf1-4e43-a270-b94d27654d85",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "reactivated",
"created_at": "2025-07-29T11:24:39.260584+00:00",
"effective_at": "2026-06-01T00:00:00.000Z",
"metadata": {},
"country": "tr"
}
}
Cancel Subscription (DELETE)
Makes the subscriber's subscription inactive. An active subscription receives a canceled event. Repeating the request for an already canceled subscription, or canceling a subscriber with no subscription events, returns 200 OK without writing a duplicate event. Pass effective_at as an optional query parameter when you need a future-dated cancellation.
Cancel subscription
curl -X DELETE "https://v1.api.clearmindmeditation.app/subscriptions?msisdn=+447123456789&effective_at=2026-05-31T23:59:59Z" \
-H "x-partner-id: $PARTNER_ID" \
-H "x-auth-token: $PARTNER_TOKEN"
const url = new URL("https://v1.api.clearmindmeditation.app/subscriptions");
url.searchParams.set("msisdn", "+447123456789");
url.searchParams.set("effective_at", "2026-05-31T23:59:59Z");
const response = await fetch(url, {
method: "DELETE",
headers: {
"x-partner-id": process.env.PARTNER_ID,
"x-auth-token": process.env.PARTNER_TOKEN
}
});
console.log(await response.json());
using System.Net.Http;
var endpoint = "https://v1.api.clearmindmeditation.app/subscriptions?msisdn=%2B447123456789&effective_at=2026-05-31T23%3A59%3A59Z";
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Delete, endpoint);
request.Headers.Add("x-partner-id", Environment.GetEnvironmentVariable("PARTNER_ID"));
request.Headers.Add("x-auth-token", Environment.GetEnvironmentVariable("PARTNER_TOKEN"));
using var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
<?php
use GuzzleHttp\\Client;
$client = new Client();
$response = $client->delete('https://v1.api.clearmindmeditation.app/subscriptions', [
'headers' => [
'x-partner-id' => getenv('PARTNER_ID'),
'x-auth-token' => getenv('PARTNER_TOKEN')
],
'query' => [
'msisdn' => '+447123456789',
'effective_at' => '2026-05-31T23:59:59Z'
]
]);
echo $response->getBody();
HTTP Request
DELETE /subscriptions
Query Parameters
| Parameter | Required | Description |
|---|---|---|
msisdn |
Conditional | Mutually exclusive identifier. |
email |
Conditional | Mutually exclusive identifier. |
username |
Conditional | Mutually exclusive identifier. |
effective_at |
No | Optional ISO 8601 timestamp for a future-dated cancellation. Defaults to the request insertion time when omitted. |
Responses
| Status | Description |
|---|---|
200 OK |
Subscription canceled (result: canceled, changed: true, current_status: canceled), already canceled (result: already_canceled, changed: false, current_status: canceled), or already inactive (result: already_inactive, changed: false, current_status: none). |
400 Bad Request |
Request validation failed. Inspect the error code. |
403 Forbidden |
Partner credentials missing or rejected. |
404 Not Found |
No subscriber found (code: subscriber_not_found). |
500 Internal Server Error |
Cancellation event could not be written (for example missing historical country data or database failures). |
200 OK response
{
"message": "Subscription canceled successfully",
"result": "canceled",
"changed": true,
"current_status": "canceled",
"event": {
"id": "c11121a9-38a3-43dd-b66c-3f4663463d8f",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "canceled",
"created_at": "2025-07-29T11:18:31.230371+00:00",
"effective_at": "2026-05-31T23:59:59.000Z",
"metadata": {
"reason": "partner_cancellation"
},
"country": "tr"
}
}
200 OK response (already canceled)
{
"message": "Subscription is already canceled",
"result": "already_canceled",
"changed": false,
"current_status": "canceled",
"event": {
"id": "c11121a9-38a3-43dd-b66c-3f4663463d8f",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "canceled",
"created_at": "2025-07-29T11:18:31.230371+00:00",
"effective_at": "2026-05-31T23:59:59.000Z",
"metadata": {
"reason": "partner_cancellation"
},
"country": "tr"
}
}
200 OK response (subscriber already inactive)
{
"message": "Subscription is already inactive",
"result": "already_inactive",
"changed": false,
"current_status": "none",
"event": null
}
Reactivate Subscription (PUT)
Makes an existing subscription active. A canceled subscription receives a reactivated event; repeating the request for an active subscription returns 200 OK without writing a duplicate event. A subscriber without subscription events must be activated with POST. Pass effective_at when the reactivation should take effect in the future.
Reactivate subscription
curl -X PUT "https://v1.api.clearmindmeditation.app/subscriptions" \
-H "x-partner-id: $PARTNER_ID" \
-H "x-auth-token: $PARTNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "listener@example.com",
"effective_at": "2026-06-01T00:00:00Z",
"metadata": {
"plan": "standard"
}
}'
const response = await fetch(
"https://v1.api.clearmindmeditation.app/subscriptions",
{
method: "PUT",
headers: {
"x-partner-id": process.env.PARTNER_ID,
"x-auth-token": process.env.PARTNER_TOKEN,
"Content-Type": "application/json"
},
body: JSON.stringify({
email: "listener@example.com",
effective_at: "2026-06-01T00:00:00Z",
metadata: { plan: "standard" }
})
}
);
console.log(await response.json());
using System.Net.Http;
using System.Net.Http.Json;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Put, "https://v1.api.clearmindmeditation.app/subscriptions");
request.Headers.Add("x-partner-id", Environment.GetEnvironmentVariable("PARTNER_ID"));
request.Headers.Add("x-auth-token", Environment.GetEnvironmentVariable("PARTNER_TOKEN"));
request.Content = JsonContent.Create(new
{
email = "listener@example.com",
effective_at = "2026-06-01T00:00:00Z",
metadata = new { plan = "standard" }
});
using var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
<?php
use GuzzleHttp\\Client;
$client = new Client();
$response = $client->put('https://v1.api.clearmindmeditation.app/subscriptions', [
'headers' => [
'x-partner-id' => getenv('PARTNER_ID'),
'x-auth-token' => getenv('PARTNER_TOKEN'),
'Content-Type' => 'application/json'
],
'json' => [
'email' => 'listener@example.com',
'effective_at' => '2026-06-01T00:00:00Z',
'metadata' => [ 'plan' => 'standard' ]
]
]);
echo $response->getBody();
HTTP Request
PUT /subscriptions
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
msisdn |
string | Conditional | Subscriber phone number in E.164 format. |
email |
string | Conditional | Subscriber email address. |
username |
string | Conditional | Subscriber username. |
effective_at |
string | No | Optional ISO 8601 timestamp for a future-dated renewal/reactivation. Defaults to the request insertion time when omitted. |
metadata |
object | No | Free-form JSON stored with the reactivation event. |
Exactly one identifier is required; providing multiple identifiers returns 400 Bad Request.
Responses
| Status | Description |
|---|---|
200 OK |
Subscription reactivated (result: reactivated, changed: true, current_status: active) or already active (result: already_active, changed: false, current_status: active). |
400 Bad Request |
Request validation failed. Inspect the error code. |
403 Forbidden |
Partner credentials missing or rejected. |
404 Not Found |
Subscriber missing (code: subscriber_not_found) or subscriber has no subscription (code: subscription_not_found). |
500 Internal Server Error |
Reactivation event could not be written (for example missing historical country data or database failures). |
200 OK response (reactivated)
{
"message": "Subscription reactivated successfully",
"result": "reactivated",
"changed": true,
"current_status": "active",
"event": {
"id": "210e4258-fbf1-4e43-a270-b94d27654d85",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "reactivated",
"created_at": "2025-07-29T11:24:39.260584+00:00",
"effective_at": "2026-06-01T00:00:00.000Z",
"metadata": {},
"country": "tr"
}
}
200 OK response (already active)
{
"message": "Subscription is already active",
"result": "already_active",
"changed": false,
"current_status": "active",
"event": {
"id": "210e4258-fbf1-4e43-a270-b94d27654d85",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "reactivated",
"created_at": "2025-07-29T11:24:39.260584+00:00",
"effective_at": "2026-06-01T00:00:00.000Z",
"metadata": {},
"country": "tr"
}
}
Get Subscription Status (GET)
Returns the subscriber’s current lifecycle status and historical events.
Fetch subscription status
curl "https://v1.api.clearmindmeditation.app/subscriptions?email=listener@example.com" \
-H "x-partner-id: $PARTNER_ID" \
-H "x-auth-token: $PARTNER_TOKEN"
const url = new URL("https://v1.api.clearmindmeditation.app/subscriptions");
url.searchParams.set("email", "listener@example.com");
const response = await fetch(url, {
headers: {
"x-partner-id": process.env.PARTNER_ID,
"x-auth-token": process.env.PARTNER_TOKEN
}
});
console.log(await response.json());
using System.Net.Http;
var endpoint = "https://v1.api.clearmindmeditation.app/subscriptions?email=listener%40example.com";
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, endpoint);
request.Headers.Add("x-partner-id", Environment.GetEnvironmentVariable("PARTNER_ID"));
request.Headers.Add("x-auth-token", Environment.GetEnvironmentVariable("PARTNER_TOKEN"));
using var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
<?php
use GuzzleHttp\\Client;
$client = new Client();
$response = $client->get('https://v1.api.clearmindmeditation.app/subscriptions', [
'headers' => [
'x-partner-id' => getenv('PARTNER_ID'),
'x-auth-token' => getenv('PARTNER_TOKEN')
],
'query' => [
'email' => 'listener@example.com'
]
]);
echo $response->getBody();
HTTP Request
GET /subscriptions
Query Parameters
| Parameter | Required | Description |
|---|---|---|
msisdn |
Conditional | Mutually exclusive identifier. |
email |
Conditional | Mutually exclusive identifier. |
username |
Conditional | Mutually exclusive identifier. |
Responses
| Status | Description |
|---|---|
200 OK |
Status and event history returned. |
400 Bad Request |
Invalid identifier format or multiple identifiers supplied. |
403 Forbidden |
Partner credentials missing or rejected. |
404 Not Found |
No subscriber found for the supplied identifier. |
500 Internal Server Error |
Unexpected failure while retrieving status. |
200 OK response
{
"msisdn": "+440123456321",
"identifier_type": "phone",
"identifier_value": "+440123456321",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"current_status": "active",
"events": [
{
"id": "a5d60299-d4e0-4bb9-bfe8-d336c27bcc57",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "created",
"created_at": "2025-07-29T11:13:56.846989+00:00",
"effective_at": "2025-07-29T11:13:56.846989+00:00",
"metadata": {
"price": {
"amount": "100",
"currency": "TRY"
}
},
"country": "tr"
},
{
"id": "c11121a9-38a3-43dd-b66c-3f4663463d8f",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "canceled",
"created_at": "2025-07-29T11:18:31.230371+00:00",
"effective_at": "2026-05-31T23:59:59.000Z",
"metadata": {
"reason": "partner_cancellation"
},
"country": "tr"
},
{
"id": "210e4258-fbf1-4e43-a270-b94d27654d85",
"partner_id": "f9f9efe1-1b9a-4e87-994a-fb3e5fc3e784",
"user_id": "067f0e9b-c11b-4f6a-984c-07b90440dc7d",
"event": "reactivated",
"created_at": "2025-07-29T11:24:39.260584+00:00",
"effective_at": "2026-06-01T00:00:00.000Z",
"metadata": {},
"country": "tr"
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
identifier_type |
string | phone, email, or username depending on the supplied identifier. |
identifier_value |
string | Normalized identifier echo. |
msisdn |
string/null | Only present for phone identifiers. |
email |
string/null | Only present for email identifiers. |
username |
string/null | Only present for username identifiers. |
user_id |
string | UUID of the subscriber in Clearmind systems. |
current_status |
string | none, active, or canceled. |
events |
array | Ordered lifecycle events (see Subscription Events). |
Health Check (HEAD)
Performs an unauthenticated readiness probe. Use before sending production traffic.
Health check
curl -I "https://v1.api.clearmindmeditation.app/subscriptions"
HTTP Request
HEAD /subscriptions
Responses
| Status | Description |
|---|---|
200 OK |
API is ready. |
503 Service Unavailable |
A readiness check failed; retry before raising an incident. |
Support
Need production assistance, new credentials, or expanded functionality? Email team@clearmindmeditation.app.
Idempotency
The mutation endpoints describe a desired subscription state and are safe to retry. A repeated request returns a successful response without writing a duplicate lifecycle event when the subscription is already in the requested state. Requests for the same identifier are serialized so that concurrent state transitions cannot both append the same transition.
There is no special HTTP status for an idempotent no-op. Inspect the stable result and changed fields:
| Field | Type | Description |
|---|---|---|
result |
string | Machine-readable outcome described in the table below. |
changed |
boolean | true when this request appended a lifecycle event; false when the requested state already existed. |
current_status |
string | Subscription status after the request: active, canceled, or none. |
message |
string | Human-readable summary. Do not use it for program logic. |
event |
object/null | Event appended by this request, or the latest relevant event for an idempotent no-op. It is null when the subscriber exists but has no lifecycle events. |
| Method | State before request | HTTP status | result |
changed |
State after request |
|---|---|---|---|---|---|
POST |
Subscriber is new, or exists without subscription events | 201 Created |
created |
true |
active |
POST |
canceled |
200 OK |
reactivated |
true |
active |
POST |
active |
200 OK |
already_active |
false |
active |
PUT |
canceled |
200 OK |
reactivated |
true |
active |
PUT |
active |
200 OK |
already_active |
false |
active |
PUT |
Subscriber exists without subscription events | 404 Not Found |
Error code subscription_not_found |
— | none |
PUT |
Subscriber does not exist | 404 Not Found |
Error code subscriber_not_found |
— | — |
DELETE |
active |
200 OK |
canceled |
true |
canceled |
DELETE |
canceled |
200 OK |
already_canceled |
false |
canceled |
DELETE |
Subscriber exists without subscription events | 200 OK |
already_inactive |
false |
none |
DELETE |
Subscriber does not exist | 404 Not Found |
Error code subscriber_not_found |
— | — |
Idempotent 200 OK response
{
"message": "Subscription is already active",
"result": "already_active",
"changed": false,
"current_status": "active",
"event": {
"id": "a5d60299-d4e0-4bb9-bfe8-d336c27bcc57",
"event": "created",
"effective_at": "2026-05-01T00:00:00.000Z"
}
}
Errors
Errors on the subscriptions route use an additive JSON envelope:
{
"error": "Invalid email format",
"code": "invalid_email"
}
error is a human-readable explanation and may be refined without notice. code is the stable, lower snake_case value intended for program logic. Clients should compare code and never match the error text.
Error Code Reference
| Code | HTTP status | When it happens |
|---|---|---|
invalid_json |
400 Bad Request |
A non-empty POST, PUT, or DELETE body is not valid JSON. |
identifier_required |
400 Bad Request |
None of msisdn, email, or username was supplied. |
multiple_identifiers |
400 Bad Request |
More than one subscriber identifier was supplied. |
invalid_msisdn |
400 Bad Request |
msisdn cannot be normalized to E.164 format. |
invalid_email |
400 Bad Request |
email is not valid. |
invalid_username |
400 Bad Request |
username is not 4–12 alphanumeric characters. |
invalid_effective_at |
400 Bad Request |
effective_at is not a valid ISO 8601 datetime. |
password_too_short |
400 Bad Request |
A supplied password is shorter than six characters. |
country_required |
400 Bad Request |
country is missing from a subscription-creation request. |
invalid_country |
400 Bad Request |
country is not a two-character ISO 3166-1 alpha-2 code. |
authentication_failed |
403 Forbidden |
Partner credentials are missing or rejected. |
subscriber_not_found |
404 Not Found |
The supplied identifier does not match a subscriber. |
subscription_not_found |
404 Not Found |
The subscriber exists but has no subscription to reactivate. |
route_not_found |
404 Not Found |
The requested path is not an API route. |
method_not_allowed |
405 Method Not Allowed |
The HTTP method is not supported on the subscriptions route. |
login_token_configuration_error |
500 Internal Server Error |
A login token was requested but server-side token signing is not configured. |
user_creation_failed |
500 Internal Server Error |
The subscriber account could not be provisioned. |
subscription_creation_failed |
500 Internal Server Error |
The creation event could not be persisted. |
subscription_reactivation_failed |
500 Internal Server Error |
The reactivation event could not be persisted. |
subscription_cancellation_failed |
500 Internal Server Error |
The cancellation event could not be persisted. |
subscription_country_missing |
500 Internal Server Error |
Historical subscription data does not contain the required country. |
internal_error |
500 Internal Server Error |
An unexpected service failure occurred. |
Validation errors should be corrected before retrying. For authentication_failed, verify the environment-specific partner ID and token. A 500 response can be retried with backoff; contact support if it persists, and include the response body and timestamp.
Need help interpreting an error? Contact team@clearmindmeditation.app.