> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ofauth.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connections

> Manage connected OnlyFans accounts

Connections represent authenticated OnlyFans accounts linked to your organization. There are two ways to create connections:

* **Link authentication** — Users authenticate through OFAuth's secure [Link](/guides/link) flow. OFAuth handles credentials, 2FA, and session management.
* **Import** — You provide existing OnlyFans session data directly via the API. Useful if you manage authentication yourself or are migrating from another system.

Both types produce a Connection ID that you use with the [Access API](/api-reference/access/overview) to interact with OnlyFans data.

## Creating Connections via Link

### Obtaining Connection IDs

After a user completes authentication through Link, you receive the connection ID through one of these methods:

| Method                                                                        | When to Use                                                   |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------- |
| [`connection.created` webhook](/api-reference/system-webhook-events/overview) | **Recommended.** Server-side, reliable, includes full details |
| [Embed `onSuccess` callback](/guides/link#success-metadata)                   | Client-side, immediate feedback for embedded flows            |
| [Redirect query params](/guides/link#callback-parameters)                     | Hosted redirect flow, `connection_id` in URL                  |

### Using Client Reference ID

The `clientReferenceId` you provide when [initializing a Link session](/api-reference/link/init) is your key to mapping connections to users in your system:

```javascript theme={null}
// 1. When initializing Link, pass your internal user ID
const session = await fetch("https://api.ofauth.com/v2/link/init", {
  method: "POST",
  headers: { apikey: "YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    redirectUrl: "https://yourapp.com/callback",
    clientReferenceId: "user_abc123" // Your internal user ID
  })
});

const sessionData = await session.json();
if (sessionData.mode !== "hosted") {
  throw new Error(`Expected hosted Link session, received ${sessionData.mode}`);
}
```

```javascript theme={null}
// 2. In webhook handler, use clientReferenceId to store the connection
app.post("/webhooks/ofauth", async (req, res) => {
  const { type, data } = req.body;
  
  if (type === "connection.created") {
    // Use clientReferenceId to find your user and store their connection
    await db.users.update({
      where: { id: data.clientReferenceId },
      data: { connectionId: data.connection.id }
    });
  }
  
  res.status(200).send("ok");
});
```

<Tip>
  Always pass a `clientReferenceId` when initializing Link sessions. This is the recommended way to correlate connections back to your users, especially when using webhooks.
</Tip>

## Importing Connections

If you manage OnlyFans authentication yourself, you can import sessions directly. Imported connections are **not billed monthly** and are **not health-checked** by the connection monitor. They can be used through the Access API immediately.

### Import a Connection

```http theme={null}
POST /v2/account/connections/import
```

| Field               | Type      | Required | Description                                                               |
| ------------------- | --------- | -------- | ------------------------------------------------------------------------- |
| `cookie`            | string    | Yes      | OnlyFans session cookie. Must contain `auth_id`, `sess`, and `fp` values. |
| `userAgent`         | string    | Yes      | The user agent string used to create the session.                         |
| `permissions`       | string\[] | No       | Permissions to grant. Defaults to organization permissions.               |
| `clientReferenceId` | string    | No       | Your internal reference ID for tracking.                                  |

OFAuth validates the session by making a request to OnlyFans and automatically fetches the user's profile data. If the session is invalid or expired, the import will fail.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.ofauth.com/v2/account/connections/import \
    -H "apikey: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "cookie": "auth_id=123456; sess=your_session_token; fp=your_fingerprint",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ...",
      "clientReferenceId": "user_abc123"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.ofauth.com/v2/account/connections/import", {
    method: "POST",
    headers: {
      apikey: "YOUR_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      cookie: "auth_id=123456; sess=your_session_token; fp=your_fingerprint",
      userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ...",
      clientReferenceId: "user_abc123"
    })
  })

  const connection = await response.json()
  console.log("Imported:", connection.id, connection.userData.username)
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.ofauth.com/v2/account/connections/import",
      headers={
          "apikey": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={
          "cookie": "auth_id=123456; sess=your_session_token; fp=your_fingerprint",
          "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ...",
          "clientReferenceId": "user_abc123"
      }
  )

  connection = response.json()
  print("Imported:", connection["id"], connection["userData"]["username"])
  ```
</CodeGroup>

The response includes the full connection object with `imported: true` and the user's profile data fetched from OnlyFans.

<Warning>
  If an active connection with the same OnlyFans user already exists, the import returns a `409` error with the existing connection ID. You can update the session on the existing connection using the [update endpoint](#updating-an-imported-session) instead.
</Warning>

### Updating an Imported Session

If an imported connection's session expires or needs to be rotated, you can update it in place without deleting and re-importing. This preserves the connection ID.

```http theme={null}
PATCH /v2/account/connections/import/{connectionId}
```

| Field       | Type   | Required | Description                                                                   |
| ----------- | ------ | -------- | ----------------------------------------------------------------------------- |
| `cookie`    | string | Yes      | New OnlyFans session cookie. Must contain `auth_id`, `sess`, and `fp` values. |
| `userAgent` | string | Yes      | The user agent string used to create the new session.                         |

The new session is validated against OnlyFans and **must belong to the same OnlyFans user** as the existing connection. If the user ID from the new cookie doesn't match, the request returns a `409` error.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH https://api.ofauth.com/v2/account/connections/import/conn_abc123xyz \
    -H "apikey: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "cookie": "auth_id=123456; sess=new_session_token; fp=new_fingerprint",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ..."
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.ofauth.com/v2/account/connections/import/conn_abc123xyz", {
    method: "PATCH",
    headers: {
      apikey: "YOUR_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      cookie: "auth_id=123456; sess=new_session_token; fp=new_fingerprint",
      userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ..."
    })
  })

  const connection = await response.json()
  console.log("Updated:", connection.id, connection.status)
  ```

  ```python Python theme={null}
  import requests

  response = requests.patch(
      "https://api.ofauth.com/v2/account/connections/import/conn_abc123xyz",
      headers={
          "apikey": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={
          "cookie": "auth_id=123456; sess=new_session_token; fp=new_fingerprint",
          "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ..."
      }
  )

  connection = response.json()
  print("Updated:", connection["id"], connection["status"])
  ```
