BetterFans Link SDK — OnlyFans APIBetterFans Link SDK
HTTP Client

Error handling

Handle errors, configure retries, and understand error codes.

The SDK uses a tuple-based error pattern inspired by Go's error handling. Every request() call returns [error, null] on failure or [null, data] on success — no try/catch needed for normal error flow.

The error tuple

const [error, data] = await account.request("GET /users/me", {})

if (error) {
  // error is OfApiError
  console.error(error.code)    // "rate_limited" | "unauthorized" | ...
  console.error(error.status)  // HTTP status code
  console.error(error.message) // Human-readable description
  return
}

// data is fully typed — no null check needed
console.log(data.name)

This pattern makes it impossible to accidentally use the response without checking for errors first.

Error codes

The code field on OfApiError is one of these values:

CodeStatusMeaning
unauthorized401Invalid or missing API key
forbidden403Valid key but insufficient access
not_found404Route or resource doesn't exist
rate_limited429Too many requests — retried automatically
server_error5xxUpstream server error — retried automatically
network_errorConnection failed — retried automatically
unknownUnexpected error

Automatic retries

GET requests are retried automatically on 429, 5xx, and network errors. The SDK uses exponential backoff with jitter.

Default retry configuration:

Prop

Type

Override retries per-client or per-request:

const client = new OfApiClient({
  apiKey: process.env.BFL_API_KEY,
  retry: { retries: 5, baseDelay: 2000 },
})

Only GET requests are retried by default. POST, PUT, and DELETE requests are not retried to avoid duplicate side effects.

Using fetch() with try/catch

If you prefer the throw pattern, use fetch() instead of request():

import { OfApiError } from "@betterfans/link-sdk"

try {
  const me = await account.fetch("GET /users/me", {})
  console.log(me.name)
} catch (error) {
  if (error instanceof OfApiError) {
    switch (error.code) {
      case "rate_limited":
        console.log("Rate limited, try again later")
        break
      case "unauthorized":
        console.log("Check your API key")
        break
      default:
        console.error("Request failed:", error.message)
    }
  }
}

Checking error types

OfApiError is exported from the SDK for instanceof checks:

import { OfApiError } from "@betterfans/link-sdk"

const [error, data] = await account.request("GET /users/me", {})

if (error) {
  if (error.status === 429) {
    // Rate limited — back off
  }
  if (error.code === "not_found") {
    // Resource doesn't exist
  }
}

On this page