ofapisv1
quickstart

OnlyFans API with C#

Calling the OnlyFans API from C# needs no external package: ofapis is a plain REST API with Bearer auth, so HttpClient from System.Net.Http is all you need in .NET. System.Text.Json handles serialization out of the box. 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 is kept alive server-side, so your C# code only handles your ofapis_sk_... token.

1. Get a token

Create a key in the dashboard (start free) and read it from configuration or an environment variable — never hard-code it. See authentication.

2. Setup

Both System.Net.Http and System.Text.Json are in the base class library, so a fresh console app needs no packages:

dotnet new console -n OfapisDemo
cd OfapisDemo
export OFAPIS_KEY=ofapis_sk_...
dotnet run

3. Verify the token — GET /me

Configure one HttpClient with the BaseAddress and a default Authorization header so every call carries the Bearer token:

using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

var token = Environment.GetEnvironmentVariable("OFAPIS_KEY")!;

var http = new HttpClient { BaseAddress = new Uri("https://api.ofapis.com/api/public/v1/") };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

var res = await http.GetAsync("me");
if (!res.IsSuccessStatusCode)
    throw new Exception($"GET /me failed: {(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");

var me = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"connected as {me.GetProperty("username").GetString()}");

Note the trailing slash on the BaseAddress and the relative paths without a leading slash — that combination is what HttpClient resolves correctly.

4. List chats

var chats = await http.GetFromJsonAsync<JsonElement>("chats?limit=50");
foreach (var c in chats.GetProperty("data").EnumerateArray())
    Console.WriteLine(c.GetProperty("id").GetString());

5. Send a message

var res = await http.PostAsJsonAsync("chats/123/messages", new { text = "Thanks for subscribing!" });

switch ((int)res.StatusCode)
{
    case 200: Console.WriteLine("delivered — 1 credit spent"); break;
    case 401: throw new InvalidOperationException("bad or revoked token");
    case 429: Console.Error.WriteLine("rate limited — back off and retry"); break;
    default:  throw new Exception($"send failed: {(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");
}

A 200 means delivered and one credit spent. Failed calls — an expired session, a 429, or an upstream 5xx — are never charged, so retrying after a failure is free.

Dependency injection

In ASP.NET Core, register a typed client instead of newing up HttpClient yourself:

builder.Services.AddHttpClient("ofapis", c => {
    c.BaseAddress = new Uri("https://api.ofapis.com/api/public/v1/");
    c.DefaultRequestHeaders.Authorization =
        new AuthenticationHeaderValue("Bearer", builder.Configuration["Ofapis:Key"]);
});

IHttpClientFactory pools handlers and avoids socket exhaustion — prefer it over a using var http per call.

Agencies: scope by account

Managing several creators? Address each by id under scoped routes, e.g. http.GetAsync("accounts/42/chats"). See agency automation.

FAQ

Do I need a NuGet package to call the OnlyFans API from C#?

No. System.Net.Http.HttpClient and System.Text.Json from the BCL are enough. You can also generate a typed client from the OpenAPI spec linked in the docs.

How do I handle rate limits in .NET?

Check for HTTP 429 and retry after a short backoff — Polly's retry policies work well here. Plan ceilings run from 60 rpm on Free to 500 rpm on Pro — see pricing.

Does a failed request cost a credit?

No. Billing is metered per successful call: one 2xx equals one credit. Timeouts, 429s and upstream 5xx responses are not charged.

Should I reuse HttpClient?

Yes. A single long-lived HttpClient (or IHttpClientFactory) reuses connections. Creating and disposing one per request can exhaust sockets under load.

Next steps

Related guides

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