Docs

Partner API

For approved partners: make Chart Premium activation codes for your clients from your own systems (CRM, client area, onboarding), and see which ones were used. About the partner programme.

Authentication

Create a key on your partner page and send it in the Authorization header. Keys look like mdp_pk_3f9a1c07de_…; we keep only a fingerprint, so a lost key cannot be shown again: make a new one.

curl https://app.marketapi.app/partner/v1/account \
  -H "Authorization: Bearer mdp_pk_YOUR_KEY"

Rotation without downtime: Rotate makes a new key and keeps the old one working for 24 hours. Put the new key in your systems, then the old one expires by itself (or revoke it at once). Never put a key in a web page or mobile app: call the API from your server.

Limits: 120 requests a minute per partner; too many failed keys from one address are blocked for 10 minutes. Errors are JSON: {"error": "…", "code": "invalid"} with HTTP 400, 401, 405 or 429.

Your seats

GET /partner/v1/account

{"partner_id": "MP-7KQ3TA", "name": "Example Broker", "status": "active",
 "seats": [{"plan": "pro", "name": "Pro", "days": 30, "left": 48, "trial": false, "expires_at": null}]}

Each seat is one activation code for a plan and a length (30, 91, 182 or 365 days). Buy seat packs on your partner page (30% off the normal price, packs of 10, 50, 250).

Make codes

POST /partner/v1/codes with a JSON body:

FieldMeaning
planpro or proplus
months1, 3, 6 or 12 (the seat length), or days
counthow many codes (1–5000); may be left out when you give references
customer_refsoptional: your own reference for each code (e.g. the client's account number), up to 120 characters each. We store it masked (45•••68) with a keyed fingerprint, so you can find a code by the full reference but we never keep it.
expires_dayshow long an unused code stays valid (default 365; trial seats end sooner). An unused code that expires gives its seat back.
batchoptional name to recognise the batch

Send an Idempotency-Key header (any unique text): if your request is retried, you get the same codes back instead of new ones (for 24 hours).

curl -X POST https://app.marketapi.app/partner/v1/codes \
  -H "Authorization: Bearer mdp_pk_YOUR_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: onboarding-45123468" \
  -d '{"plan": "pro", "months": 1, "customer_refs": ["45123468"]}'
201 {"count": 1, "codes": [{"code": "K7QM-3XTP-9RWA-FD2H", "hint": "FD2H", "customer_ref": "45•••68",
      "plan": "pro", "days": 30, "expires_at": "2027-10-17T08:00:00+00:00"}]}

The codes are in the answer only once. Give each client their code; they enter it on https://app.marketapi.app/premium (signed in) and the plan starts at once, or after the plan they already have.

Big batches: more than 100 codes are made by our task queue. The answer is 202 {"job": 812, "url": "/partner/v1/jobs/812"}; ask that URL until status is done; the codes are in that answer the first time only.

GET /partner/v1/jobs/812
{"status": "queued", "position": 2, "eta_s": 4.0}  →  {"status": "done", "count": 2000, "codes": [ … ]}

Find codes

GET /partner/v1/codes?customer_ref=45123468&status=unused&limit=100&offset=0 — status: unused, redeemed or cancelled.

{"codes": [{"id": 9134, "hint": "FD2H", "customer_ref": "45•••68", "plan": "pro", "days": 30, "status": "redeemed",
            "created_at": "…", "expires_at": "…", "redeemed_at": "…"}]}

Cancel a code

POST /partner/v1/codes/9134/cancel — only unused codes; the seat is free again at once.

Security