Work in progress. Some documented features are not live yet.

Errors and retries

Handle rejected charges and retry requests without duplicate debits or deposits.

API errors return a code and message:

{
  "error": "insufficient_balance",
  "message": "This wallet does not have enough credits."
}

The SDK exposes rejected API requests as OrbyteApiError, with status, code, and message.

Handle a rejected charge

import { OrbyteApiError, track } from "@orbytelabs/credit";

try {
  await track("api-call", "customer_123", { id: "request_123:api-call" });
} catch (error) {
  if (
    error instanceof OrbyteApiError &&
    error.code === "insufficient_balance"
  ) {
    // Ask the customer to add credits, or stop further work.
  } else {
    throw error;
  }
}

An insufficient-balance error creates no usage transaction or debit. After funding the wallet, retry the same event ID and payload. An allowed check does not reserve funds, so tracking can still fail if another request spends the balance first.

An unaffordable check itself returns allowed: false with HTTP 200. Invalid input, credentials, or pricing configuration can still cause a check to throw.

For included plan usage, check can return reason: "feature_limit_exceeded" or reason: "subscription_inactive". Tracking the same usage returns a 409 error with that code. A blocked allowance requires a plan change or a new allowance period; an inactive subscription requires restoring its active state. Adding prepaid credits alone does not resolve either denial.

Error codes

StatusCodesWhat to do
400invalid_request, invalid_event, invalid_json, invalid_quantityFix the request shape, quantity, or pricing inputs. Unknown properties are rejected.
401unauthenticated, invalid_api_keyCheck the secret key and whether it has expired or been revoked.
403forbidden, forbidden_api_keyUse a secret key with the required permission.
404not_found, feature_not_found, wallet_not_foundCheck the resource key or identity and the application selected by your API key.
409feature_limit_exceededWait for the quota period to reset, change plans, or use a plan with credit overage.
409subscription_inactiveRestore an active subscription before using its included features.
409insufficient_balanceFund the wallet before retrying usage.
409idempotency_conflictReuse the original payload for a retry. Use a new ID only for a new operation.
409conflictInspect the message for an existing catalog key, locked period policy, balance overflow, or wallet balance limit.
409stripe_not_connected, stripe_not_readyConnect Stripe, complete onboarding, or finish plan synchronization before retrying checkout.
413payload_too_largeKeep the JSON request body within 16 KiB.
415unsupported_media_typeSend Content-Type: application/json on write requests.
422credit_not_found, invalid_billing_period, unsupported_pricing, invalid_chargeFix the feature's credit, billing period, or charge calculation.
429rate_limitedWait for the Retry-After delay before retrying.
500internal_errorRetry eligible operations with the same IDs and payloads.
502stripe_errorInspect the payment state before retrying with the same operation key.

Missing resources are scoped to the API key's application. For example, a feature deployed in Development is not available to a Production key until you deploy it there.

Retry the same operation

If a response is lost, the server may already have accepted the request. Keep the identifiers for that operation:

  • Usage uses id, unique within the application. An identical retry returns the original transaction with status: "duplicate".
  • Funding uses idempotencyKey, also unique within the application. An identical retry returns the original deposit with duplicate: true.
  • Checkout and subscription changes use stable idempotencyKey values for each purchase or change. Reuse the same inputs on retries.

The namespaces are separate. The same string can identify one event and one deposit, but two different usage events must not share an ID.

For callback prices, a retry must resolve to the same nanocredit amount. Automatic SDK retries preserve the serialized request. If your own job calls the SDK again, preserve the original pricing inputs and calculation too.

Automatic SDK retries

For check, track, topup, reads, and supported updates, the SDK makes up to three attempts for transport failures, interrupted responses, HTTP 429, and server errors. Each attempt has a 20-second timeout. Retries use exponential backoff and honor a positive Retry-After delay up to 30 seconds.

After retries are exhausted, network failures raise OrbyteTransportError; valid API error responses raise OrbyteApiError. Local input validation and unexpected response shapes can raise other errors, so retain an unknown-error path in your handler.

Catalog creation does not automatically retry uncertain network or server failures. Read the catalog before trying another creation. The SDK can retry a catalog request explicitly rejected with rate_limited because that request was not admitted.

Rate and size limits

API requests are limited per key to 600 per minute, with a burst capacity of 120. Failed authenticated requests also use request capacity. If your own retry loop runs beyond the SDK's attempt limit, keep it bounded and respect Retry-After.

JSON bodies are limited to 16 KiB. Unknown JSON fields and repeated query parameters are rejected. API amounts must be nonnegative integer strings within the supported 64-bit range; deposits must be positive. See pricing for precision rules.

Use the API reference for each operation's required permissions and schemas.

On this page