---
title: "Testing"
description: "What test mode does, how each test card ends, and what a test Pix or Boleto does."
url: https://docs.fluveo.com/start/testing/
---

> Index of every page: https://docs.fluveo.com/llms.txt. Integrating Fluveo? Read https://docs.fluveo.com/agents/integrate.md first.

> Too long? This page with code in one language only: https://docs.fluveo.com/start/testing.curl.md (cURL), https://docs.fluveo.com/start/testing.node.md (Node.js), https://docs.fluveo.com/start/testing.python.md (Python), https://docs.fluveo.com/start/testing.php.md (PHP).

# Testing

What test mode does, how each test card ends, and what a test Pix or Boleto does.

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](https://docs.fluveo.com/start/authentication.md).

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.

**Pay with a test card**

cURL:

```bash
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=true
```

Node.js:

```javascript
const 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);
```

Python:

```python
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:

```php
<?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](https://docs.fluveo.com/payments/refunds.md#balance-too-low).

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](https://docs.fluveo.com/payments/disputes.md).

### 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](https://docs.fluveo.com/payments/custom-checkout.md) and on the [hosted checkout](https://docs.fluveo.com/payments/checkout.md) 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](https://docs.fluveo.com/start/testing.md#3d-secure). |
| `4000 0027 6000 3184` | `pm_card_authenticationRequired` | Asks the buyer to authenticate, as under [3D Secure](https://docs.fluveo.com/start/testing.md#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](https://docs.fluveo.com/payments/pix.md#test-it). |
| 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](https://docs.fluveo.com/payments/boleto.md#test-it). |

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

1. Create a PaymentIntent with `payment_method_types[]=card`, `pm_card_visa` and `confirm=true`. You get `status` `succeeded`.
2. Do it again with `pm_card_visa_chargeDeclined`. You get `402`, `card_declined` and `generic_decline`.
3. Confirm the same PaymentIntent again with `pm_card_visa`. It succeeds.

> **For AI agents:**
>
> Use the pm_card_* names on this page as test values in API calls. In Fluveo's payment form, on your own checkout or on the hosted checkout page, type a number of the "Type a card into the payment form" table; never send one to the API. A 3D Secure test card needs return_url on the confirm, then the buyer presses Complete or Fail on the test page; read the PaymentIntent afterwards, never trust the redirect alone. Never send a raw card number; never invent a test_helpers route. In test mode a Pix or Boleto is paid by the payer email: a local part ending in succeed_immediately within seconds, any other email about 3 minutes after the confirm, and one ending in expire_immediately, expire_with_delay or fill_never never; a Pix with no email is never paid. Wait for payment_intent.succeeded; never call a /__mock/ path. A card refund the store's balance does not cover yet answers 200 with status pending and pending_reason insufficient_funds, and goes out once the balance covers it: that is expected, so wait for refund.updated and never refund it again. A Pix refund the balance does not cover answers 400 balance_insufficient and refunds nothing; never retry it in a loop with new Idempotency-Keys.

## Next

- [Idempotency](https://docs.fluveo.com/start/idempotency.md): Retry a payment without charging twice.
- [Accept a payment](https://docs.fluveo.com/payments/accept-a-payment.md): The full flow for card, Pix and Boleto, with capture.
- [Receive webhooks](https://docs.fluveo.com/webhooks.md): Get the events these tests produce on your server.
