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; make sure you deliver any generated credentials or keep the request passwordless when you want Clearmind to handle login links/OTPs.
  4. Handle JSON responses. Successful mutations return a human-readable message plus the lifecycle event that was persisted.
  5. 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

  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.

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:

  1. Deliver the subscriber’s identifier (email, phone, or username) and, if you supplied one, the initial password.
  2. If you created a passwordless account, send the appropriate magic link or OTP through your normal channels.
  3. 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.