Every route lives under https://api.ofapis.com/api/public/v1 and authenticates with a single Bearer token. Successful responses are wrapped in a data object; errors return {"error":{"code","message"}}. Most calls cost one credit; the heavier writes cost more, and the rules are spelled out under billing.
Read the linked creator profile and the audience around it.
List conversations, read history, and send — including priced PPV messages.
Create a campaign, preview its reach and cost, dispatch it, then track the run.
Group fans into lists and address a whole cohort in one send.
Queue feed posts and messages ahead of time, and manage the queue.
Upload to the vault, then reference media by id; poll activity or use webhooks.
Account-scoped variants of the read endpoints exist under /accounts/{accountId}/… so an agency can address each creator by id under one token. The full interactive reference — with schemas, a live playground and multi-language samples — is below.
One Bearer token is the whole credential — there is no request signing and no second secret. Create it in the dashboard; it inherits your plan's rate limit and spends your credit balance, so keep it server-side.
curl https://api.ofapis.com/api/public/v1/me \
-H "Authorization: Bearer $OFAPIS_TOKEN"Linking a creator account is a separate, one-time step — how account linking works.
Every success puts its payload under data; every failure replaces it with error. The two never appear together, so one check tells you which branch you are on.
{ "data": { "id": 4812, "username": "creator" } }
{ "error": { "code": "INSUFFICIENT_CREDITS",
"message": "Not enough credits…" } }Branch on code — it is stable. The message is written for a human reader and gets reworded.
These five failures can come back from any endpoint. Malformed parameters also return 400, but as a plain validation string rather than the envelope above.
| Status | Code | Meaning |
|---|---|---|
| 200 | — | Call succeeded and the credit stays debited. |
| 401 | UNAUTHENTICATED | The Authorization header is missing, malformed or names a revoked token. |
| 402 | INSUFFICIENT_CREDITS | The balance is too low for this call. Nothing was sent. |
| 403 | NO_ACTIVE_SUBSCRIPTION | The plan lapsed or was cancelled. Reactivate it and retry. |
| 409 | IDEMPOTENCY_CONFLICT | An earlier request with the same Idempotency-Key is still running. |
| 429 | RATE_LIMIT_EXCEEDED | Over the plan's requests per minute. Honour Retry-After. |
A call costs one credit by default. Four writes cost more, because each one drives substantially more work upstream:
| Call | Credits |
|---|---|
| Everything not listed below | 1 |
| POST /accounts/{id}/media | 5 |
| POST /accounts/{id}/scheduled/posts | 3 |
| POST /accounts/{id}/scheduled/messages | 3 |
| POST /accounts/{id}/chats/{chatId}/messages | 2 |
| POST /accounts/{id}/mailings/{id}/trigger | 0 at the call — the run debits per recipient |
Credits are taken before the request reaches the handler, which decides what a failure costs. A 401, 402, 403 or 429 is rejected at the gate, so nothing is debited. A 5xx, a 424 or a 409 is refunded automatically. A 400, 404 or 422 is not refunded — the request was authorised and ran, it was the input that was wrong, so validate before you send rather than probing. Costs per plan are on pricing.
The throttle is per token per minute: 60 on Free, 100 on Starter, 500 on Pro. Three headers ride on every response, so a client can pace itself instead of discovering the ceiling by hitting it.
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 98
X-RateLimit-Reset: 1749600000 # unix seconds
Retry-After: 30 # on 429 onlyA X-Request-Id is echoed back too — send your own and it shows up in our logs beside yours. See rate limits in detail.
List endpoints take limit (default 20, clamped to 1–100) and offset. Message history pages by cursor instead — pass olderThanMessageId with the oldest id you hold, so a conversation that grows mid-scroll does not shift under you.
Any POST accepts an Idempotency-Key. A repeat with the same key replays the original response with Idempotency-Replayed: true and is not charged twice — which is what makes a network timeout on a mass DM safe to retry.