RailbedDocs

Errors

Every error the Railbed API returns, with its HTTP status, what caused it and what to do next.

The error object

Every error has an HTTP status of 400 or above and the same JSON body:

An error
{
  "error": {
    "code": "no_payout_wallet",
    "message": "Add a payout wallet in the dashboard before taking live payments."
  }
}
409 Conflict
FieldTypeDescription
codestringStable and machine-readable. Branch on this
messagestringA sentence for people. It can be reworded at any time, so show it or log it, but never parse it
fieldstringThe request field at fault, when there is one: amount, metadata, starting_after

Handling errors

Decide by status first, then by code where it matters:

StatusMeaningWhat your code should do
400The request was invalidFix the request. Retrying it unchanged fails the same way
401The key is missing, malformed or revokedCheck the key and its mode. Don't retry
403Not allowed for this account or keyDon't retry
404Not found in this account and modeCheck the id and whether the key's mode matches the object's
409The object's state doesn't allow thisRead the object and act on its current status
410The session can't be paid any moreCreate a new session
413, 415The body is too large or isn't JSONFix the request
429Rate limitedWait for Retry-After seconds, then retry
500, 502, 503Something failed on our side or upstreamRetry with backoff. Creates are safe to retry with the same Idempotency-Key
A small error handler
async function railbed(path, init = {}) {
  const res = await fetch(`https://pay.railbed.io/v1${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.RAILBED_SECRET_KEY}`,
      'Content-Type': 'application/json',
      ...init.headers,
    },
  });
  const body = await res.json();
  if (res.ok) return body;
  const err = Object.assign(new Error(body.error.message), {
    status: res.status,
    code: body.error.code,
    field: body.error.field,
  });
  err.retryable = res.status === 429 || res.status >= 500;
  err.retryAfter = Number(res.headers.get('Retry-After')) || null;
  throw err;
}

Every code

400 Bad Request

CodeEndpointCause
invalid_jsonAny with a bodyThe body isn't a JSON object
invalid_amountCreateamount isn't a string, or isn't from "1.00" to "100000.00" with at most two decimal places
invalid_currencyCreatecurrency isn't USD, EUR, GBP, CAD or AUD
missing_descriptionCreatedescription is missing, blank or not a string
too_longCreatedescription or reference is over 120 characters. See field
invalid_referenceCreatereference isn't a string
invalid_emailCreate, Startcustomer_email isn't a valid address, or Start needs one and none is on the session
invalid_urlCreatesuccess_url or cancel_url isn't a full http(s):// address, has a username or password, is over 1,000 characters, or isn't https:// in Live mode
invalid_metadataCreateOver 20 keys, a blank key, a key over 40 characters or starting with __, or a value that isn't a string of at most 500 characters
invalid_idempotency_keyCreateThe Idempotency-Key header is blank, over 120 characters or has characters other than printable ASCII
invalid_countryStartcountry isn't a two-letter code such as US
invalid_limitList paymentslimit isn't a whole number from 1 to 100
invalid_cursorList paymentsstarting_after isn't one of your payments in this mode
invalid_outcomeSimulateoutcome isn't paid, underpaid or failed

401 Unauthorized

CodeCause
invalid_api_keyNo Authorization: Bearer header, a malformed key, or a revoked one. Create a key in Developers

403 Forbidden

CodeCause
suspendedThe account is suspended. Contact support
live_paymentSimulate was called on a Live payment. Only Test payments can be simulated

404 Not Found

CodeCause
not_foundNo such session or payment in your account in this key's mode, or no such endpoint. A Test key can't see Live objects and the other way round

409 Conflict

CodeEndpointCause
idempotency_conflictCreateThe key was used with a different body. Rarely, the first request with the key hadn't finished saving: retry in a moment
no_payout_walletCreateLive mode needs a payout wallet. Add one in Settings
unavailableStartThe account can't take payments now
no_providersStartNo card provider can take this amount and currency right now. Nothing was started; try later or a different amount
already_paidStartThe payment is complete
heldStartThe money arrived and the payment is held for review
failedStartThe payment was declined. Create a new session
not_startedSimulateStart the session before simulating

410 Gone

CodeCause
expiredThe session passed its expires_at without being paid
canceledThe payment link was canceled in the dashboard

Size, type and rate

StatusCodeCause
413request_too_largeThe body is over 64 KiB
415unsupported_media_typeThe body isn't sent as Content-Type: application/json
429rate_limitedOver about 120 requests a minute, or 12 starts a minute. Wait for Retry-After

5xx

StatusCodeCause
500internalSomething failed on our side. Retry with backoff; contact support if it continues
502network_unavailableThe card network didn't answer while starting. Retry in a minute
503misconfiguredCard payments are briefly unavailable. Retry later

Updated · This page as Markdown