Onlys vault API v1

Base URL: https://onlys.vip/api/v1. JSON over HTTPS, server-to-server. See OpenAPI and Chatters integration.

Public documentation: onlys.vip/developers. This page documents the deployed API v1, not proposed endpoints.

Available capabilities

The API lists private vault assets and folders, returns individual asset metadata, and generates or revokes expiring access links. Photos, videos and audio are supported. API keys are generated/revoked by the creator in the dashboard.

Uploads, file deletion, folder creation, thumbnail-frame changes, import progress, visual-group filtering and API-key management are not exposed by API v1. Dashboard routes are not bearer-token API endpoints. There is no vault:write scope, OnlyFans synchronization endpoint, or webhook subscription endpoint.

Create credentials

Sign in as the creator and open /dashboard/api-keys (also linked from the vault). Enter a name, permissions, optional UTC expiry, and your account password. Copy the key once; it cannot be retrieved later. Multiple keys allow rotation: create a replacement, update your client, then revoke the old key.

Send Authorization: Bearer ovk_<id>.<secret> on every API request. Never put a key in a URL, browser extension, frontend bundle, source control, or logs. vault:read permits metadata reads; vault:links permits link creation and revocation. /me accepts either permission. Keys only access their creator's vault. An active, verified account, unsuspended profile, enabled vault and active Professional entitlement are required. Keys can still be revoked in the dashboard after entitlement expires.

Endpoints

Method/pathPermissionResponse
GET /meEitherCreator ID, handle, name, scopes, vault expiry
GET /vault/assetsvault:readPaginated metadata
GET /vault/assets/{id}vault:readSingle asset metadata
GET /vault/foldersvault:readAll creator folders (vault maximum 100)
POST /vault/assets/{id}/linksvault:linksOriginal/preview download link
DELETE /vault/links/{id}vault:links204; revoke a managed link

Successful responses wrap results in data. Listing also returns next_cursor. Asset IDs are opaque strings. Do not construct storage URLs or infer ownership.

List filters: type=image|video|audio, state=uploading|quarantined|ready|failed|deleting, folder_id, q (name/tags, up to 100 bytes), limit (1–100, default 50), and cursor. Default lists all non-deleted states, including suspended records with suspended: true. Use state=ready for a catalog; suspension still prevents links. Keep filters identical while following cursors. Ordering is newest created first, then ID descending; cursors are opaque and must be URL-encoded. Pagination is not a snapshot: a subsequent complete refresh discovers new/deleted assets.

Stop pagination only when next_cursor is null; use asset IDs to reconcile records across refreshes. A partial or failed scan must not be treated as a list of deleted assets. No total-file count is returned by this endpoint.

Asset fields: id, name, type, state, suspended, bytes, mime_type, width, height, duration_seconds, sha256, folder_id, tags, has_preview, created_at, updated_at. Media fields can be null before processing. tags is the creator's existing free-text string; it is not a normalized array. Bytes mean stored original bytes, not a reserved upload size. Timestamps use UTC RFC 3339.

Resolutions, previews and visual variants

Use width and height to show resolution (for example, 1920 × 1080), and duration_seconds for playback length. These fields can be null while processing or when not applicable, including image/video dimensions for audio. File size, resolution or duration alone does not establish that two files contain the same content. Higher pixel dimensions do not guarantee better source quality.

The dashboard can label related encodings and likely visual variants, but those group IDs, labels and group/resolution sort options are not returned or accepted as supported filters by API v1. Keep each asset ID distinct in API clients; do not infer dashboard groups or delete files from visual similarity. Matching non-null verified sha256 values indicate byte-identical originals, not merely different resolutions of the same scene.

For a small preview, create a link with variant: "preview". has_preview indicates an available preview object, not an original-quality copy. A video thumbnail can be changed in the dashboard; request a fresh preview link to see the current preview. Previously issued links may still refer to the older image. The variant link parameter means original versus preview, not a visual variant group or a requested resolution/transcode.

Quick start

curl --fail-with-body https://onlys.vip/api/v1/me \
  -H "Authorization: Bearer $ONLYS_API_KEY"
curl --fail-with-body 'https://onlys.vip/api/v1/vault/assets?state=ready&type=video&limit=50' \
  -H "Authorization: Bearer $ONLYS_API_KEY"
curl --fail-with-body "https://onlys.vip/api/v1/vault/assets/$ASSET_ID/links" \
  -H "Authorization: Bearer $ONLYS_API_KEY" -H 'Content-Type: application/json' \
  --data '{"variant":"original","mode":"managed","expires_in":86400}'

Link input defaults: original, managed, 86400. variant accepts original or preview; mode accepts managed or direct. expires_in must be an integer from 60 to 604800 seconds (7 days). Expiry starts at creation, not first download. The effective deadline is capped by key expiry and creator entitlement expiry; the response's expires_at and expires_in are authoritative, even if fewer than 60 seconds remain. Only ready, unsuspended assets can receive links.

Example response (illustrative, not a usable token):

{
  "data": {
    "id": "0123456789abcdef0123456789abcdef",
    "asset_id": "abcdef0123456789abcdef0123456789",
    "variant": "original",
    "mode": "managed",
    "url": "https://onlys.vip/vault/access/EXAMPLE_TOKEN",
    "expires_at": "2026-09-20T12:00:00Z",
    "expires_in": 86400,
    "revocable": true
  }
}

Access and revocation

Managed URLs can be opened without the API key. GET rechecks the issuing key, entitlement, account/profile, asset, grant revocation and expiration, then returns a 302 redirect to R2 with a maximum five-minute validity, capped by the remaining access window. Media bytes are served by R2. DELETE revokes a managed link owned by the same creator (including links made with another key). Repeated DELETE is 204 while the record exists. Revoking a key disables all its managed links.

Direct URLs are R2 presigned GET URLs. They have id: null and revocable: false. They cannot be individually revoked through this API. Key revocation, suspension or later entitlement changes do not invalidate an already issued direct URL. Use managed mode when those changes must affect future visits.

Anyone holding either URL can download or share it. Neither identifies a buyer or proves payment; this is creator-authorized external access, not commerce fulfillment. Already issued R2 URLs survive until expiry, and transfers already started may continue. Saved files cannot be recalled. Renewing access requires a new authenticated request; visiting the URL does not reset its deadline.

Do not forward the Onlys Authorization header to R2 or to a managed URL. Use a separate unauthenticated download request following redirects. Avoid logging URLs. Normal navigations/downloads do not need browser CORS; JavaScript cross-origin fetch is not enabled by this API. Keep metadata and link generation on the backend.

Errors, limits, retries

{"error":{"code":"forbidden","message":"Required permission: vault:links","request_id":"example"}}

Statuses: 400 invalid JSON/request, 401 invalid/expired/revoked key, 403 missing scope or inactive access, 404 missing/foreign asset, unknown endpoint or expired managed link, 405 unsupported method on access URL, 409 asset/preview unavailable, 413 body too large, 415 wrong content type, 422 invalid values, 429 rate limit, 500 internal error, 503 disabled vault or temporarily unavailable database. Database startup failures return the same JSON error envelope with a request ID and Retry-After: 5. No login redirects occur on API routes. Responses carry X-Request-ID and Cache-Control: no-store.

Limits use fixed minute buckets: 120 requests/key, 300 requests/creator, 600 requests/IP (including managed access), and 60 link creations/creator. 429 returns Retry-After: 60. JSON bodies are limited to 16 KiB. Back off on 429/503; do not automatically retry 401/403. GET and DELETE can be retried; POST is not idempotent and may create an additional grant if retried after a lost response. Store the returned link ID and expiry if you need revocation.