Developer Docs

Promoter API

Resell ILMU memberships from your own platform. Provision users, grant subscriptions, and sign them in with one-time magic links — all over a simple, key-authenticated REST API. Every request is sandboxed to the users your key creates.

Base URL https://ilmuhq.com/api/v1

Introduction

The Promoter API lets approved partners sell ILMU memberships alongside their own products. You receive an API key tied to a platform name and domain; from there you can create users, grant or extend plans, and issue magic login links. Responses are JSON with a top-level data object on success and an error object on failure.

Keys are issued by an ILMU administrator. Each user you create gets the email {external_id}@{your-domain}, so the domain on your key must be one you control.

Authentication

Authenticate every request with your secret key in an Authorization: Bearer header (an X-Api-Key header is also accepted). Keys are shown only once at creation — store yours securely and never expose it in client-side code. A missing, invalid, or revoked key returns 401.

Header
Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12

Errors

Authentication failures return a structured error object. Validation failures return 422 with a message and field-level errors. Because your key is sandboxed, addressing a user or order you don't own returns 404 — identical to one that doesn't exist.

401Unauthenticated. Missing, invalid, or revoked API key.
404Not found. The user or order doesn't exist, or isn't owned by your key.
422Unprocessable. Validation failed — e.g. a duplicate external_id, an unknown plan, or a login request for a user with no active subscription.
429Too many requests. You exceeded the rate limit. Back off and retry.
401 response
JSON
{
  "error": {
    "code": "unauthenticated",
    "message": "A valid API key is required."
  }
}

Rate limits

API requests are limited to 120 per minute per key. The magic-link redemption URL is separately limited to 30 per minute. Exceeding a limit returns 429 with a Retry-After header.

Users

Provision and manage the end-users you onboard. Every user you create is sandboxed to your key — you can never see or touch users created by another promoter or via normal sign-up.

POST /api/v1/users

Create a user

Creates a verified student account. The login email is derived as {external_id}@{your-domain} and returned in the response — use it for your own records.

Body parameters
FieldTypeRequiredDescription
external_id string Required Your unique id for the user (letters, numbers, . _ -). Unique within your key.
name string Required The user's display name.
Request
cURL
curl -X POST https://ilmuhq.com/api/v1/users \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12" \
  -H "Content-Type: application/json" \
  -d '{"external_id": "alice", "name": "Alice Tan"}'
Response 201 Created
JSON
{
  "data": {
    "external_id": "alice",
    "email": "alice@acme.com"
  }
}
PATCH /api/v1/users/{external_id}

Update a user profile

Updates the name and personal details. The email is promoter-derived and cannot be changed.

Body parameters
FieldTypeRequiredDescription
name string Optional New display name.
date_of_birth date Optional ISO date, must be in the past. Send null to clear.
timezone string Optional IANA timezone, e.g. Asia/Dubai.
Request
cURL
curl -X PATCH https://ilmuhq.com/api/v1/users/alice \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12" \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice T.", "timezone": "Asia/Dubai"}'
Response 200 OK
JSON
{
  "data": {
    "external_id": "alice",
    "email": "alice@acme.com",
    "name": "Alice T."
  }
}
POST /api/v1/users/{external_id}/suspend

Suspend a user

Blocks the user from signing in. Any existing session is invalidated on their next request.

Request
cURL
curl -X POST https://ilmuhq.com/api/v1/users/alice/suspend \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12"
Response 200 OK
JSON
{
  "data": { "success": true, "suspended": true }
}
POST /api/v1/users/{external_id}/unsuspend

Restore a user

Lifts a suspension and restores normal access.

Request
cURL
curl -X POST https://ilmuhq.com/api/v1/users/alice/unsuspend \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12"
Response 200 OK
JSON
{
  "data": { "success": true, "suspended": false }
}
DELETE /api/v1/users/{external_id}

Delete a user

Permanently deletes the user and their linked orders and subscriptions. This cannot be undone.

Request
cURL
curl -X DELETE https://ilmuhq.com/api/v1/users/alice \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12"
Response 200 OK
JSON
{
  "data": { "success": true }
}

Plans & Orders

Grant access by creating a plan (a comped order + active subscription), extend it, or remove it. Billing is settled on your side, so ILMU records these orders at a zero amount.

POST /api/v1/users/{external_id}/orders

Create a plan

Grants the user an active subscription to a plan for duration_days. Returns the order id and the resulting expiry date.

Body parameters
FieldTypeRequiredDescription
plan string Required The plan slug, e.g. premium, basic, starter.
duration_days integer Required Length of access in days (1–3650).
Request
cURL
curl -X POST https://ilmuhq.com/api/v1/users/alice/orders \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12" \
  -H "Content-Type: application/json" \
  -d '{"plan": "premium", "duration_days": 30}'
Response 201 Created
JSON
{
  "data": {
    "success": true,
    "order_id": "9f1c2b7e-3a44-4c0d-bf21-6d8e9a0c1234",
    "expiry_date": "2026-07-14T09:30:00+00:00"
  }
}
POST /api/v1/orders/{order_id}/extend

Add expiry duration

Extends the subscription tied to an order by duration_days. A lapsed subscription is reactivated and extended from today.

Body parameters
FieldTypeRequiredDescription
duration_days integer Required Number of days to add (1–3650).
Request
cURL
curl -X POST https://ilmuhq.com/api/v1/orders/9f1c2b7e-3a44-4c0d-bf21-6d8e9a0c1234/extend \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12" \
  -H "Content-Type: application/json" \
  -d '{"duration_days": 15}'
Response 200 OK
JSON
{
  "data": {
    "success": true,
    "order_id": "9f1c2b7e-3a44-4c0d-bf21-6d8e9a0c1234",
    "expiry_date": "2026-07-29T09:30:00+00:00"
  }
}
DELETE /api/v1/orders/{order_id}

Delete an order

Deletes the order and revokes the subscription it granted, removing the user's access.

Request
cURL
curl -X DELETE https://ilmuhq.com/api/v1/orders/9f1c2b7e-3a44-4c0d-bf21-6d8e9a0c1234 \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12"
Response 200 OK
JSON
{
  "data": { "success": true }
}

Magic-link login

Sign your users into ILMU with a one-time link. Request a link, then redirect the user's browser to it.

POST /api/v1/users/{external_id}/login

Create a magic link

Returns a single-use login URL valid for 1 minute. Requires an active subscription, otherwise responds 422. Redirect the user to magic_link in their browser — it logs them in and lands them on their dashboard.

Request
cURL
curl -X POST https://ilmuhq.com/api/v1/users/alice/login \
  -H "Authorization: Bearer ilmu_live_8f3a2c91b4e7d60a5f12"
Response 200 OK
JSON
{
  "data": {
    "magic_link": "https://ilmuhq.com/promoter/login/V1Stk...64-char-token"
  }
}

End-to-end flow

A typical sale on your platform maps to four calls and one redirect:

  1. Create the userPOST /users with your external_id and the buyer's name. Save the returned email.
  2. Grant the planPOST /users/{external_id}/orders with a plan slug and duration_days. Keep the returned order_id to extend or revoke later.
  3. Request a magic linkPOST /users/{external_id}/login. You'll get a magic_link valid for 1 minute.
  4. Redirect the buyer — send their browser to magic_link. They're signed into ILMU and dropped on their dashboard. Each link works exactly once.
Because the magic link expires in 1 minute and is single-use, always request it at the moment you're about to redirect the user — not in advance.