Vezmo App

Get started

Errors

Every response, success or failure, has the same envelope. Check success first: when it is false, message says what went wrong in one line and errors lists each problem. The HTTP status tells you what kind of problem it is.

The error body

404 Not Found
{
  "success": false,
  "message": "Invoice not found",
  "errors": [
    {
      "code": "http.404",
      "message": "Invoice not found",
      "statusCode": 404
    }
  ],
  "data": null,
  "requestId": "1b1f55e8-b214-48a9-92f1-d6aad8f7a312",
  "timestamp": "2026-10-17T09:30:00.000Z"
}
FieldWhat it holds
successAlways false on an error.
messageA short summary you can show or log.
errors[]One entry per problem: a code and a message, sometimes a field or extra detail such as required.
dataAlways null on an error.
requestIdThe id of this call. Quote it when you contact support. You can also send your own in an X-Request-Id header.

Status codes

StatusMeaningWhat to do
200 OKThe read or update worked.—
201 CreatedA POST created something.—
400 Bad RequestA field is missing or invalid.Fix the request; errors[] names each field.
401 UnauthorizedThe access token is missing, wrong or expired.Refresh the token and retry once.
403 ForbiddenYour API key lacks the permission the endpoint needs, or the endpoint isn't open to API keys.Add the permission in required to your key under VezmoPay → Developers.
404 Not FoundThe object doesn't exist in your account. With a test key, an object your account has in live mode answers 404 with the message No such invoice: a similar object exists in live mode, but a test mode key was used to make this request. (and the reverse with a live key).Check the id, or switch keys.
409 ConflictThe request clashes with the object's state, for example the payment is already paid.Reconcile the object; don't retry under a new key.
422 UnprocessableAn Idempotency-Key was reused with a different body.Use a new key for a new request.
429 Too Many RequestsYou went over a rate limit.Wait, then retry with backoff.
500 and aboveSomething failed on our side. The message is always generic.Retry with backoff. If it keeps failing, send support the requestId.

Validation errors

A 400 from a bad body lists every failing field, so you can fix them in one pass. Fields the endpoint doesn't know are ignored, not rejected, so check the spelling of optional fields against the endpoint's page.

400 Bad Request
{
  "success": false,
  "message": "Bad Request",
  "errors": [
    { "code": "validation.name must be a string", "message": "name must be a string" },
    { "code": "validation.email must be an email", "message": "email must be an email" }
  ],
  "data": null,
  "requestId": "…",
  "timestamp": "…"
}

Permission errors

A 403 names the permissions the endpoint needs in required. Add them to your key under VezmoPay → Developers; tokens you create afterwards carry them.

403 Forbidden
{
  "success": false,
  "message": "Insufficient API permissions",
  "errors": [
    {
      "code": "http.403",
      "message": "Insufficient API permissions",
      "required": ["subscription.read"]
    }
  ],
  "data": null,
  "requestId": "…",
  "timestamp": "…"
}

Handling errors

  • Retry only 429 and 5xx answers, with exponential backoff (for example 1 s, 2 s, 4 s, then stop).
  • Never retry a 4xx unchanged; it will fail the same way.
  • Before retrying a call that moves money, make it safe to repeat. See Idempotency.
Node.js
const res = await fetch(url, { headers: { Authorization: `Bearer ${accessToken}` } });
const body = await res.json();

if (!body.success) {
  // Show body.message; log body.requestId so support can find the call.
  console.error(res.status, body.message, body.requestId, body.errors);

  if (res.status === 401) await refreshAccessToken(); // then retry once
  if (res.status === 429 || res.status >= 500) await retryWithBackoff();
}