vlayervlayer docs
Conventions and errors

Conventions

Base URL, authentication, response shapes, pagination, rate limits and usage reporting shared by every Social Data API route.

Base URL and authentication

Your base URL comes with your credentials; the examples write it as {API_BASE_URL}. Send your API token as a Bearer token on every request:

curl -G {API_BASE_URL}/v1/stats \
  -H "Authorization: Bearer <API_TOKEN>" \
  --data-urlencode "url=https://www.instagram.com/p/ABC123/"

A missing or invalid token returns 401. Most routes accept any valid token. A few engagement verification routes need one with admin rights and return 403 otherwise: creating and advancing an attempt, redelivering an attempt's webhooks, and registering or disconnecting a creator's handle.

The routes for issuing and revoking tokens are in the Tokens reference.

Responses

The data lookup routes under /v1 return the result object itself. Every other route wraps it in data, and list routes add pagination:

{
  "data": [ ... ],
  "pagination": { "page": 1, "limit": 20, "total": 150 }
}

Errors return an error code and a human-readable message on every route. Branch on error; message may be reworded.

{ "error": "POST_NOT_FOUND", "message": "Post not found" }

Routes that read a post or profile can also return the codes listed in Data lookup errors.

A few cases fall outside that envelope:

  • A /v1 request with a missing or invalid parameter returns 422 VALIDATION_ERROR before anything is read. On the engagement verification routes, a request body or query string that fails validation is rejected by the schema layer with 400 and the validator's own report, not an error code.
  • In a batch, each failed result carries error as an object with code and message.
  • POST /social-accounts/disconnect answers 404 with a sentence in error and no message.

Pagination

Comments pages with a cursor: pass nextCursor back as cursor until hasMore is false.

The engagement verification list routes accept page (default 1) and limit (default 20), and cap limit at 100; a larger limit is rejected with 400 rather than clamped. GET /admin/brands and GET /admin/creators are not paginated: they take neither parameter and return every row.

Limits

LimitValueWhen you exceed it
GET /v1/stats, GET /v1/comments, GET /v1/profile60 per minute per client IP, for each route429 RATE_LIMITED
POST /v1/stats/batch60 URLs per minute per client IP, counting every URL in the batch429 RATE_LIMITED
URLs in one batch1 to 25422 VALIDATION_ERROR
Batch duration100 secondsUnfinished URLs return BATCH_TIMEOUT

Engagement verification adds its own:

LimitValueWhen you exceed it
Post metrics refresh, one challengeOnce every 5 minutes429 RATE_LIMITED
Post metrics refresh, any challenge200 per minute per client IP429 RATE_LIMITED
Post check (/admin/posts/thumbnail)10 per post per 5 minutes, and 100 per minute per token429 RATE_LIMITED
Likers refresh10 per minute per client IP, across every challenge429 RATE_LIMITED
Likers refresh maxCount1 to 5000, default 1000—
limit on a paginated list route100400
Webhook response timeAny 2xx within 10 secondsThe delivery is retried; see Webhooks
Comment history stored per challenge6,000 commentsThe walk back through older history stops; newer comments keep being stored. See historyComplete on Comments and metrics on a challenge

Limits that count per client IP are keyed on the address the request arrives from, not on your token, so every caller behind a shared egress address — an office network, a NAT gateway — counts as one. They are a guardrail against runaway callers rather than a budget to spend down.

Every 429 carries a Retry-After header. Wait for it instead of polling. 429 SCRAPING_RATE_LIMITED is different: reads are being throttled upstream, not by your own usage; see Data lookup errors.

Usage

GET /auth/usage reports what your tokens have done over a window, 30 days by default: requests, billable units and errors, in total and broken down by token, by route and by UTC day. A successful request counts one unit, a batch counts one per distinct post that succeeded, and a failed request counts none.

curl "{API_BASE_URL}/auth/usage?from=2026-09-01&to=2026-10-01" \
  -H "Authorization: Bearer <API_TOKEN>"
{
  "data": {
    "from": "2026-09-01T00:00:00.000Z",
    "to": "2026-10-01T00:00:00.000Z",
    "totals": { "requests": 1240, "billableUnits": 1180, "errors": 60 },
    "byToken": [{ "tokenId": 1, "name": "Production Token", "requests": 1240, "billableUnits": 1180, "errors": 60 }],
    "byRoute": [{ "method": "GET", "route": "/v1/stats", "requests": 900, "billableUnits": 880, "errors": 20 }],
    "byDay": [{ "day": "2026-09-16", "requests": 41, "billableUnits": 40, "errors": 1 }]
  }
}

from is inclusive, to exclusive, and the window may not exceed 400 days. Add tokenId to report on one token. A token revoked after use keeps its rows with a null tokenId.

Parameter tables and schemas for every route are in the API reference.

Last updated on