Everything a sk_test_ key does stays in test data: cards are not charged, banks see nothing, and every object carries livemode: false. Build and check your whole integration this way. Fluveo serves only test mode today. See Authentication.
In test mode Fluveo does not e-mail your store's notices to your address, such as a payment, a dispute, a request for more details to verify your business or the news that it is verified: the Dashboard shows each of them, and Activation in Settings shows your verification.
Pay with a test card#
You never send card numbers to the API. In test mode, pass one of the names below as payment_method when you create and confirm a PaymentIntent, or when you confirm it later. Each use makes a new PaymentMethod (pm_...) in your store with the brand and last four digits shown.
curl https://api.fluveo.com/v1/payment_intents \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: test-decline-1" \
-d amount=2000 \
-d currency=usd \
-d "payment_method_types[]=card" \
-d payment_method=pm_card_visa_chargeDeclined \
-d confirm=trueconst response = await fetch("https://api.fluveo.com/v1/payment_intents", {
method: "POST",
headers: { Authorization: "Bearer sk_test_...", "Idempotency-Key": "test-decline-1" },
body: new URLSearchParams({
amount: "2000",
currency: "usd",
"payment_method_types[]": "card",
payment_method: "pm_card_visa_chargeDeclined",
confirm: "true",
}),
});
const body = await response.json();
console.log(response.status, body.error?.code, body.error?.decline_code);import requests
response = requests.post(
"https://api.fluveo.com/v1/payment_intents",
headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": "test-decline-1"},
data={
"amount": 2000,
"currency": "usd",
"payment_method_types[]": "card",
"payment_method": "pm_card_visa_chargeDeclined",
"confirm": "true",
},
)
error = response.json().get("error", {})
print(response.status_code, error.get("code"), error.get("decline_code"))<?php
$ch = curl_init("https://api.fluveo.com/v1/payment_intents");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_...", "Idempotency-Key: test-decline-1"],
CURLOPT_POSTFIELDS => http_build_query([
"amount" => 2000,
"currency" => "usd",
"payment_method_types" => ["card"],
"payment_method" => "pm_card_visa_chargeDeclined",
"confirm" => "true",
]),
]);
$body = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . " " . ($body["error"]["code"] ?? "") . " " . ($body["error"]["decline_code"] ?? "");Successful payments#
payment_method | Brand | Last 4 | Outcome |
|---|---|---|---|
pm_card_visa | Visa, credit | 4242 | The payment succeeds. |
pm_card_visa_debit | Visa, debit | 5556 | The payment succeeds. |
pm_card_mastercard | Mastercard, credit | 4444 | The payment succeeds. |
pm_card_amex | American Express, credit | 0005 | The payment succeeds. |
Declines#
A decline answers 402 with error.type card_error. The PaymentIntent stays in requires_payment_method, so you can confirm it again with another payment method.
payment_method | Last 4 | error.code | error.decline_code |
|---|---|---|---|
pm_card_visa_chargeDeclined | 0002 | card_declined | generic_decline |
pm_card_visa_chargeDeclinedInsufficientFunds | 9995 | card_declined | insufficient_funds |
pm_card_chargeDeclinedExpiredCard | 0069 | expired_card | none |
pm_card_chargeDeclinedIncorrectCvc | 0127 | incorrect_cvc | none |
pm_card_chargeDeclinedProcessingError | 0119 | processing_error | none |
3D Secure#
These cards ask the buyer to authenticate. Confirm them with a return_url: the answer is 200 with status requires_action and a next_action of type redirect_to_url. In test mode, next_action.redirect_to_url.url opens a test page with two buttons, Complete and Fail, and then sends the buyer to your return_url with payment_intent, payment_intent_client_secret and redirect_status (succeeded or failed) in the query. Confirmed without a return_url, a PaymentIntent created with payment_method_types answers requires_action with a next_action of type use_fluveo_sdk that cannot be completed, and one created without payment_method_types is refused with 400 and nothing is charged; confirmed with error_on_requires_action=true, each one answers 402 card_error with error.code authentication_required.
payment_method | Last 4 | After Complete | After Fail |
|---|---|---|---|
pm_card_threeDSecure2Required | 3220 | succeeded | requires_payment_method, last_payment_error.code payment_intent_authentication_failure |
pm_card_authenticationRequired | 3184 | succeeded | requires_payment_method, last_payment_error.code payment_intent_authentication_failure |
pm_card_authenticationRequiredChargeDeclinedInsufficientFunds | 3178 | requires_payment_method, card_declined with insufficient_funds | requires_payment_method, last_payment_error.code payment_intent_authentication_failure |
pm_card_threeDSecureRequiredChargeDeclined | 1629 | requires_payment_method, card_declined with generic_decline | requires_payment_method, last_payment_error.code payment_intent_authentication_failure |
pm_card_threeDSecureRequiredProcessingError | 1280 | requires_payment_method, processing_error | requires_payment_method, last_payment_error.code payment_intent_authentication_failure |
Refunds and disputes#
payment_method | Last 4 | Outcome |
|---|---|---|
pm_card_refundFail | 5126 | The payment succeeds. A refund of it is created, then fails, and you get refund.failed. |
pm_card_createDispute | 0259 | The payment succeeds, and a dispute as fraudulent is already open when the payment answers. |
pm_card_createDisputeProductNotReceived | 2685 | The payment succeeds, and a dispute as product not received is already open when the payment answers. |
pm_card_createDisputeInquiry | 1976 | The payment succeeds, and an inquiry is already open when the payment answers. |
A refund is paid from your store's balance, funds still pending included. A card refund the balance does not cover is accepted with status pending and pending_reason insufficient_funds, and goes out once the balance covers it; a Pix refund the balance does not cover is refused with 400 balance_insufficient and refunds nothing. See Refund a payment.
A dispute arrives as a charge.dispute.created event. Treat the dispute id as opaque: store it as it comes and never parse it. See Handle disputes.
Names that are not test cards#
A test card name Fluveo does not know answers 404 resource_missing with param payment_method. Raw card numbers are refused: put the test name in payment_method, never a number in card[number]. A sk_live_ key never accepts a test name.
Type a card into the payment form#
On your own checkout and on the hosted checkout page, the buyer types the card into Fluveo's payment form. In test mode, type one of the numbers below with any future expiration date and any three-digit security code. Each number ends as the test card name beside it does. The numbers work only in the form: the API still refuses a card number in a request.
| Number | Same as | Outcome |
|---|---|---|
4242 4242 4242 4242 | pm_card_visa | The payment succeeds. |
5555 5555 5555 4444 | pm_card_mastercard | The payment succeeds. |
4000 0000 0000 0002 | pm_card_visa_chargeDeclined | Declined: card_declined with generic_decline. |
4000 0000 0000 9995 | pm_card_visa_chargeDeclinedInsufficientFunds | Declined: card_declined with insufficient_funds. |
4000 0000 0000 0127 | pm_card_chargeDeclinedIncorrectCvc | Declined: incorrect_cvc. |
4000 0000 0000 3220 | pm_card_threeDSecure2Required | Asks the buyer to authenticate, as under 3D Secure. |
4000 0027 6000 3184 | pm_card_authenticationRequired | Asks the buyer to authenticate, as under 3D Secure. |
Test Pix and Boleto#
| Method | What a test payment does |
|---|---|
| Pix | Creating a test Pix answers requires_action with a pix_display_qr_code you can show. Fluveo's test bank then pays it as a real payer would, by the payer email: a local part ending in succeed_immediately is paid within seconds, one ending in expire_immediately, expire_with_delay or fill_never is never paid and expires at its own expires_at, any other email is paid about 3 minutes after the confirm, and a Pix with no email is never paid on its own. The page at hosted_instructions_url links to a test page that pays it now. See Pix. |
| Boleto | Creating a test Boleto works the same way, with a boleto_display_details next action and the same payer emails; one that is never paid expires after its clearing period. The page at hosted_voucher_url links to a test page that pays it now. See Boleto. |
Payer values for tests: CPF 12345678909, email ada@example.com (paid about 3 minutes after the confirm; use succeed_immediately@example.com to be paid within seconds), phone +5511999999999.
Test it#
- Create a PaymentIntent with
payment_method_types[]=card,pm_card_visaandconfirm=true. You getstatussucceeded. - Do it again with
pm_card_visa_chargeDeclined. You get402,card_declinedandgeneric_decline. - Confirm the same PaymentIntent again with
pm_card_visa. It succeeds.