</CodeGroup>

On success, the connection status is set back to `active` and the response includes updated user profile data from OnlyFans.

<Info>
  This endpoint only works for imported connections (`imported: true`). Link-managed connections cannot be updated through this endpoint.
</Info>

### Filtering by Type

List only imported or Link-created connections:

```http theme={null}
GET /v2/account/connections?imported=true
GET /v2/account/connections?imported=false
```

***

## Connection States

| State          | Description                             |
| -------------- | --------------------------------------- |
| `active`       | Ready for API access                    |
| `awaiting_2fa` | Waiting for 2FA verification            |
| `expired`      | Session ended, re-authentication needed |

## Connection Lifecycle

```mermaid theme={null}
graph LR
    A[Link Auth] --> B[Connection Created]
    G[Import API] --> B
    B --> C[Active]
    C --> D{Still Valid?}
    D -->|Yes| E[API Requests]
    D -->|No| F[Expired]
    E --> D
    F --> A
```

Connections may expire due to:

* OnlyFans session expiration
* User password changes
* Extended inactivity

<Tip>
  Set up [System Webhook Events](/api-reference/system-webhook-events/overview) to receive `connection.expired` events.
</Tip>

## API Reference

### List Connections

```http theme={null}
GET /v2/account/connections
```

| Parameter  | Type    | Description                                                 |
| ---------- | ------- | ----------------------------------------------------------- |
| `limit`    | integer | Max results (default: 10)                                   |
| `offset`   | integer | Skip count (default: 0)                                     |
| `status`   | string  | Filter: `active`, `expired`, `awaiting_2fa`                 |
| `imported` | string  | Filter: `true` (imported only), `false` (Link-created only) |

Response shape:

```json theme={null}
{
  "list": [
    {
      "id": "conn_abc123xyz",
      "status": "active",
      "permissions": ["profile:read"],
      "expiredAt": null,
      "createdAt": "2024-01-15T10:30:00.000Z",
      "updatedAt": "2024-01-15T10:30:00.000Z",
      "clientReferenceId": "user_abc123",
      "imported": false,
      "lastCheckedAt": "2024-01-15T10:35:00.000Z",
      "userData": {
        "id": "123456",
        "name": "Jane Doe",
        "username": "janedoe",
        "avatar": "https://..."
      }
    }
  ],
  "hasMore": false
}
```

