ofapisv1
integration

Updated

OnlyFans + Make.com

There is no ofapis app in Make's catalogue, and waiting for one would be a waste of a week. ofapis authenticates with a single Authorization: Bearer <token> header and nothing else — no OAuth connection to approve, no signature to compute — which is precisely the case the generic HTTP app covers. You build the scenario on the canvas like any other, and the OnlyFans side is just HTTP modules pointed at the endpoints that do the automating.

1. The first HTTP module

  1. Add an HTTP → Make a request module to a new scenario.
  2. URL: https://api.ofapis.com/api/public/v1/me.
  3. Method: GET.
  4. Headers: one item — Name Authorization, Value Bearer ofapis_sk_….
  5. Parse response: Yes. Without this the body arrives as a string and nothing downstream is mappable.
  6. Run once. The output bundle shows statusCode 200 and your account under data.

For anything you call repeatedly, swap in HTTP → Make an API Key Auth request and create a Keychain connection holding the same header. The token then lives outside the blueprint, so exporting the scenario or handing it to a contractor does not hand over the key. Rotation is covered in authentication.

2. The data.data trap

Make's HTTP module wraps the parsed body in its own data field. ofapis wraps every success body in a data envelope as well. The two nest, so the array of fans in module 2 is not {{2.data.list}}:

{{2.data.data.list}}        // the records
{{2.data.data.hasMore}}     // another page exists
{{2.data.data.nextOffset}}  // next offset
{{2.statusCode}}            // 200, 402, 429 …
{{2.headers.retry-after}}   // seconds, present on a 429

Errors nest the same way: {{2.data.error.code}} and {{2.data.error.message}}. The exception is a malformed query parameter, which returns 400 with a plain string body instead of the envelope — so branch on statusCode first and only read error.code after. The full table is on error codes.

To act on each record rather than the whole page, follow the HTTP module with an Iterator set to {{2.data.data.list}}. Collapse the results again with an Array aggregator when the next module needs one bundle, not three hundred.

3. Paging with a Repeater

Reads take limit (default 20, clamped 1–100) and offset (default 0). Make has no "while" module, so the idiom is a bounded Repeater plus a filter:

  1. Flow Control → Repeater, Initial value 1, Repeats 20 (that is 2,000 records at 100 per page — set it to cover your largest roster).
  2. HTTP → Make a request, URL …/accounts/42/subscribers?type=active&limit=100&offset={{(1.i - 1) * 100}}.
  3. On the route out of the HTTP module, set a filter with the condition {{2.data.data.hasMore}} equals true, so once the API says there is nothing left the remaining cycles do no work.
  4. Iterator → whatever you do per fan → Array aggregator.

Having to pick that cycle count in advance is the one place Make is genuinely weaker: n8n's HTTP Request node pages until hasMore is false without being told how far to go. Worth switching tools for only if unbounded reads are the point of the scenario rather than an occasional backfill.

Message history is the one route that does not take an offset: /chats/{chatId}/messages pages on the cursor olderThanMessageId, which you feed from the id of the oldest message in the previous bundle.

4. Rate limits and error handlers

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (unix seconds). The ceiling is per token per minute — 60 on Free, 100 on Starter, 500 on Pro — and a Repeater that fires twenty pages back to back will reach it on a Free token. A 429 adds Retry-After, in seconds.

Right-click the HTTP module and choose Add error handler. Two routes are worth building: a Break directive (with Allow storing of incomplete executions enabled on the scenario) so a throttled run is parked and retried rather than lost, and a Sleep module ahead of it with Delay mapped to the module's retry-after response header for the cases you want to resolve inside the same execution. More on the ceilings in rate limits.

5. Idempotency-Key on every POST

Any POST accepts an Idempotency-Key header. Repeat the key and ofapis replays the stored response, marks it Idempotency-Replayed: true and does not bill it again. Scenarios get re-run by hand constantly — from the Run once button, from a rollback, from an error-handler retry — so add the header as a second item in Headers on every POST module and derive the value from something stable, like the campaign date:

campaign-{{formatDate(now; "YYYY-MM-DD")}}

A key that is already mid-flight returns 409 IDEMPOTENCY_CONFLICT, which simply means "the first attempt has not finished yet, try again shortly".

Worked example: a scheduled campaign that prices itself first

Billing on a mailing is not one credit. A mailing costs recipientCount × perRecipientWeight, so a blast to 5,000 fans is a 5,000-credit event. The mailings resource has a preview call for exactly this reason, and Make's Router is the natural place to put the decision.

  1. Create the mailing scenario once — POST /accounts/42/mailings with {"name": "Friday drop", "text": "…", "listId": "123", "priceCents": 0} — and keep the returned id in a Data store record. Targeting a fan list rather than all subscribers is also what makes the recipient count knowable.
  2. Scheduling: set the scenario to run Every day at 10:00.
  3. Module 1 — Data store → Get a record: read back the mailing id.
  4. Module 2 — HTTP: POST …/accounts/42/mailings/{{1.mailingId}}/preview. The response gives recipientCount, perRecipientWeight and estimatedCost.
  5. Module 3 — Router with two routes. Route A filter: {{2.data.data.estimatedCost}} less than 2000. Route B is everything else, ending in a Slack or email module that asks a human to approve. The credit maths behind that number is on pricing.
  6. Route A — HTTP: POST …/accounts/42/mailings/{{1.mailingId}}/trigger, with Idempotency-Key set to send-{{1.mailingId}}-{{formatDate(now; "YYYY-MM-DD")}}. The response returns runId, recipientCount and creditsDebited.
  7. Module 4 — HTTP: later in the day, GET …/accounts/42/mailings/{{1.mailingId}}/runs to read status, successCount and skippedCount into a sheet.

That is a mass DM that cannot quietly spend ten times what you expected, built from four HTTP modules and a Router. If the sends should land at a fixed hour instead of the moment the scenario runs, POST /accounts/42/scheduled/messages with scheduledAt, userLists and text queues them on OnlyFans' own scheduler instead. Raise priceCents above zero and the same four modules become a locked PPV drop that is costed before it goes out.

FAQ

Which HTTP module should I pick?

Use Make a request for one-offs and while you are building, and Make an API Key Auth request for anything you keep, because the Keychain connection holds the Bearer token outside the scenario blueprint. Both send the same single header; the difference is only where the secret is stored.

Why is my array at data.data.list?

Because two wrappers stack. Make's HTTP module puts the parsed body under its own data field, and every ofapis success body is itself {"data": …}. Map {{2.data.data.list}} and the Iterator will find the records.

Can a scenario page through every subscriber?

Yes, with a Repeater whose cycle count covers your roster, offset computed from {{1.i}}, and a filter on hasMore so finished pages stop the route. There is no unbounded loop in Make, so pick a ceiling deliberately rather than hoping the scenario stops itself.

How do I stop a manual re-run from sending a campaign twice?

Put an Idempotency-Key header on the trigger module with a value that is stable for that campaign and date. The second run replays the first response, returns Idempotency-Replayed: true, and debits nothing further.

What does a mass DM actually cost?

recipientCount × perRecipientWeight credits, debited on the run — not one credit for the whole blast. Call the preview endpoint first and read estimatedCost. Preview has no weight of its own, so it costs the default 1 credit — a rounding error against the blast it protects you from.

Related: Zapier · n8n · all integrations

Related guides

All guides
Start free — 250 credits, no card
Generate a token and make your first call in minutes.
Get started