Skip to Content

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.

i
Server to server only

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." } ] }
FieldTypeNotes
errorsarrayOne or more error items.
errors[].codestringA stable, uppercase identifier. Branch your logic on this.
errors[].descriptionstringA short, English diagnostic for developers. Do not parse it.
X-Request-IDstringA 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.

i
Always log X-Request-ID

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.codeHTTPMeaning
INVALID_API_KEY401The Authorization header is missing, malformed, revoked, or unknown.
MISSING_SCOPE403The key is valid but lacks the scope this endpoint requires.
INSUFFICIENT_CREDITS402The account does not have enough credits for this action.
RATE_LIMITED429Too many requests. Respect the Retry-After header before retrying.
VALIDATION_ERROR422The request body or query parameters failed validation.
INVALID_JSON400The request body is not valid JSON and could not be parsed.
NOT_FOUND404The resource does not exist or is not owned by this account.
ORIGIN_REJECTED403The request came from a browser or disallowed origin. Call from your server.
UPSTREAM_ERROR502A 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

Branch on error.code

Use the stable uppercase code for logic. Never parse errors[].description, which is a free form English string meant for developers.

Log every request_id

Store X-Request-ID on both success and failure. It is the fastest way for support to trace a call.

Respect Retry-After

On a 429 RATE_LIMITED, read the Retry-After header and wait the stated number of seconds before retrying.

Retry only transient errors

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.

Keep keys server side

The API has no CORS. Calling from a browser yields ORIGIN_REJECTED and risks leaking your key. Always call from your backend.

Frequently Asked Questions

Last updated on