OnlyFans API with curl
ofapis is a plain REST API with Bearer auth, so calling the OnlyFans API with curl is the fastest way to try it — no SDK, no code. These examples pipe responses through jq to pull out fields. Every request goes to https://api.ofapis.com/api/public/v1.
ofapis is an independent, unofficial API for OnlyFans, not affiliated with OnlyFans. Accounts are connected once in the dashboard and the session stays alive server-side, so on the command line you only ever pass your ofapis_sk_... token.
1. Set up
Create a key in the dashboard (start free), then export it and the base URL so the snippets below stay short. Keep the token out of your shell history — a leading space or a secrets manager helps. See authentication.
export OFAPIS_KEY=ofapis_sk_...
export BASE=https://api.ofapis.com/api/public/v1
2. Verify the token — GET /me
-s silences the progress meter, -f makes curl exit non-zero on HTTP errors so a bad token fails your script:
curl -sf "$BASE/me" \
-H "Authorization: Bearer $OFAPIS_KEY" | jq '.username'
3. List chats
curl -sf "$BASE/chats?limit=50" \
-H "Authorization: Bearer $OFAPIS_KEY" | jq -r '.data[].id'
jq -r '.data[].id' prints one chat id per line (raw, unquoted) — handy for piping into a loop.
4. Send a message
curl -sf -X POST "$BASE/chats/123/messages" \
-H "Authorization: Bearer $OFAPIS_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Thanks for subscribing!"}'
A 200 means delivered and one credit spent. Failed calls — an expired session, a 429, or an upstream 5xx — are never charged, so a retry after failure is free.
5. Handle errors explicitly
-f hides the response body on failure, which makes debugging hard. To branch on the status code instead, capture the HTTP code separately with -w:
code=$(curl -s -o /tmp/out.json -w '%{http_code}' \
-X POST "$BASE/chats/123/messages" \
-H "Authorization: Bearer $OFAPIS_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Hi!"}')
case "$code" in
200) echo "delivered — 1 credit spent" ;;
401) echo "bad or revoked token"; jq . /tmp/out.json ;;
429) echo "rate limited — back off and retry" ;;
*) echo "send failed: $code"; jq . /tmp/out.json ;;
esac
Fan out with jq
Combine the two calls to message everyone in a list — jq extracts the ids, the shell loops:
for id in $(curl -sf "$BASE/chats?limit=100" \
-H "Authorization: Bearer $OFAPIS_KEY" | jq -r '.data[].id'); do
curl -sf -X POST "$BASE/chats/$id/messages" \
-H "Authorization: Bearer $OFAPIS_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"New drop is live!"}'
done
For real mass sends prefer the mass DM API, which batches server-side and respects your plan's rate limit.
Agencies: scope by account
Managing several creators? Address each by id under scoped routes, e.g. curl -sf "$BASE/accounts/42/chats" -H "Authorization: Bearer $OFAPIS_KEY". See agency automation.
FAQ
How do I pass the Bearer token with curl?
Add an Authorization header: -H "Authorization: Bearer $OFAPIS_KEY". Store the token in an environment variable so it never lands in your shell history or scripts.
How do I see the HTTP status code in curl?
Use -w '%{http_code}' and send the body to a file with -o, or add -i to print response headers. Combine with -f if you just want curl to exit non-zero on any 4xx/5xx.
Does a failed curl request cost a credit?
No. Billing is metered per successful call: one 2xx equals one credit. 401s, 429s and upstream 5xx responses are not charged.
Why use jq with the OnlyFans API?
Responses are JSON, and jq lets you extract fields (.data[].id), filter, and reshape output right in the pipeline — no scripting language needed for quick tasks.
Next steps
- Live API docs
- Messaging API reference
- Prefer a language? Python · Node · Go
Related: Postman