Errors
Successful VDClip REST API responses under https://api.vdclip.com/v1 return resource data
directly. Failed responses return an errors array. Branch on errors[].code for logic, and
show errors[].description to a developer.
The REST API has no CORS support. Calls must be made from your backend with the
Authorization: Bearer vdck_... header. Never embed an API key in a browser, mobile app, or any client
that ships to end users. A request from a rejected origin returns ORIGIN_REJECTED.
Error shape
Failed /v1/* endpoints return this top level shape:
{
"errors": [
{
"code": "INSUFFICIENT_CREDITS",
"description": "Not enough credits to start this render."
}
]
}| Field | Type | Notes |
|---|---|---|
errors | array | One or more error items. |
errors[].code | string | A stable, uppercase identifier. Branch your logic on this. |
errors[].description | string | A short, English diagnostic for developers. Do not parse it. |
X-Request-ID | string | A unique id for this request. Always log it. |
On success, endpoints return the resource data directly. Pagination fields and limits are defined per endpoint in the OpenAPI spec.
Every response carries a X-Request-ID. Log it for both successes and failures. When you
contact support at contact@vdclip.com, include the X-Request-ID of the failing call so we can
trace the exact request in our logs. Without it, debugging is far slower.
Error codes
Every error code, its HTTP status, and what it means. The HTTP status and error.code always
agree, so you can branch on either.
error.code | HTTP | Meaning |
|---|---|---|
INVALID_API_KEY | 401 | The Authorization header is missing, malformed, revoked, or unknown. |
MISSING_SCOPE | 403 | The key is valid but lacks the scope this endpoint requires. |
INSUFFICIENT_CREDITS | 402 | The account does not have enough credits for this action. |
RATE_LIMITED | 429 | Too many requests. Respect the Retry-After header before retrying. |
VALIDATION_ERROR | 422 | The request body or query parameters failed validation. |
INVALID_JSON | 400 | The request body is not valid JSON and could not be parsed. |
NOT_FOUND | 404 | The resource does not exist or is not owned by this account. |
ORIGIN_REJECTED | 403 | The request came from a browser or disallowed origin. Call from your server. |
UPSTREAM_ERROR | 502 | A dependency failed. Transient. Retry with exponential backoff. |
New codes may be added in minor versions. Treat an unrecognized error.code as a generic
failure and fall back to success and the HTTP status. Existing codes are never repurposed.
What each error means
INVALID_API_KEY
401. The key is missing, malformed, revoked, or not recognized. Confirm you are sending Authorization: Bearer vdck_... and that the key is still active.
MISSING_SCOPE
403. The key works but does not carry the scope this endpoint needs. Scopes use the form vdclip:resource:action. Re-issue the key with the required scope.
INSUFFICIENT_CREDITS
402. The action needs more credits than the account has. Top up or upgrade. See the pricing page for what each plan includes.
RATE_LIMITED
429. You sent requests too fast. The response includes a Retry-After header in seconds. Wait that long, then retry.
VALIDATION_ERROR
422. A field in the body or query string is missing or invalid. The message names what failed. Fix the request and resend.
INVALID_JSON
400. The request body is not parseable JSON. Check your serialization and Content-Type header, then resend.
NOT_FOUND
404. The resource id does not exist, or it belongs to another account. Verify the id and that your key owns the resource.
ORIGIN_REJECTED
403. The call came from a browser or an origin the API does not allow. The API is server to server only, with no CORS. Move the call to your backend.
UPSTREAM_ERROR
502. A downstream dependency failed. This is usually transient. Retry with exponential backoff and log the request_id if it persists.
Plan gated scopes
Two scopes are gated by plan: vdclip:render:execute and vdclip:social:publish. If your key
holds one of these scopes but your plan does not include the feature, the call returns
MISSING_SCOPE or INSUFFICIENT_CREDITS depending on the gate. Review what your plan covers on
the pricing page before relying on these endpoints. For the full list of scopes and which
endpoints require them, see Authentication.
Handling rate limits
When you receive RATE_LIMITED (HTTP 429), the response carries a Retry-After header that
tells you how many seconds to wait before trying again:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{
"errors": [
{
"code": "RATE_LIMITED",
"description": "Rate limit exceeded. Retry after 12 seconds."
}
]
}Honor Retry-After rather than retrying immediately. For more detail on limits and backoff
strategy, see Rate limits.
OAuth and agent clients
The envelope here applies to the /v1/* endpoints authenticated with Authorization Bearer. The OAuth 2.1
Authorization Server at /oauth2/* and /.well-known/* (issuer https://api.vdclip.com), used by
MCP servers, AI agents, and third-party integrations with Authorization: Bearer <JWT>, returns
standard RFC bodies instead. Handle its errors separately. See OAuth.
Tips & Best Practices
Use the stable uppercase code for logic. Never parse errors[].description, which is a free form English string meant for developers.
Store X-Request-ID on both success and failure. It is the fastest way for support to trace a call.
On a 429 RATE_LIMITED, read the Retry-After header and wait the stated number of seconds before retrying.
Retry UPSTREAM_ERROR (502) and RATE_LIMITED (429) with backoff. Do not retry validation, scope, or credit errors. Fix the request or the account instead.
The API has no CORS. Calling from a browser yields ORIGIN_REJECTED and risks leaking your key. Always call from your backend.