MeuMore Creator API
Run your whole creator business from the tools you already use: publish and schedule posts, message fans (including mass and locked messages), see subscribers and spend, track earnings, request payouts and get webhooks when things happen.
Base URL https://meumore.com/api/v1 · OpenAPI 3.1 (openapi.json)
Authentication
Create a key in Settings → API (creators only). Keys look like mm_live_<id>_<secret> and are shown once: we only store a hash. Send the key in the Authorization header of every request. Revoke a key there at any time; it stops working immediately (401).
curl https://meumore.com/api/v1/me \
-H "Authorization: Bearer mm_live_0123456789abcdef_…"Keep keys on your server. Never put them in a browser app or a public repository.
Scopes
Each key has one or more scopes. GET /me and GET /stats work with any key. A missing scope returns 403 insufficient_scope.
content· upload, schedule, edit and delete postsmessages· read and send chat messages, mass messagesfans· subscribers and fan detailsearnings· earnings, transactions and payoutswebhooks· manage webhook endpoints
Rate limits & errors
- 60 requests per minute per key (a token bucket, so short bursts are fine).
- Mass messages: 10 per hour. Chat messages: 30 per minute. Uploads: 20 per hour.
- Over a limit you get 429
rate_limited; wait and retry.
Errors are JSON with a stable code and a readable message:
HTTP/1.1 403 Forbidden
{"error":{"code":"insufficient_scope","message":"This API key is missing the 'earnings' scope."}}Codes include invalid_api_key, revoked_api_key, not_a_creator, insufficient_scope, invalid_request, invalid_json, not_found, conflict, already_published, payment_required, unprocessable (e.g. content rejected by moderation), rate_limited and internal_error.
Pagination
Lists return {"data": [...], "next_cursor": "…"}. Pass ?cursor=<next_cursor> for the next page and ?limit= (1–100, default 25). next_cursor is null on the last page. Amounts are integers in minor units (paise, cents) with an ISO 4217 currency; times are ISO 8601 UTC.
Endpoints
In the examples, $MEUMORE_KEY holds your key.
/mescope: anyYour profile, creator status, subscription price and counts
curl -s https://meumore.com/api/v1/me -H "Authorization: Bearer $MEUMORE_KEY"/statsscope: anySubscribers now, new and churned, revenue per day by source, top posts by unlocks
curl -s https://meumore.com/api/v1/stats?from=2026-09-01T00:00:00Z -H "Authorization: Bearer $MEUMORE_KEY"/media/uploadsscope: contentGet a presigned upload URL
PUT the file bytes to upload.url with upload.headers, then finalise with POST /media. Images up to 10 MB, videos up to 100 MB.
curl -s https://meumore.com/api/v1/media/uploads -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"content_type":"image/jpeg","size":123456}'
curl -X PUT -H 'Content-Type: image/jpeg' --data-binary @photo.jpg "$UPLOAD_URL"/mediascope: contentList your media, newest first
curl -s https://meumore.com/api/v1/media?limit=10 -H "Authorization: Bearer $MEUMORE_KEY"/mediascope: contentFinalise an upload: caption, visibility, price, scheduling
Processing and moderation run now. Explicit content is rejected (422). A future publish_at schedules the post: it stays hidden everywhere until then. context "chat" makes a vault item for messages that never shows in your gallery.
curl -s https://meumore.com/api/v1/media -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"upload_id":"$UPLOAD_ID","content_type":"image/jpeg","caption":"New set","visibility":"subscribers","publish_at":"2026-10-01T18:00:00Z"}'/media/{id}scope: contentOne media item, with a short-lived URL to the original
curl -s https://meumore.com/api/v1/media/$MEDIA_ID -H "Authorization: Bearer $MEUMORE_KEY"/media/{id}scope: contentEdit caption, visibility, price or schedule
publish_at can only change before the post is published; null publishes now.
curl -s -X PATCH https://meumore.com/api/v1/media/$MEDIA_ID -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"caption":"Updated"}'/media/{id}scope: contentDelete a media item (buyers lose access)
curl -s -X DELETE https://meumore.com/api/v1/media/$MEDIA_ID -H "Authorization: Bearer $MEUMORE_KEY"/conversationsscope: messagesYour conversations, most recent first
curl -s https://meumore.com/api/v1/conversations -H "Authorization: Bearer $MEUMORE_KEY"/conversations/{id}/messagesscope: messagesMessages in a conversation, newest first
curl -s https://meumore.com/api/v1/conversations/$CONVERSATION_ID/messages -H "Authorization: Bearer $MEUMORE_KEY"/conversations/{id}/messagesscope: messagesSend a text, media or locked message
Text only, a media_id (one of your media; upload chat-only media with context "chat"), or a locked message: media_id plus tier_id. The fan sees a blurred preview and pays their local price to unlock. You can message fans who subscribe to you, and your matches. 30 messages per minute; text up to 2000 characters.
curl -s https://meumore.com/api/v1/conversations/$CONVERSATION_ID/messages -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"text":"Thanks for subscribing!"}'/mass-messagesscope: messagesSend one message to a segment of fans
Delivered as individual messages (a locked message unlocks per fan), only to fans you may chat with. 10 per hour.
curl -s https://meumore.com/api/v1/mass-messages -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"segment":{"type":"all_subscribers"},"text":"New post is up!"}'/mass-messages/{id}scope: messagesStatus and counts of a mass message
curl -s https://meumore.com/api/v1/mass-messages/$MASS_ID -H "Authorization: Bearer $MEUMORE_KEY"/subscribersscope: fansYour subscribers with lifetime spend
curl -s https://meumore.com/api/v1/subscribers?status=active -H "Authorization: Bearer $MEUMORE_KEY"/fans/{id}scope: fansA fan: subscription status, spend, last message
curl -s https://meumore.com/api/v1/fans/$FAN_ID -H "Authorization: Bearer $MEUMORE_KEY"/earningsscope: earningsEarnings by source and currency, and balances
curl -s https://meumore.com/api/v1/earnings?from=2026-09-01T00:00:00Z -H "Authorization: Bearer $MEUMORE_KEY"/transactionsscope: earningsLedger rows, one per payment (20% platform fee, 80% yours)
curl -s https://meumore.com/api/v1/transactions?source=tip -H "Authorization: Bearer $MEUMORE_KEY"/payoutsscope: earningsYour payout requests
curl -s https://meumore.com/api/v1/payouts -H "Authorization: Bearer $MEUMORE_KEY"/payoutsscope: earningsRequest a payout of the full available balance in a currency
curl -s https://meumore.com/api/v1/payouts -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"currency":"INR"}'/webhooksscope: webhooksYour webhook endpoints
curl -s https://meumore.com/api/v1/webhooks -H "Authorization: Bearer $MEUMORE_KEY"/webhooksscope: webhooksAdd a webhook endpoint (returns its signing secret once)
curl -s https://meumore.com/api/v1/webhooks -H "Authorization: Bearer $MEUMORE_KEY" -H 'Content-Type: application/json' -d '{"url":"https://example.com/meumore","events":["subscriber.new","tip.received"]}'/webhooks/{id}scope: webhooksDelete a webhook endpoint
curl -s -X DELETE https://meumore.com/api/v1/webhooks/$WEBHOOK_ID -H "Authorization: Bearer $MEUMORE_KEY"Uploading and scheduling a post
POST /media/uploadswith the content type and size: you get anupload_idand a PUT URL.- PUT the file bytes to that URL with the returned headers.
POST /mediawith theupload_id, caption, visibility and an optional futurepublish_at. Scheduled posts are hidden everywhere until then; a job publishes them every minute and sendsmedia.published.
Webhooks
Add an endpoint with POST /webhooks and the events you want. The response includes the endpoint's signing secret (whsec_…), shown once. We POST each event as JSON:
POST /your/endpoint
Content-Type: application/json
X-MeuMore-Event: tip.received
X-MeuMore-Signature: t=1727700000,v1=<hex HMAC-SHA256(secret, "1727700000." + raw body)>
{
"id": "evt_0123456789abcdef01234567",
"type": "tip.received",
"created_at": "2026-09-30T12:00:00.000Z",
"data": {
"order_id": "uuid",
"message_id": "uuid",
"fan_id": "uuid",
"amount_minor": 10000,
"currency": "INR"
}
}- Respond with any 2xx within 10 seconds. Anything else, or a timeout, is a failure.
- Failures are retried with exponential backoff, up to 8 attempts in total: after 1 min, 4 min, 16 min, 1 h 4 min, 4 h 16 min, 12 h, 12 h.
- An endpoint is disabled after 50 consecutive failed attempts. Delete it and add it again to re-enable.
- Retries of an event keep the same
id: use it to deduplicate. Events may arrive out of order. - Endpoints must be public
httpsURLs; private, loopback and link-local addresses are refused.
Verifying signatures (Node.js)
Compute the HMAC over the raw request body (before JSON parsing) and compare in constant time:
import crypto from 'node:crypto';
import http from 'node:http';
const SECRET = process.env.MEUMORE_WEBHOOK_SECRET; // whsec_… from POST /webhooks
function verify(rawBody, header, toleranceSeconds = 300) {
// header: "t=1727700000,v1=5f2b…"
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=', 2)));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; // stale: possible replay
const expected = crypto.createHmac('sha256', SECRET).update(`${t}.${rawBody}`).digest();
const got = Buffer.from(parts.v1 ?? '', 'hex');
return got.length === expected.length && crypto.timingSafeEqual(got, expected);
}
http.createServer((req, res) => {
let raw = '';
req.on('data', (c) => (raw += c));
req.on('end', () => {
if (!verify(raw, req.headers['x-meumore-signature'] ?? '')) {
res.writeHead(400).end('bad signature');
return;
}
const event = JSON.parse(raw); // { id, type, created_at, data }
// Deduplicate on event.id: a retry of the same event has the same id.
console.log(event.type, event.data);
res.writeHead(200).end('ok');
});
}).listen(8080);Events
subscriber.new
A fan subscribed (first payment of a monthly subscription or a 30-day pass).
{
"data": {
"subscription_id": "uuid",
"fan_id": "uuid",
"mode": "auto",
"current_period_end": "2026-10-30T12:00:00.000Z",
"amount_minor": 14900,
"currency": "INR"
}
}subscriber.renewed
A subscription renewed, or a returning fan paid again.
{
"data": {
"subscription_id": "uuid",
"fan_id": "uuid",
"mode": "auto",
"current_period_end": "2026-11-30T12:00:00.000Z",
"amount_minor": 14900,
"currency": "INR"
}
}subscriber.cancelled
Auto-renew stopped (fan cancelled, payment halted or plan completed). Access runs to access_until.
{
"data": {
"subscription_id": "uuid",
"fan_id": "uuid",
"reason": "cancelled_by_fan",
"access_until": "2026-10-30T12:00:00.000Z"
}
}subscriber.expired
A subscription ended.
{
"data": {
"subscription_id": "uuid",
"fan_id": "uuid",
"ended_at": "2026-10-30T12:00:00.000Z"
}
}purchase.created
A fan bought one of your paid posts.
{
"data": {
"order_id": "uuid",
"media_id": "uuid",
"fan_id": "uuid",
"amount_minor": 4900,
"currency": "INR"
}
}tip.received
A fan tipped you in chat.
{
"data": {
"order_id": "uuid",
"message_id": "uuid",
"fan_id": "uuid",
"amount_minor": 10000,
"currency": "INR"
}
}message.received
A fan sent you a message (after moderation, for photos and videos).
{
"data": {
"message_id": "uuid",
"conversation_id": "uuid",
"fan_id": "uuid",
"kind": "text",
"created_at": "2026-09-30T12:00:00.000Z"
}
}message.unlocked
A fan unlocked one of your locked messages.
{
"data": {
"order_id": "uuid",
"message_id": "uuid",
"fan_id": "uuid",
"amount_minor": 14900,
"currency": "INR"
}
}media.approved
A post or chat media item passed moderation.
{
"data": {
"media_id": "uuid",
"kind": "image",
"context": "gallery",
"visibility": "subscribers",
"published": true
}
}media.rejected
A post or chat media item was rejected in review.
{
"data": {
"media_id": "uuid",
"kind": "image",
"context": "gallery",
"visibility": "free",
"published": true
}
}media.published
A scheduled post went live.
{
"data": {
"media_id": "uuid",
"kind": "image",
"visibility": "subscribers",
"status": "approved",
"publish_at": "2026-10-01T18:00:00.000Z"
}
}payout.updated
A payout was requested, paid or rejected.
{
"data": {
"payout_id": "uuid",
"status": "paid",
"amount_minor": 250000,
"currency": "INR",
"note": "UTR 1234",
"settled_at": "2026-10-02T10:00:00.000Z"
}
}Partners
For companies working with MeuMore. Three parts: invites (your server asks MeuMore to email an invitation to someone who agreed to receive it), demo users (AI demo profiles for testing) and partner apps (a MeuMore user lets your app act for them, for example to add AI-edited profile photos). Base URL https://meumore.com/api/partner/v1 · OpenAPI 3.1 (openapi.json). Partner keys and apps are issued by MeuMore; contact us through the Grievance page.
Invites
Authenticate with your partner key: Authorization: Bearer mm_partner_<id>_<secret>. We store only a hash of it. Keep it on your server.
Consent rules (read these first)
- Only invite people who agreed, in words that name MeuMore, to receive an invitation from MeuMore. "Offers from our partners" or general marketing consent is not enough.
- Every request must include
consent:source(the form or page),captured_at(when) andtext(the exact wording they agreed to). Ifconsent.textdoesn't mention MeuMore the request fails with 422consent_not_specificand nothing is sent. We keep the consent record with the invite. - We send at most one invitation per address every 30 days, never to existing members, and never again to anyone who unsubscribed (a global list that applies to every partner).
- Every email comes from MeuMore, names you as the source, and has a one-click unsubscribe.
- Statuses:
sent→clicked(opened the join link) →signed_up(joined with Google) →profile_complete(added a photo and finished their profile); orunsubscribed/bounced. - If someone joins from the link with a different Google address, the invite still counts and
email_mismatchis true. - 201 created. 409
already_invitedwhen you invited this address in the last 30 days (or it joined through your invite): the body has that invite'sidandstatusand no email is sent. 409not_invitablewhen the address unsubscribed, bounced, is already a member or was invited recently by someone else: we don't say which. - Limits per partner: 1000 invites per hour, 20000 per day and 600 API requests per minute (429
rate_limited).
/api/partner/v1/invitespartner keySend an invitation email from MeuMore to one person who agreed to receive it.
consent is required and consent.text must name MeuMore (422 otherwise). 409 when you invited this address in the last 30 days (with that invite's id and status), or when it can't be invited (unsubscribed, bounced, already a member, or invited recently by someone else; the reason isn't disclosed). Limits: 1000 per hour and 20000 per day.
curl -s https://meumore.com/api/partner/v1/invites -H "Authorization: Bearer $MEUMORE_PARTNER_KEY" \
-H "Content-Type: application/json" -d '{
"email": "[email protected]", "name": "Ana", "country": "BR",
"consent": {"source": "oxbo.in/signup", "captured_at": "2026-09-30T10:00:00Z",
"text": "I agree that Oxbo may share my email with MeuMore so MeuMore can send me an invitation."},
"utm": {"source": "oxbo", "medium": "partner", "campaign": "sept"}, "external_id": "lead_123"
}'/api/partner/v1/invitespartner keyYour invites, newest first, with cursor pagination.
curl -s "https://meumore.com/api/partner/v1/invites?status=signed_up" -H "Authorization: Bearer $MEUMORE_PARTNER_KEY"/api/partner/v1/invites/{id}partner keyOne invite's status. Other partners' invites are 404.
curl -s https://meumore.com/api/partner/v1/invites/$INVITE_ID -H "Authorization: Bearer $MEUMORE_PARTNER_KEY"Demo users (AI demo profiles)
With the demo scope you can create AI demo profiles for testing MeuMore, and read and answer the chats members send them. Demo profiles never sign in, get no emails, and never count in member numbers, stats, earnings or attribution.
Who sees demo profiles (set by MeuMore)
- Testers only (the default): only MeuMore admins and testers see them, and can like, match, chat and use test payments with them. Nobody else sees them anywhere.
- Labeled: every member sees them, always marked with an "AI" badge on every photo and avatar note, and can like, match and chat with them. Nobody except testers can pay a demo profile (subscribe, buy, unlock or tip: 403
demo_profile_payments). - Off: nobody sees them, testers included.
- Payments with demo profiles only ever run with test payment keys.
- Demo profiles like back whoever likes them (when that member may match with them), so a like is a match.
- Replies you send through the API are stored as normal text messages from the demo profile and follow the normal chat rules.
/api/partner/v1/demo-userspartner keyCreate or update (by external_id) an AI demo profile.
multipart/form-data: the fields below, `photos` (1-5 image files; replaces all current photos on update) and `ai_enhanced` (once for all photos, or once per photo in order). Or JSON with `photos: [{upload_id, ai_enhanced}]` from POST /demo-users/uploads. Creating needs name, age (18+), gender, interested_in, looking_for and photos; updates take any subset. Photos go through moderation (rejected: 422). The profile is onboarded, has no Google identity and can never sign in. 201 created, 200 updated.
curl -s https://meumore.com/api/partner/v1/demo-users -H "Authorization: Bearer $MEUMORE_PARTNER_KEY" \
-F external_id=demo_ana -F name="Ana" -F age=29 -F gender=woman -F interested_in=man \
-F looking_for=both -F city="São Paulo" -F country=BR -F lat=-23.55 -F lng=-46.63 -F bio="Coffee and hiking" \
-F [email protected] -F [email protected] -F ai_enhanced=true/api/partner/v1/demo-userspartner keyYour demo profiles, newest first.
/api/partner/v1/demo-userspartner keyDelete all your demo profiles with their photos, media and chats.
curl -s -X DELETE https://meumore.com/api/partner/v1/demo-users -H "Authorization: Bearer $MEUMORE_PARTNER_KEY"/api/partner/v1/demo-users/uploadspartner keyPresigned PUT for a demo profile photo (then POST /demo-users with photos: [{upload_id}]).
/api/partner/v1/demo-users/{external_id}partner keyOne demo profile.
/api/partner/v1/demo-users/{external_id}partner keyDelete one demo profile, its photos, media and chats.
/api/partner/v1/demo-users/{external_id}/conversationspartner keyChats members started with this demo profile, each with its latest 20 messages (oldest first). Fetched messages are marked read.
curl -s https://meumore.com/api/partner/v1/demo-users/demo_ana/conversations -H "Authorization: Bearer $MEUMORE_PARTNER_KEY"/api/partner/v1/demo-users/{external_id}/messagespartner keyReply as the demo profile (text only). The same chat rules and rate limit (30 per minute) apply as for members.
curl -s https://meumore.com/api/partner/v1/demo-users/demo_ana/messages -H "Authorization: Bearer $MEUMORE_PARTNER_KEY" -H "Content-Type: application/json" \
-d '{"conversation_id":"<id>","text":"Hi! Thanks for the message."}'Partner apps (OAuth 2.0 with PKCE)
Your app gets a client_id, a client secret and exact redirect URIs from MeuMore. The user signs in with Google on MeuMore, sees your app's name and what it may do, and chooses Allow or Deny. They can disconnect your app at any time in Settings → Connected apps.
- Redirect the user to
https://meumore.com/partner/authorizewithresponse_type=code,client_id,redirect_uri(must match a registered URI exactly),scope(space-separated),state(required) and, recommended,code_challenge+code_challenge_method=S256. - We redirect back to
redirect_uri?code=…&state=…, or?error=access_denied&state=…. Checkstate. - POST the code to
https://meumore.com/api/partner/oauth/tokenwithin 10 minutes. Codes work once. Send yourclient_secret(body or HTTP Basic), the PKCEcode_verifier, or both: one of them is required. - Call the user endpoints with
Authorization: Bearer mmat_…. Access tokens last 90 days. Refresh withgrant_type=refresh_token: you get a new access and refresh token and the old pair stops working.
import crypto from 'node:crypto';
// 1. Before redirecting the user: a random verifier, its S256 challenge and a state.
const verifier = crypto.randomBytes(32).toString('base64url'); // keep it (session), never send it here
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
const state = crypto.randomBytes(16).toString('base64url'); // check it on the way back
const url = new URL('https://meumore.com/partner/authorize');
url.search = new URLSearchParams({
response_type: 'code',
client_id: process.env.MEUMORE_CLIENT_ID,
redirect_uri: 'https://yourapp.example/meumore/callback', // exactly as registered
scope: 'photos:write profile:read',
state,
code_challenge: challenge,
code_challenge_method: 'S256',
}).toString();
// redirect the user to url
// 2. On https://yourapp.example/meumore/callback?code=…&state=… (or ?error=access_denied&state=…)
async function exchange(code) {
const res = await fetch('https://meumore.com/api/partner/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.MEUMORE_CLIENT_ID,
client_secret: process.env.MEUMORE_CLIENT_SECRET, // server-side apps; omit in a public client
code,
redirect_uri: 'https://yourapp.example/meumore/callback',
code_verifier: verifier,
}),
});
return res.json(); // { access_token: "mmat_…", refresh_token: "mmrt_…", expires_in: 7776000, token_type: "Bearer", scope }
}curl -s https://meumore.com/api/partner/oauth/token \
-d grant_type=refresh_token -d client_id=$MEUMORE_CLIENT_ID \
-d client_secret=$MEUMORE_CLIENT_SECRET -d refresh_token=$REFRESH_TOKENScopes
profile:read· See your basic profile: first name, age, country and your photosphotos:write· Add or replace your profile photos (up to 5; every photo is checked by our moderation first)media:write· Post photos and videos to your gallery as you (creator accounts only)
User endpoints
/api/partner/v1/user/meuser token · anyThe user who authorised your app, the granted scopes and (with profile:read) their basic profile.
curl -s https://meumore.com/api/partner/v1/user/me -H "Authorization: Bearer $USER_ACCESS_TOKEN"/api/partner/v1/user/photosuser token · photos:writeAdd a profile photo (next free slot; max 5) or replace one.
multipart/form-data with `photo` (JPEG, PNG, WebP or HEIC, 10 MB max), optional `replace` (a photo id or "main") and `ai_enhanced` ("true" when the image was made or edited with AI). Or JSON {upload_id, replace?, ai_enhanced?} after POST /user/photos/uploads. Every photo is moderated: rejected images return 422, others may stay pending until reviewed. At 5 photos adding returns 400: replace one instead.
curl -s https://meumore.com/api/partner/v1/user/photos -H "Authorization: Bearer $USER_ACCESS_TOKEN" \
-F [email protected] -F ai_enhanced=true/api/partner/v1/user/photos/uploadsuser token · photos:writePresigned PUT for a large profile photo; then POST /user/photos {"upload_id": …}.
/api/partner/v1/user/media/uploadsuser token · media:writePresigned PUT for a gallery photo or video.
curl -s https://meumore.com/api/partner/v1/user/media/uploads -H "Authorization: Bearer $USER_ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"content_type":"image/jpeg","size":123456}'/api/partner/v1/user/mediauser token · media:writePublish an upload to the user's gallery, as the user.
Same processing, moderation and scheduling as posts made on the site. The user must be a creator (creator fee paid), otherwise 403 not_a_creator; paid needs tier_id.
curl -s https://meumore.com/api/partner/v1/user/media -H "Authorization: Bearer $USER_ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"upload_id":"<upload_id>","content_type":"image/jpeg","caption":"Studio shoot","ai_enhanced":true}'ai_enhanced
Set ai_enhanced: true on photos and posts your app generated or edited with AI. MeuMore shows a small "AI-enhanced" label on them in the profile photos and the gallery, and returns ai_enhanced in the API. Always set it when AI changed how someone looks, so people on MeuMore know what they are seeing. The max-5 photo rule and moderation apply as usual.
Errors and limits
API errors are JSON {"error":{"code","message"}}; the token endpoint uses OAuth's {"error","error_description"}.
- 400 invalid_request, invalid_json · 401 invalid_partner_key, invalid_token, token_expired, token_revoked, app_disabled · 403 partner_disabled, insufficient_scope, not_a_creator, account_disabled, demo_profile_payments · 404 not_found · 409 already_invited, not_invitable · 413 payload_too_large · 415 unsupported_media_type · 422 consent_required, consent_invalid, consent_not_specific, unprocessable (content rejected by moderation) · 429 rate_limited · 503 email_failed (retry later).
- Token endpoint: invalid_client (401), invalid_grant (400: unknown, used or expired code, wrong redirect_uri or verifier), unsupported_grant_type.
- Limits: partner key 600 requests/min; invites 1000/hour and 20000/day; user tokens 60 requests/min each; photo and media uploads 20/hour per user; token endpoint 30/min per app.