Skip to main content

Error Codes

All errors return a consistent JSON structure with a machine-readable code field for programmatic handling and a human-readable message field for debugging.
{
  "error": {
    "type": "invalid_request_error",
    "message": "Amount must be between 0.01 and 10000",
    "param": "amount",
    "code": "amount_out_of_range"
  }
}

Error Types

TypeDescription
invalid_request_errorThe request was malformed or missing required parameters.
authentication_errorInvalid, expired, or missing API key.
authorization_errorValid API key but insufficient permissions for the requested resource.
not_found_errorThe requested resource does not exist.
conflict_errorThe request conflicts with existing state (e.g., duplicate idempotency key, cancelling a confirmed intent).
rate_limit_errorToo many requests. Back off and retry.
api_errorAn internal error on our side. Retry with exponential backoff.

Payment Intent Errors

CodeHTTP StatusDescriptionResolution
amount_out_of_range400Amount is below 0.01orabove0.01 or above 10,000.Adjust the amount to within the allowed range.
invalid_currency400Currency is not usd.Set currency to "usd".
invalid_merchant400Merchant ID is malformed.Check the merchant ID format (mer_*).
merchant_not_found404Merchant does not exist or is not accessible to this API key.Verify the merchant ID and API key permissions.
merchant_not_active422Merchant account is suspended or deactivated.Contact support or check merchant status in the dashboard.
intent_not_cancellable409Payment intent is not in awaiting_payment status.Only intents with status awaiting_payment can be cancelled.
idempotency_key_conflict409The idempotency key was used with different parameters.Use a unique idempotency key for each distinct request.
ttl_out_of_range400TTL is below 60 or above 3600 seconds.Set TTL between 60 and 3600.

Authentication Errors

CodeHTTP StatusDescriptionResolution
missing_api_key401No Authorization header provided.Include Authorization: Bearer sk_* in request headers.
invalid_api_key401API key is malformed or does not exist.Check that the key is correct and hasn’t been revoked.
revoked_api_key401API key has been revoked.Generate a new API key from the dashboard.
environment_mismatch403Using a test key against production resources or vice versa.Use sk_test_* for sandbox and sk_live_* for production.

Webhook Errors

CodeHTTP StatusDescriptionResolution
invalid_webhook_url400Webhook URL is not a valid HTTPS URL.Provide a valid HTTPS URL.
webhook_unreachable422Could not reach the webhook URL during registration.Ensure your endpoint is publicly accessible and returns 200.

Rate Limit Errors

CodeHTTP StatusDescriptionResolution
rate_limit_exceeded429Too many requests in the current window.Wait and retry. Check X-RateLimit-Reset header for when the window resets.

Handling Errors

async function createPaymentIntent(amount, merchantId) {
  const response = await fetch('https://api.stablegenius.co/v1/payment-intents', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ amount, currency: 'usd', merchant_id: merchantId }),
  });

  if (!response.ok) {
    const { error } = await response.json();

    switch (error.type) {
      case 'authentication_error':
        // API key issue — check configuration
        throw new Error(`Auth failed: ${error.message}`);
      case 'rate_limit_error':
        // Back off and retry
        const resetAt = response.headers.get('X-RateLimit-Reset');
        await sleep(resetAt * 1000 - Date.now());
        return createPaymentIntent(amount, merchantId); // Retry
      case 'api_error':
        // Our issue — retry with backoff
        await sleep(1000);
        return createPaymentIntent(amount, merchantId);
      default:
        throw new Error(`API error: ${error.code}${error.message}`);
    }
  }

  return response.json();
}

Best Practices

  • Always check error.code for programmatic handling, not error.message (messages may change).
  • Retry on 429 and 500 with exponential backoff. Use the X-RateLimit-Reset header for rate limits.
  • Never retry on 400, 401, 403, 404 — these indicate issues with your request, not transient failures.
  • Log the full error response for debugging. Include the error.type, error.code, and error.param fields.