Errors

The Fluveo /v1 API uses conventional HTTP status codes and a Stripe-compatible error envelope. A 2xx is success; a 4xx means something about your request needs fixing; a 5xx is a problem on Fluveo’s side.

The error envelope

Every error returns JSON with a top-level error object:

1{
2 "error": {
3 "type": "invalid_request_error",
4 "code": "amount_too_small",
5 "message": "Amount must be at least 50",
6 "param": "amount"
7 }
8}
FieldMeaning
typeBroad category — branch your control flow on this.
codeSpecific, machine-readable reason (when applicable).
messageHuman-readable description. Log it; don’t show raw to end users.
paramThe offending request field, when the error is about one input.

Public responses use Stripe field names and never leak internal connector/provider/acquirer identifiers.

Error types

typeHTTPMeaningWhat to do
invalid_request_error4xxThe request was malformed or missing a field.Fix the request; param names the field.
authentication_error401API key is missing, invalid, or revoked.Check your secret key — see authentication. A revoked key may keep working for up to 60s.
card_error402The customer’s card was declined or failed a check.Surface the decline to the customer; don’t blindly retry.
idempotency_error409An Idempotency-Key was reused with a different request body.Use a fresh key, or replay the original request unchanged.
rate_limit_error429Too many requests.Back off and retry with exponential delay.
api_error5xxInternal Fluveo error.Safe to retry with the same Idempotency-Key.

Common error codes

These code values appear most often on the payment path (see the full schemas in the API Reference):

HTTPcodeCause
400parameter_missingA required field was absent.
400amount_too_smallAmount is below the connector’s minimum.
400amount_too_largeAmount is above the connector’s maximum.
402card_declinedCard issuer refused authorization. Includes a decline_code.
402expired_cardCard expired before the request landed.
402incorrect_cvcCVC failed the issuer’s check.
403authentication_requiredA 3DS step is required and no return_url was given.
404resource_missingThe object id does not exist (or belongs to another merchant — the two are indistinguishable by design).
409idempotency_errorIdempotency-Key collided with a non-matching request.
429rate_limit_errorToo many requests; back off.
500api_errorInternal Fluveo error; retry with the same Idempotency-Key.

Decline codes (decline_code)

On a card_declined response, decline_code carries the machine-readable reason. The common values:

decline_codeMeaning
generic_declineThe issuer declined without a specific reason.
insufficient_fundsThe account lacked funds.
fraudulentThe payment was refused by pre-payment antifraud screening (see below).

Antifraud screening

Card payments are screened for fraud before they reach the card network. If screening refuses a payment, the confirm call returns 402 with code: "card_declined" and decline_code: "fraudulent" — the same shape as any other decline, and the payment never reaches the issuer (no authorization, no charge). A refusal is indistinguishable from a network decline by design; do not surface “fraud” wording to the shopper.

Notes:

  • Retrying the same card on the same PaymentIntent replays the refusal. A shopper may try a different card, which is screened fresh.
  • The intent stays in requires_confirmation after a screening refusal (it is not moved to requires_payment_method); read the PaymentIntent if you need its current state. This is a documented deviation from Stripe’s post-decline state.
  • In the sandbox, screening runs against the provider sandbox; refusals are deterministic for the provider’s designated test cards so you can exercise the 402 path end to end.

Handling errors

A practical pattern:

  1. Branch on error.type, not on message text (messages may change).
  2. For card_error, show the customer a clear, non-technical decline message; the decline_code tells you why but is for your logs, not the cardholder.
  3. For invalid_request_error, fix the field named in param — these are programming errors, not runtime conditions.
  4. For rate_limit_error (429), back off exponentially before retrying.
  5. For api_error (5xx), retry the same request with the same Idempotency-Key so you never double-charge. Idempotent retries are the safe way to recover from transient failures — see the quickstart.

For the canonical envelope reference, see the overview.