---
title: "Quickstart"
description: "Go from a test secret key to your first successful test payment in a few minutes, with plain HTTP."
url: https://docs.fluveo.com/start/
---

> 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.curl.md (cURL), https://docs.fluveo.com/start.node.md (Node.js), https://docs.fluveo.com/start.python.md (Python), https://docs.fluveo.com/start.php.md (PHP).

# Quickstart

Go from a test secret key to your first successful test payment in a few minutes, with plain HTTP.

You make one test payment with Fluveo's `/v1` API. You need a terminal with `curl` (or Node.js, Python or PHP) and a Fluveo account. Nothing on this page moves real money: every call uses a test key.

### Step 1: Get a test secret key

In the [Fluveo Dashboard](https://dash.fluveo.com), open **Settings** in the sidebar. In the **API keys** section, click **Secret key**. The bottom of the sidebar shows **Test mode**, so the key is a test key and starts with `sk_test_`. The Dashboard shows the full key once, so copy it to a safe place.

Keep the key on your server. Never put it in a browser, a mobile app or a commit.

### Step 2: Check that the key works

Read your account. The answer's `id` is your store's id, which starts with `mch_`. Every object you create belongs to that store.

**Read your account**

cURL:

```bash
curl https://api.fluveo.com/v1/account \
  -H "Authorization: Bearer sk_test_..."
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/account", {
  headers: { Authorization: "Bearer sk_test_..." },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/account",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/account");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_..."],
]);
echo curl_exec($ch);
```

A `401` means the key is missing or wrong. See [Authentication](https://docs.fluveo.com/start/authentication.md).

### Step 3: Pay with a test card

Create a PaymentIntent and confirm it in one request. An amount is a whole number in the currency's smallest unit, so `2000` is $20.00. `pm_card_visa` is a test card that the bank always approves.

**Pay $20.00 with a test card**

cURL:

```bash
curl https://api.fluveo.com/v1/payment_intents \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: quickstart-order-1001" \
  -d amount=2000 \
  -d currency=usd \
  -d "payment_method_types[]=card" \
  -d payment_method=pm_card_visa \
  -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": "quickstart-order-1001",
  },
  body: new URLSearchParams({
    amount: "2000",
    currency: "usd",
    "payment_method_types[]": "card",
    payment_method: "pm_card_visa",
    confirm: "true",
  }),
});
const paymentIntent = await response.json();
console.log(paymentIntent.id, paymentIntent.status);
```

Python:

```python
import requests

response = requests.post(
    "https://api.fluveo.com/v1/payment_intents",
    headers={
        "Authorization": "Bearer sk_test_...",
        "Idempotency-Key": "quickstart-order-1001",
    },
    data={
        "amount": 2000,
        "currency": "usd",
        "payment_method_types[]": "card",
        "payment_method": "pm_card_visa",
        "confirm": "true",
    },
)
payment_intent = response.json()
print(payment_intent["id"], payment_intent["status"])
```

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: quickstart-order-1001",
    ],
    CURLOPT_POSTFIELDS => http_build_query([
        "amount" => 2000,
        "currency" => "usd",
        "payment_method_types" => ["card"],
        "payment_method" => "pm_card_visa",
        "confirm" => "true",
    ]),
]);
$paymentIntent = json_decode(curl_exec($ch), true);
echo $paymentIntent["id"] . " " . $paymentIntent["status"];
```

The PaymentIntent comes back `succeeded`, and `latest_charge` names the Charge it made (`ch_...`). That is your first test payment.

*Response (shortened)*

```json
{
  "id": "pi_...",
  "object": "payment_intent",
  "amount": 2000,
  "currency": "usd",
  "status": "succeeded",
  "latest_charge": "ch_...",
  "livemode": false
}
```

### Step 4: Ask for a Pix

The same call takes a Pix. Name the method in `payment_method_data[type]` and the payer in `payment_method_data[billing_details]`: name, email, phone and CPF. `1000` is R$ 10,00, and `12345678909` is a CPF for tests. The currency each method charges in is on [Payments](https://docs.fluveo.com/payments.md#payment-methods).

**Create a R$ 10,00 Pix charge**

cURL:

```bash
curl https://api.fluveo.com/v1/payment_intents \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: quickstart-pedido-1001" \
  -d amount=1000 \
  -d currency=brl \
  -d "payment_method_types[]=pix" \
  -d confirm=true \
  -d "payment_method_data[type]=pix" \
  --data-urlencode "payment_method_data[billing_details][name]=Ada Lovelace" \
  -d "payment_method_data[billing_details][email]=ada@example.com" \
  --data-urlencode "payment_method_data[billing_details][phone]=+5511999999999" \
  -d "payment_method_data[billing_details][tax_id]=12345678909"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/payment_intents", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_test_...",
    "Idempotency-Key": "quickstart-pedido-1001",
  },
  body: new URLSearchParams({
    amount: "1000",
    currency: "brl",
    "payment_method_types[]": "pix",
    confirm: "true",
    "payment_method_data[type]": "pix",
    "payment_method_data[billing_details][name]": "Ada Lovelace",
    "payment_method_data[billing_details][email]": "ada@example.com",
    "payment_method_data[billing_details][phone]": "+5511999999999",
    "payment_method_data[billing_details][tax_id]": "12345678909",
  }),
});
const paymentIntent = await response.json();
console.log(paymentIntent.status, paymentIntent.next_action.pix_display_qr_code.data);
```

Python:

```python
import requests

