cred.diy/ docs
    Sign inGet an API key
    All documentation

    Errors & Request IDs - cred.diy API documentation

    Errors & Request IDs

    Every error is JSON with a human-readable error, a machine-readable code where one applies, any fields the code documents, and the call's request_id. Branch on code (and on error_code for 402s), never on the message text.

    Request IDs

    Every response carries an X-Request-Id header (exposed to browsers via CORS), and every JSON error body (status 400 and up) includes the same value as request_id. Send your own X-Request-Id (8–128 characters: letters, digits, . _ : -) to trace a call end to end; without one (or with a malformed one) a UUID is generated. Quote it when you contact support so the call can be found in our logs. The SDK returns it as requestId on every response and error.requestId on failures, and takes { requestId } in per-call options.

    HTTP/1.1 400 Bad Request
    X-Request-Id: 6f1c2e4a-9b7d-4c1e-8a2f-3d5b7e9f1a2c
    
    { "error": "Insufficient credits", "code": "INSUFFICIENT_CREDITS", "requested_amount": 100,
      "request_id": "6f1c2e4a-9b7d-4c1e-8a2f-3d5b7e9f1a2c" }

    HTTP statuses

    400Invalid parameters or JSON, or a business rule (INSUFFICIENT_CREDITS, NO_FIELDS_TO_UPDATE, SWAP_NOT_BIDIRECTIONAL, …)
    401Missing, unknown, disabled or expired API key (INVALID_API_KEY, API_KEY_DISABLED, API_KEY_EXPIRED)
    402Out of CRD (PLATFORM_CREDITS_EXHAUSTED, payable via x402 when enabled), or Stripe refused money (STRIPE_REFUND_FAILED, STRIPE_TRANSFER_FAILED, CARD_DECLINED)
    403Platform Stripe Connect blocked for the project (AUP_NOT_ACCEPTED, AUP_VERSION_STALE, CATEGORY_RESTRICTED)
    404User or resource not found; an unknown endpoint lists available_endpoints
    409Conflict: IDEMPOTENCY_KEY_REUSED, TIER_IN_USE, USER_HAS_HISTORY, ALREADY_REFUNDED, HOLD_NOT_ACTIVE
    429RATE_LIMITED — free (no CRD charged); back off until X-RateLimit-Reset
    500Internal error — quote the request_id to support
    502Stripe's outcome unknown: PAYOUT_PENDING (/redeem) or charge_not_started (/charge-saved) — retry with the same idempotency key

    Authentication, metering and rate limits

    CodeStatusMeaning
    INVALID_API_KEY401Missing, malformed (not sk_live_) or unknown API key. (every API-key call)
    API_KEY_DISABLED401The key was disabled on the API Keys page. (every API-key call)
    API_KEY_EXPIRED401The key's expiration date has passed. Create a new key; expiry is enforced. (every API-key call)
    RATE_LIMITED429Over 100 requests/minute for this key (30/minute per IP on the public x402 routes). Checked before the 1 CRD charge, so a 429 costs nothing. Retry after X-RateLimit-Reset (unix seconds). (every API-key call)
    PLATFORM_CREDITS_EXHAUSTED402Your CRD (platform credit) balance is spent. Sent as both code and error_code, with credits_remaining; when x402 is enabled the 402 also carries a PAYMENT-REQUIRED offer you can pay and retry the same request with. (every API-key call)
    AUP_NOT_ACCEPTED / AUP_VERSION_STALE / CATEGORY_RESTRICTED403The project has not accepted the current acceptable-use policy, or its business category is restricted on the platform account. (checkout and charges on platform Stripe Connect)

    Idempotency

    CodeStatusMeaning
    INVALID_IDEMPOTENCY_KEY400The idempotency key is longer than 255 characters. (any write with a key)
    IDEMPOTENCY_KEY_REUSED409This key was already used for a different request. A retry of the same request returns the first result (idempotent_replay: true) instead. (/issue, /deduct, /refund, /swap, /redeem, /escrow/hold, /charge-saved)
    IDEMPOTENCY_KEY_REQUIRED400Off-session charges need an Idempotency-Key header (or idempotency_key). (/charge-saved)

    Credits, users and pricing tiers

    CodeStatusMeaning
    INSUFFICIENT_CREDITS400The user's balance is too low. /deduct and /redeem include requested_amount; /swap includes required. Not 422. (/deduct, /escrow/hold, /redeem, /swap, /refund (clawback))
    INVALID_CREDIT_TYPE400credit_type_id is not an active credit type in this project. (/issue, /deduct, /escrow/hold, referral settings)
    USER_NOT_FOUND404No user with that user_email / user_id (external_id) in this project. Only /issue and POST /users create users. (user-scoped endpoints)
    NO_FIELDS_TO_UPDATE400The body has none of email, name, metadata, signup_url, signup_host, signup_credit_type_id, wallet_address. (PATCH /users)
    USER_HAS_HISTORY409The user has swap history, kept as a financial record, so the user cannot be deleted (swap_transactions gives the count). (DELETE /users)
    TIER_IN_USE409Auto top-up rules buy this tier (auto_topup_rules gives the count). Move them, or retry with force: true to delete the rules and the tier in one transaction. (DELETE /pricing-tiers)
    tier_not_one_time400The tier is recurring-only; saved-card charges need a one-time (or both) tier. (/charge-saved, POST /auto-topup)

    Escrow holds

    CodeStatusMeaning
    HOLD_NOT_FOUND404No hold with that id in this project. (/escrow/release, /escrow/capture)
    HOLD_NOT_ACTIVE409The hold was already released or captured. (/escrow/release, /escrow/capture)
    CAPTURE_EXCEEDS_HELD400The capture amount is more than the hold. (/escrow/capture)
    INVALID_AMOUNT400amount must be a positive number. (/escrow/*)

    Swaps

    CodeStatusMeaning
    SWAP_NOT_BIDIRECTIONAL400direction "reverse" on a one-way pair. Enable Bidirectional on the pair to swap target → source. (/swap)
    INVALID_DIRECTION400direction must be "forward" or "reverse". (/swap)

    Refunds

    CodeStatusMeaning
    PURCHASE_NOT_FOUND404No purchase with that purchase_id / stripe_payment_intent_id in this project. (/refund)
    TRANSACTION_NOT_FOUND404No transaction with that transaction_id / reference_id in this project. (/refund)
    ALREADY_REFUNDED409The source was already refunded in full. (/refund)
    PURCHASE_NOT_REFUNDABLE400Only completed purchases can be refunded. (/refund)
    NOT_REFUNDABLE400Redeem and escrow transactions have their own reversal flows and cannot be refunded here. (/refund)
    REFUND_EXCEEDS_ORIGINAL400The amount is more than what is left to refund. (/refund)
    STRIPE_REFUND_FAILED402Stripe refused the money refund; no credits moved. (/refund)

    Cash payouts (redeem)

    CodeStatusMeaning
    NOT_REDEEMABLE400The credit type is not marked Redeemable for Cash. (/redeem)
    PAYOUT_TOO_SMALL400amount × exchange_rate rounds to zero. (/redeem)
    INVALID_DESTINATION400destination is not this user's own payout account from /onboard-payout (or they have none). (/redeem)
    STRIPE_KEYS_MISSING400The project has no Stripe secret key under Payments → Your Own Keys. (/redeem, /onboard-payout)
    STRIPE_TRANSFER_FAILED402Stripe refused the transfer; the credits were returned (new_balance). (/redeem)
    PAYOUT_PENDING502Stripe's answer was lost; the credits stay deducted. Retry with the returned idempotency_key to finish it — it never pays twice. If you never retry, the reconciliation sweep settles it after 15 minutes (paid, or credits returned only if Stripe definitively refuses). A claim the sweep cannot settle safely is flagged needs_review for manual review instead of being paid or refunded; retries keep answering PAYOUT_PENDING until then. (/redeem)

    Saved cards (POST /charge-saved, auto top-up)

    CodeStatusMeaning
    CARD_DECLINED402Sent as error_code. code is Stripe's (e.g. card_declined), with decline_code, message and purchase_id. (/charge-saved)
    CARD_AUTHENTICATION_REQUIRED402Sent as error_code with requires_action: true — the bank wants the buyer present (3-D Secure). Send them through hosted checkout. (/charge-saved)
    no_saved_payment_method404The user has no saved card. (DELETE /payment-method answers 200 { deleted: false } with this code instead.) (/charge-saved)
    saved_payment_method_unusable409The card was saved on a Stripe account the project no longer charges through. The buyer must save a card again at checkout. (/charge-saved)
    charge_not_started502Stripe could not be reached to start the charge. Retry with the same idempotency key; it never charges twice. (/charge-saved)

    Referrals

    CodeStatusMeaning
    INVALID_REFERRAL_CODE400No referrer has this code. (/referrals/apply)
    ALREADY_REFERRED400The user already used a referral code. (/referrals/apply)
    SELF_REFERRAL400A user cannot use their own code. (/referrals/apply)

    Own-keys Stripe webhook (payment-webhook, seen in Stripe's delivery log)

    CodeStatusMeaning
    MISSING_SIGNATURE400The delivery has no Stripe-Signature header. (payment-webhook)
    INVALID_PROJECT400?project_id in the endpoint URL is not a valid project id. (payment-webhook)
    WEBHOOK_SECRET_NOT_CONFIGURED400No signing secret saved for this project. Save the endpoint's whsec_ secret under Payments → Your Own Keys. (payment-webhook)
    INVALID_SIGNATURE400The signature does not match the saved signing secret (wrong or rotated whsec_). (payment-webhook)

    SDK-side (no HTTP response)

    CodeStatusMeaning
    TIMEOUT—The request exceeded the client timeout (default 30 s). (@cred-diy/sdk)
    NETWORK_ERROR—fetch failed, or no fetch implementation is available. (@cred-diy/sdk)
    INVALID_RESPONSE—The API answered 2xx with a body that is not JSON. (@cred-diy/sdk)

    Your first credit is one request away.

    Create a project, copy an API key, and issue a credit from your server.