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.
Get a test secret key#
In the Fluveo Dashboard, 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.
Check that the key works#
Read your account. The answer's
idis your store's id, which starts withmch_. Every object you create belongs to that store.Read your accountcurl https://api.fluveo.com/v1/account \ -H "Authorization: Bearer sk_test_..."const response = await fetch("https://api.fluveo.com/v1/account", { headers: { Authorization: "Bearer sk_test_..." }, }); console.log(await response.json());import requests response = requests.get( "https://api.fluveo.com/v1/account", headers={"Authorization": "Bearer sk_test_..."}, ) print(response.json())<?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
401means the key is missing or wrong. See Authentication.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
2000is $20.00.pm_card_visais a test card that the bank always approves.Pay $20.00 with a test cardcurl 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=trueconst 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);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 $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, andlatest_chargenames the Charge it made (ch_...). That is your first test payment.Response (shortened){ "id": "pi_...", "object": "payment_intent", "amount": 2000, "currency": "usd", "status": "succeeded", "latest_charge": "ch_...", "livemode": false }Ask for a Pix#
The same call takes a Pix. Name the method in
payment_method_data[type]and the payer inpayment_method_data[billing_details]: name, email, phone and CPF.1000is R$ 10,00, and12345678909is a CPF for tests. The currency each method charges in is on Payments.Create a R$ 10,00 Pix chargecurl 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"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);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 $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_codecarries what you put on screen.datais the code the buyer pastes in their bank app,image_url_pngandimage_url_svgdraw it as a QR code, andexpires_atis the moment it stops working.Response (shortened){ "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 }See what happened#
The payment you just made created an event. List the newest ones.
List recent eventscurl -G https://api.fluveo.com/v1/events \ -H "Authorization: Bearer sk_test_..." \ -d limit=3const 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);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 $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.succeededfor a card you just paid, orpayment_intent.createdfor a Pix that waits for the buyer. In production you get the same events pushed to your server as webhooks.
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. - Swap
pm_card_visaforpm_card_visa_chargeDeclined. The request answers402with acard_error. See Testing for every test value.