response = requests.post(
    "https://api.fluveo.com/v1/payment_intents",
    headers={
        "Authorization": "Bearer sk_test_...",
        "Idempotency-Key": "quickstart-pedido-1001",
    },
    data={
        "amount": 1000,
        "currency": "brl",
        "payment_method_types[]": "pix",
        "confirm": "true",
        "payment_method_data[type]": "pix",
        "payment_method_data[billing_details][name]": "Ada Lovelace",
        "payment_method_data[billing_details][email]": "ada@example.com",
        "payment_method_data[billing_details][phone]": "+5511999999999",
        "payment_method_data[billing_details][tax_id]": "12345678909",
    },
)
payment_intent = response.json()
print(payment_intent["status"], payment_intent["next_action"]["pix_display_qr_code"]["data"])
```

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: quickstart-pedido-1001",
    ],
    CURLOPT_POSTFIELDS => http_build_query([
        "amount" => 1000,
        "currency" => "brl",
        "payment_method_types" => ["pix"],
        "confirm" => "true",
        "payment_method_data" => [
            "type" => "pix",
            "billing_details" => [
                "name" => "Ada Lovelace",
                "email" => "ada@example.com",
                "phone" => "+5511999999999",
                "tax_id" => "12345678909",
            ],
        ],
    ]),
]);
$paymentIntent = json_decode(curl_exec($ch), true);
echo $paymentIntent["status"] . "\n" . $paymentIntent["next_action"]["pix_display_qr_code"]["data"];
```

This time the status is `requires_action`: the buyer still has to pay. `next_action.pix_display_qr_code` carries what you put on screen. `data` is the code the buyer pastes in their bank app, `image_url_png` and `image_url_svg` draw it as a QR code, and `expires_at` is the moment it stops working.

*Response (shortened)*

```json
{
  "id": "pi_...",
  "object": "payment_intent",
  "amount": 1000,
  "currency": "brl",
  "status": "requires_action",
  "next_action": {
    "type": "pix_display_qr_code",
    "pix_display_qr_code": {
      "data": "00020101...",
      "expires_at": 1767225600,
      "hosted_instructions_url": "https://...",
      "image_url_png": "https://...",
      "image_url_svg": "https://..."
    }
  },
  "livemode": false
}
```

> **A test Pix is paid by its payer email:** When the buyer pays, the PaymentIntent moves to `succeeded` and you get a `payment_intent.succeeded` event. In test mode Fluveo's test bank pays it for you: send the payer email `succeed_immediately@example.com` to be paid within seconds; an email whose part before the `@` ends in `expire_immediately`, `expire_with_delay` or `fill_never` is never paid, any other email is paid about 3 minutes after the confirm, and a Pix with no email is never paid. See [Testing](https://docs.fluveo.com/start/testing.md#pix-and-boleto).

### Step 5: See what happened

The payment you just made created an event. List the newest ones.

**List recent events**

cURL:

```bash
curl -G https://api.fluveo.com/v1/events \
  -H "Authorization: Bearer sk_test_..." \
  -d limit=3
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/events?limit=3", {
  headers: { Authorization: "Bearer sk_test_..." },
});
const events = await response.json();
for (const event of events.data) console.log(event.type, event.data.object.id);
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/events",
    headers={"Authorization": "Bearer sk_test_..."},
    params={"limit": 3},
)
for event in response.json()["data"]:
    print(event["type"], event["data"]["object"]["id"])
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/events?limit=3");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_..."],
]);
foreach (json_decode(curl_exec($ch), true)["data"] as $event) {
    echo $event["type"] . " " . $event["data"]["object"]["id"] . "\n";
}
```

You see `payment_intent.succeeded` for a card you just paid, or `payment_intent.created` for a Pix that waits for the buyer. In production you get the same events pushed to your server as [webhooks](https://docs.fluveo.com/webhooks.md).

## Test it

- Send the same request again with the same `Idempotency-Key`. You get the same PaymentIntent back, and nothing is charged twice. See [Idempotency](https://docs.fluveo.com/start/idempotency.md).
- Swap `pm_card_visa` for `pm_card_visa_chargeDeclined`. The request answers `402` with a `card_error`. See [Testing](https://docs.fluveo.com/start/testing.md) for every test value.

> **For AI agents:**
>
> Use plain HTTP with form-encoded bodies (application/x-www-form-urlencoded). Install no server SDK. Authenticate with Authorization: Bearer and a sk_test_ key; never send a header that acts for another account. Send an Idempotency-Key on every POST and reuse it on a retry of the same request. Every store makes the same calls. In test mode a Pix or Boleto whose payer email ends in succeed_immediately before the @ is paid within seconds, one ending in expire_immediately, expire_with_delay or fill_never is never paid, and any other email about 3 minutes after the confirm; do not look for a test_helpers route.

## Next

- [Authentication](https://docs.fluveo.com/start/authentication.md): Test keys, the Authorization header and the errors a bad key gets.
- [Testing](https://docs.fluveo.com/start/testing.md): Test cards and what each one does, and what you can test with Pix and Boleto.
- [Accept a payment](https://docs.fluveo.com/payments/accept-a-payment.md): Card, Pix and Boleto in one call; capture and declines.
- [Pix](https://docs.fluveo.com/payments/pix.md): Show the code, wait for payment and fulfil the order.
- [Receive webhooks](https://docs.fluveo.com/webhooks.md): Get events on your server and check their Fluveo-Signature.
