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; make sure you deliver any generated credentials or keep the request passwordless when you want Clearmind to handle login links/OTPs.- Handle JSON responses. Successful mutations return a human-readable
messageplus the lifecycleeventthat was persisted. - Treat any non-2xx status as an error; the body always follows
{ "error": "..." }.
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. |
Endpoints
All endpoints share the path https://v1.api.clearmindmeditation.app/subscriptions.
Create Subscription (POST)
Creates a new subscriber and auto-renewing subscription. If the identifier already exists in a canceled state, the call reactivates it and returns 200 OK. When the identifier is brand new, Clearmind provisions the user account alongside the subscription; you are responsible for delivering any credentials to that user or offering a passwordless experience.
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",
"password": "clearmind1",
"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",
password: "clearmind1",
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",
password = "clearmind1",
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',
'password' => 'clearmind1',
'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. |
password |
string | No | Optional account password (≥6 characters). Omit for passwordless. |
metadata |
object | No | Free-form JSON persisted with the event and user profile. |
Exactly one of msisdn, email, or username must be present. Leave password out to issue a passwordless account—ideal when you prefer email magic links, SMS OTP, or other non-credential flows.
Responses
| Status | Description |
|---|---|
201 Created |
New subscription created and event logged. |
200 OK |
Existing subscription reactivated; event logged. |
400 Bad Request |
Validation failure (missing identifier, short password, missing/invalid country, already active subscription, etc.). |
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",
"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",
"metadata": {
"price": {
"amount": "100",
"currency": "TRY"
}
},
"country": "tr"
}
}
Fulfillment & Delivery
After you receive a successful response, complete the subscription onboarding flow on your side:
- Deliver the subscriber’s identifier (email, phone, or username) and, if you supplied one, the initial password.
- If you created a passwordless account, send the appropriate magic link or OTP through your normal channels.
- Share the universal landing URL
http://go.clearmindmeditation.app/. It automatically detects the platform and locale, redirecting users to the App Store, Play Store, or Clearmind web experience with the correct country storefront.
This hand-off keeps control of the end-user messaging with you while ensuring every subscriber reaches the right Clearmind entry point.
200 OK response (reactivated)
{
"message": "Subscription reactivated successfully",
"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",
"metadata": {},
"country": "tr"
}
}
Cancel Subscription (DELETE)
Cancels an active subscription by appending a canceled event. Requests with no matching active subscription return 400 Bad Request.
Cancel subscription
curl -X DELETE "https://v1.api.clearmindmeditation.app/subscriptions?msisdn=+447123456789" \
-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");
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";
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'
]
]);
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. |
Responses
| Status | Description |
|---|---|
200 OK |
Subscription canceled; event payload returned. |
400 Bad Request |
Invalid identifier format, subscriber not found, or subscription already inactive. |
403 Forbidden |
Partner credentials missing or rejected. |
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",
"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",
"metadata": {
"reason": "partner_cancellation"
},
"country": "tr"
}
}
Reactivate Subscription (PUT)
Explicitly reactivates a canceled subscription by emitting a reactivated event. Use when you want a dedicated reactivation call instead of relying on POST auto-reactivation.
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",
"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",
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",
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',
'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. |
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; event payload returned. |
400 Bad Request |
Identifier invalid, subscriber missing, or the subscription is not currently canceled. |
403 Forbidden |
Partner credentials missing or rejected. |
500 Internal Server Error |
Reactivation event could not be written (for example missing historical country data or database failures). |
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",
"auto_renew": true,
"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",
"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",
"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",
"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. |
auto_renew |
boolean | Always true for subscriptions managed by this API. |
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 |
|---|---|
204 No Content |
API is up and responding. |
403 Forbidden |
You accidentally included invalid auth headers. |
500 Internal Server Error |
Unexpected failure; retry before raising an incident. |
Support
Need production assistance, new credentials, or expanded functionality? Email team@clearmindmeditation.app or monitor real-time availability at https://status.clearmindmeditation.app.
Errors
All error responses share the same envelope:
{ "error": "message" }
| Status | When it happens | Example message |
|---|---|---|
400 Bad Request |
Identifier missing/duplicated, invalid format, missing country, short password, attempting to cancel/reactivate an already inactive or active subscription, or any other validation failure. | "Subscription is already active. Auto-renewing subscriptions renew automatically." |
403 Forbidden |
x-partner-id or x-auth-token was missing, malformed, or rejected. |
"Authentication failed" |
404 Not Found |
No subscriber exists for the supplied identifier (GET only). |
"User not found" |
500 Internal Server Error |
Unexpected error in Clearmind services. Retry; contact support if persistent. | "Unexpected error while retrieving the subscription status." |
405 Method Not Allowed |
HTTP verb not supported on the subscriptions route. | "Method Not Allowed" |
If you receive an error string not covered above, please capture the response body and timestamp before contacting team@clearmindmeditation.app.