MYM API

A REST API for MYM creator data — transactions, subscribers, payout balance and native tracking links — plus real-time webhooks. Connect an account once; the API keeps the session alive itself.

base url
https://mym-api.com/v1

Authentication

Every endpoint except /ping requires your API key as a bearer token. Keys look like mymk_live_… and are shown once at creation — store them securely.

curl
curl https://mym-api.com/v1/me \
  -H "Authorization: Bearer mymk_live_your_key"

You can also send it as X-Api-Key: mymk_live_…. A missing or invalid key returns 401.

Conventions

  • Responses are JSON. Success is wrapped in {"data": …}; errors in {"error": {status, code, message}}.
  • All monetary amounts are in cents (integer). 1246 = €12.46.
  • Timestamps are ISO 8601 in UTC.
  • List endpoints return has_more; page with ?page= or ?offset= as noted.

Connect an account

Create a connection to a MYM creator account. Three ways, in order of preference:

POST/v1/connections
FieldDescription
emailoption ACreator's MYM email. With password, performs a headless login and captures a refresh token so the session self-renews forever. Recommended.
passwordoption ACreator's MYM password. Used once to log in — never stored.
tokenoption BA MYMX1 blob from the browser token grabber.
php_session_idoption CA raw Symfony session id (advanced). Probed live before saving.
labeloptionalA human label for the connection.
proxyoptionalPer-connection outbound proxy (IP stability).
curl · auto-login
curl -X POST https://mym-api.com/v1/connections \
  -H "Authorization: Bearer mymk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{"email":"creator@example.com","password":"••••••","label":"My creator"}'
201 Created
{ "data": {
  "id": 3, "label": "My creator", "platform": "mym",
  "status": "active", "last_probed_at": "2026-07-20T14:07:29Z"
} }

With email + password, expired sessions self-heal automatically — the API renews from the stored refresh token, so you never have to reconnect.

Account & usage

GET/v1/me

Your account, connection count and current usage.

200 OK
{ "data": {
  "id": 1, "plan": "trial", "status": "active", "connections": 1,
  "usage": { "today": 42, "month": 1180, "rate_limit_per_minute": 120 }
} }

Connections

GET/v1/connections
GET/v1/connections/{id}
DELETE/v1/connections/{id}

List, inspect, or disconnect connections. A connection's status is one of active, expired (needs reconnect) or error.

Transactions

GET/v1/connections/{id}/transactions

The income feed — subscriptions, private content (PPV) and tips — newest first, served from cache (kept fresh in the background). Paginate with ?limit= + ?starting_after= (pass the returned next_cursor). Filter with ?type=, ?status= and ?since= (ISO date).

200 OK
{ "data": [{
    "id": "mym_68074887", "type": "private_content",
    "amount": 806, "currency": "EUR", "status": "pending",
    "occurred_at": "2026-07-20T12:35:55Z",
    "fan": { "id": 11585476, "handle": "Mm149" }
  }], "has_more": true, "next_cursor": "68074678"
}

type is subscription, private_content, tip, or other. Most subscriptions are free (amount: 0).

Stats

GET/v1/connections/{id}/stats

Analytics computed from your ledgers — no live MYM call. Revenue totals + by-type + by-day, top spenders, and subscriber counts. Defaults to the last 30 days; widen with ?since= / ?until= (ISO date, e.g. ?since=2020-01-01 for all-time). Amounts in cents.

200 OK
{ "data": {
    "currency": "EUR", "range": { "since": "…", "until": "…" },
    "revenue": { "gross_cents": 125400, "transaction_count": 312,
      "by_type": { "subscription": 80000, "private_content": 41400, "tip": 4000 } },
    "subscribers": { "active": 120, "churned_total": 45, "new_in_range": 18, "churned_in_range": 7 },
    "arpu_cents": 1045,
    "top_fans": [{ "fan": { "id": 11585476, "handle": "Mm149" }, "spend_cents": 9800, "transaction_count": 14 }],
    "daily": [{ "date": "2026-07-01", "gross_cents": 4200, "transaction_count": 11 }]
  } }

arpu_cents is gross revenue in range ÷ active subscribers (null when there are none).

Balance

GET/v1/connections/{id}/balance

The creator's payout balance, exactly as MYM shows it.

200 OK
{ "data": { "confirmed_cents": 25536, "awaiting_cents": 221467, "currency": "EUR", "synced_at": "2026-07-20T17:34:03Z" } }

Subscribers

GET/v1/connections/{id}/subscribers
QueryDescription
bucketoptionalactive_subscriptions (default), inactive_subscriptions, interested_fans, blocked_fans
offsetoptionalPagination offset (default 0)
limitoptionalPage size, 1–100 (default 30)
200 OK
{ "data": [{ "fan_id": 21266440, "nickname": "001__", "avatar": null }],
  "total": 4481, "has_more": true }

Fan profile

GET/v1/connections/{id}/fans/{fanId}

Join date, subscribed-until and renewal state for a single fan.

Webhooks

Register endpoints to receive events instead of polling. The signing secret is returned once on creation.

POST/v1/webhooks { "url": "https://…", "events": ["*"] }
GET/v1/webhooks
DELETE/v1/webhooks/{id}
POST/v1/webhooks/{id}/test

Events

EventWhen
transaction.createdA new MYM transaction (subscription / PPV / tip) is detected.
subscriber.createdA fan appears in the active-subscriber roster for the first time (or resubscribes).
subscriber.expiredA previously-active fan drops out of the roster (subscription lapsed / cancelled).
connection.expiredA session died and couldn't self-renew — reconnect required.

Filter with "events" on create — an exact type ("subscriber.created"), a prefix wildcard ("subscriber.*"), or "*" (default) for all.

event payload
{
  "id": "evt_3_68074887", "type": "transaction.created",
  "created": "2026-07-20T12:36:01Z", "connection_id": 3,
  "data": { /* the transaction object */ }
}

Event ids are stable, so retries are safe to deduplicate on id.

Verifying signatures

Each delivery carries X-Mym-Signature: t=<ts>,v1=<hex> where v1 = HMAC-SHA256(secret, "<ts>.<raw_body>"). Recompute it and compare in constant time.

node · express
app.post("/mym/webhook", (req, res) => {
  const [t, v1] = req.headers["x-mym-signature"]
    .split(",").map(s => s.split("=")[1]);
  const expected = crypto.createHmac("sha256", SECRET)
    .update(t + "." + req.rawBody).digest("hex");
  if (!crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected)))
    return res.sendStatus(400);
  res.sendStatus(200);
});

Rate limits

Requests are limited to 120 per minute per account. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining; exceeding it returns 429 with a Retry-After header.

Errors

Errors are JSON with a status, machine-readable code, and human message.

StatusCodeMeaning
401Missing, invalid or revoked API key.
403Account is not active.
404Resource not found (or not yours).
409connection_expiredSession expired and couldn't self-renew — reconnect.
422login_failed / session_invalidBad credentials or an unusable session at connect time.
429rate_limitedToo many requests — back off.
502upstream_errorMYM was unreachable or returned an unexpected response.

mym-api.com — independent developer service. Not affiliated with MYM.