### Delete Connection

```http theme={null}
DELETE /v2/account/connections/{connectionId}
```

<Warning>
  Deleting a connection logs the user out, stops billing, permanently removes the connection record, and sends a `connection.disconnected` webhook.
</Warning>

### Invalidate Connection

```http theme={null}
POST /v2/account/connections/{connectionId}/invalidate
```

Invalidates a connection by marking it as expired and logging out the user. Unlike deletion, the connection record is preserved, making it ideal for:

* **Updating permissions**: When your platform's required permissions change, invalidate the connection so users reconnect with the new permission set
* **Security rotation**: Force users to re-authenticate without losing their connection history
* **Graceful session refresh**: Refresh credentials while maintaining connection metadata

<Info>
  When you invalidate a connection, the user's profile data and permissions configuration are preserved. Only the session data is cleared.
</Info>

## Updating User Data Permissions

When your platform needs to request different permissions from connected accounts, use the invalidate + reconnect flow:

### Step 1: Update Your Platform Permissions

In your [OFAuth Dashboard](https://app.ofauth.com/platform/developer/api), update the **User Data Permissions** to include the new permissions your platform requires.

### Step 2: Invalidate Existing Connections

```bash theme={null}
curl -X POST https://api.ofauth.com/v2/account/connections/{connectionId}/invalidate \
  -H "apikey: YOUR_API_KEY"
```

This marks the connection as expired without deleting it.

### Step 3: Prompt User to Reconnect

When users reconnect through Link with the same `connectionId`, they'll be prompted to approve the updated permissions:

```bash theme={null}
curl -X POST https://api.ofauth.com/v2/link/init \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "connectionId": "conn_abc123xyz",
    "redirectUrl": "https://yourapp.com/callback"
  }'
```

<Tip>
  Set up webhooks to listen for `connection.expired` events, then notify affected users to reconnect with the updated permissions.
</Tip>

### Invalidate vs Delete

| Action         | Session | Record    | User Data | Use Case                                  |
| -------------- | ------- | --------- | --------- | ----------------------------------------- |
| **Invalidate** | Cleared | Preserved | Preserved | Permission updates, security rotation     |
| **Delete**     | Cleared | Removed   | Removed   | User requests disconnection, stop billing |

Invalidated connections send `connection.expired` and can be reconnected with the same connection ID. Deleted connections send `connection.disconnected` and cannot be reconnected or renewed.

## Reconnecting Expired Connections

When a connection expires, you can reconnect the same OnlyFans account without creating a duplicate connection. Pass the existing `connectionId` when initializing a new Link session:

```bash theme={null}
curl -X POST https://api.ofauth.com/v2/link/init \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "connectionId": "conn_abc123xyz",
    "redirectUrl": "https://yourapp.com/callback"
  }'
```

| Parameter      | Type   | Description                                                   |
| -------------- | ------ | ------------------------------------------------------------- |
| `connectionId` | string | Existing connection ID to reconnect. Must start with `conn_`. |

When a valid `connectionId` is provided:

* The user completes authentication through Link
* The existing connection is **updated** with fresh session data
* Connection ID remains the same, preserving your references

When an invalid or non-existent `connectionId` is provided:

* The system automatically creates a new connection instead
* No error is thrown—this allows graceful handling of deleted connections

<Tip>
  Use reconnection for expired connections to maintain consistent connection IDs in your database and avoid duplicate records.
</Tip>

## Best Practices

* **Monitor status** via webhooks
* **Handle expiration** with re-auth flows using `connectionId`
* **Store securely** - treat connection IDs as credentials
* **Clean up** unused connections to stop billing

## Next Steps

<CardGroup cols={2}>
  <Card title="Access API" icon="key" href="/api-reference/access/overview">
    Use connections to access data
  </Card>

  <Card title="System Webhook Events" icon="bell" href="/api-reference/system-webhook-events/overview">
    Monitor connection events
  </Card>
</CardGroup>
