A platform, in Fluveo's words, is a checkout: the software where a buyer fills the cart and pays. The platform does not own the payments. It only sends each payment to Fluveo on behalf of the merchant who runs the store.
One merchant, one Fluveo account, one key#
Every merchant opens its own Fluveo account. The account has an id that starts with mch_, and the merchant creates its own secret keys in the Fluveo Dashboard, under Settings, API keys. Then the merchant pastes its secret key into the platform's settings.
- The platform keeps one Fluveo key per merchant, and calls
/v1with that merchant's key for that merchant's payments. - The platform never holds a Fluveo key of its own that reaches every store. There is no such key.
- There is no header that acts for another account. A request that sends one gets a
400error that names the header. - Fields that route money to someone else are refused by name with a
400:transfer_data,on_behalf_of,application_fee_amount,transfer_groupand the like. A platform cannot take a fee or split a payment through the API.
Money and events stay with the merchant#
Because every call carries the merchant's own key, everything it creates belongs to that merchant:
- PaymentIntents, Checkout Sessions, refunds and disputes live in the merchant's account and are read with the merchant's key.
GET /v1/balanceand payouts show the merchant's own money.- Webhook endpoints are created with the merchant's key, so each endpoint gets only that merchant's events, signed with that endpoint's own
whsec_secret.
curl 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_..." },
});
const account = await response.json();
console.log(account.id, account.country, account.default_currency);import requests
response = requests.get(
"https://api.fluveo.com/v1/account",
headers={"Authorization": "Bearer sk_test_..."},
)
account = response.json()
print(account["id"], account["country"], account["default_currency"])<?php
$ch = curl_init("https://api.fluveo.com/v1/account");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_..."],
]);
$account = json_decode(curl_exec($ch), true);
echo $account["id"], " ", $account["country"], " ", $account["default_currency"];The answer's id is the merchant's mch_ id, country is US or BR, and default_currency is that account's currency. A platform can make this call right after the merchant pastes the key, to show which Fluveo account it is connected to.
Build a platform integration#
If you build a checkout that many merchants use, follow these rules.
Ask each merchant for its own secret key#
Show a field where the merchant pastes its Fluveo secret key. Store it encrypted on your server, next to that merchant's store. Never send it to the browser and never write it to a log.
Check the key once#
Call
GET /v1/accountwith the key. A401means the key is wrong. Keep themch_id it returns, so you can show the merchant which account is connected.Send every request with that merchant's key#
Use plain HTTP with
Authorization: Bearer <the merchant's key>. Install no server SDK and send no header that acts for another account. Send anIdempotency-Keyon every POST and reuse it when you retry the same request.Receive that merchant's events#
Create a webhook endpoint with the merchant's key, keep its
whsec_secret beside that merchant, and check theFluveo-Signatureheader of each event with that secret.
When a merchant changes its key#
In the Dashboard, a merchant can rotate a key and choose when the old key expires: now, or in 1 hour, 24 hours, 3 days or 7 days. Both keys work until then, so the merchant can paste the new key into the platform before the old one stops. After the expiration, or at once with Now or Expire key, the platform's calls with the old key answer 401 with code api_key_expired until the new key is pasted. A merchant linked to several platform accounts keeps one named key for each; rotating or expiring one never stops the others.
Test it#
- Paste a
sk_test_...key and callGET /v1/account: you get themch_id of that test account. - Send a
sk_live_...key: you get a403. Fluveo serves test mode only for now.
Platforms#
Next#
- Authentication: keys, the Bearer header and the errors a wrong key gets.
- Idempotency: how to retry a POST safely.
- Webhooks and checking signatures.
- The Account object in the API reference.