NAV
cURL Node.js C# php

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

  1. Pick an identifier (msisdn, email, or username) and stick to a single value per request.
  2. Send the appropriate method to /subscriptions with the sandbox or production partner headers (x-partner-id, x-auth-token).
  3. POST automatically provisions a Clearmind user if one does not already exist. The implementation partner is responsible for delivering all subscriber credentials and onboarding messages.
  4. Handle JSON responses. Successful mutations return a human-readable message, a stable result, whether the lifecycle changed, the resulting status, and the relevant lifecycle event.
  5. Treat any non-2xx status as an error; the body follows { "error": "Human-readable message", "code": "invalid_email" }. Compare code, 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

  1. POST – Creates a new auto-renewing subscription. If the subscriber previously canceled, the same call reactivates the existing record.
  2. DELETE – Cancels an active subscription and appends a canceled event.
  3. PUT – Explicitly reactivates a previously canceled subscription when you want a separate reactivation call.
  4. GET – Returns the current lifecycle status plus the immutable event history.
  5. 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:

  1. Future-dated subscription starts on POST
  2. Future-dated renewals or reactivations on PUT
  3. 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:

  1. Deliver the exact identifier you used (email, username, or msisdn) to the subscriber.
  2. If you supplied password, deliver that initial password through an appropriately secure channel.
  3. Optionally set generate_login_token to true and include the returned login_url in the welcome SMS or email. The link signs the subscriber in automatically, expires after 72 hours, and works only in the Clearmind web app.
  4. Optionally append &hl={language} to the returned login_url to select the language for the subscriber's first web onboarding. Without a login token, use https://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_token is optional and defaults to false. 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.