OnlyFans API with Java
You can call the OnlyFans API from Java with no third-party HTTP library: ofapis is a plain REST API with Bearer auth, so the JDK's built-in java.net.http.HttpClient (Java 11+) is all you need. Every request goes to https://api.ofapis.com/api/public/v1. This quickstart takes you from token to a sent message.
ofapis is an independent, unofficial API for OnlyFans, not affiliated with OnlyFans. Accounts are connected once in the dashboard; the session is kept alive server-side, so your Java code only handles your ofapis_sk_... token.
1. Get a token
Create a key in the dashboard (start free) and read it from an environment variable, never a checked-in constant. See authentication.
2. Setup
java.net.http is part of the JDK, so no dependency is strictly required. For JSON, add a small parser — Jackson is used below:
<!-- Maven pom.xml -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
</dependency>
// Gradle build.gradle
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
3. Verify the token — GET /me
Build one HttpClient and a helper that attaches the Authorization header to every request:
import java.net.URI;
import java.net.http.*;
import com.fasterxml.jackson.databind.*;
public class Ofapis {
static final String BASE = "https://api.ofapis.com/api/public/v1";
static final String TOKEN = System.getenv("OFAPIS_KEY");
static final HttpClient http = HttpClient.newHttpClient();
static final ObjectMapper json = new ObjectMapper();
static HttpRequest.Builder req(String path) {
return HttpRequest.newBuilder(URI.create(BASE + path))
.header("Authorization", "Bearer " + TOKEN)
.header("Content-Type", "application/json");
}
public static void main(String[] args) throws Exception {
var res = http.send(req("/me").GET().build(),
HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200)
throw new RuntimeException("GET /me failed: " + res.statusCode() + " " + res.body());
JsonNode me = json.readTree(res.body());
System.out.println("connected as " + me.get("username").asText());
}
}
4. List chats
var res = http.send(req("/chats?limit=50").GET().build(),
HttpResponse.BodyHandlers.ofString());
for (JsonNode c : json.readTree(res.body()).path("data"))
System.out.println(c.get("id").asText());
5. Send a message
var body = HttpRequest.BodyPublishers.ofString("{\"text\":\"Thanks for subscribing!\"}");
var res = http.send(req("/chats/123/messages").POST(body).build(),
HttpResponse.BodyHandlers.ofString());
switch (res.statusCode()) {
case 200 -> System.out.println("delivered — 1 credit spent");
case 401 -> throw new IllegalStateException("bad or revoked token");
case 429 -> System.err.println("rate limited — back off and retry");
default -> throw new RuntimeException("send failed: " + res.statusCode() + " " + res.body());
}
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.
Async and timeouts
For throughput, use http.sendAsync(...) which returns a CompletableFuture, and set a timeout on the client: HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(). Reuse the single HttpClient across threads — it is safe to share and pools connections.
Agencies: scope by account
Managing several creators? Address each by id under scoped routes, e.g. req("/accounts/42/chats").GET().build(). See agency automation.
FAQ
Do I need an SDK to call the OnlyFans API from Java?
No. java.net.http.HttpClient from the JDK plus any JSON library (Jackson, Gson) is enough. You can also generate a typed client from the OpenAPI spec linked in the docs.
How do I handle rate limits in Java?
Check for HTTP 429 and retry after a short backoff. 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.
Is HttpClient thread-safe?
Yes. A single HttpClient instance is designed to be shared across threads and reuses connections, so build one and inject it rather than creating one per request.
Next steps
- Messaging API reference
- How to authenticate an OnlyFans account
- Other languages: Node · Python · Go