Flynet Payment Intents let approved partners accept payments
from Blackbird members in FLY, on behalf of third-party merchants.
The model is closely analogous to Stripe Payment Intents: you
create an intent, the member confirms it, and FLY transfers from
the member’s wallet to the merchant.
The merchant ID is your third credential
Every POST /payment_intents requires a flynet_merchant_id, a UUID identifying the merchant receiving funds. You receive it in your onboarding email if you applied for payments access. It’s scoped to your client_id and your environment; staging and production merchant IDs differ.
If flynet_merchant_id is missing, wrong, or scoped to a different partner, create returns:
{
"error": {
"type": "invalid_request_error",
"code": "resource_not_found",
"message": "Flynet merchant not found.",
"param": null
}
}
The merchant ID is not a secret on its own (it’s an addressing field), but it’s how the API knows which payee to route to. Store it alongside client_id and API_KEY in your env config; don’t hard-code it.
The primitive
A PaymentIntent moves FLY from a member’s wallet to a
merchant’s wallet. Each intent has:
- A
flynet_merchant_id - the merchant receiving the payment
- A
customer_user_id - the Blackbird member paying
- An
amount in FLY
- A
status that derives from event timestamps
Status lifecycle
confirm
pending -----------------------> paid
| |
| cancel | refund
v v
canceled refunded
(expires_at elapses before confirm -> expired)
| Status | When |
|---|
pending | Intent created, not yet confirmed |
paid | Confirmed; FLY has transferred |
canceled | Canceled before confirm |
refunded | Paid then refunded; FLY returned to member |
expired | expires_at elapsed without confirm |
Tasting note - status is computed at read time from the
timestamps on the intent. You do not transition states directly;
you call cancel, confirm, or refund and the status follows.
v1 capabilities
| Capability | v1 status |
|---|
| FLY-to-FLY transfers | Live |
| Idempotent create | Live |
| Cancel pending intents | Live |
| Refund paid intents, full only | Live |
| Receipt emails on confirm | Live |
| Card-funded payments | Coming soon |
| Partial refunds | Coming soon |
| Webhook delivery | Coming soon; poll status for v1 |
| Hosted checkout page | Coming soon |
Chef’s warning - v1 is FLY-only. If the member does not already
hold enough FLY, confirm returns 400 payment0030. You cannot
card-fund or auto-load FLY in v1.
Idempotency
Network calls fail. Retries are normal. Without idempotency, retries on POST /payment_intents could create duplicate charges. Flynet uses idempotency keys to make retries safe.
Every Payment Intent create requires an idempotency_key in the request body. The key is unique per (flynet_merchant_id, idempotency_key).
| Scenario | Response |
|---|
First create with key X | 201 Created, new intent |
Replay with same key X | 200 OK, same intent returned |
New create with key Y | 201 Created, new intent |
async function createPaymentIntent(orderId) {
const response = await fetch(`${API_BASE_URL}/payment_intents`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${ACCESS_TOKEN}`,
},
body: JSON.stringify({
flynet_merchant_id: process.env.MERCHANT_ID,
customer_user_id: userId,
amount: { value: "1000000000000000000", currency: "FLY" },
idempotency_key: orderId,
description: `Order ${orderId}`,
}),
});
return response.json();
}
From the kitchen - Use your own order ID as the idempotency key. Network retries on the same order naturally return the same Payment Intent without creating a duplicate.
Idempotency on confirm, cancel, and refund is state-based: re-confirming a paid intent or re-canceling a canceled intent returns the same intent without side effects. No separate key needed.
Money
All amounts use the Money wire shape:
{ value, currency } with value as a stringified integer in FLY wei.
Receipts
On successful confirm, the customer receives a receipt email from
flynet@blackbird.xyz.
Auth
All Payment Intent routes require an OAuth access token. API keys
are not accepted on payment routes.
Endpoints at a glance
| Method | Path | Purpose |
|---|
| POST | /payment_intents | Create |
| GET | /payment_intents/{id} | Retrieve |
| GET | /payment_intents | List |
| POST | /payment_intents/{id}/cancel | Cancel pending |
| POST | /payment_intents/{id}/confirm | Confirm and transfer FLY |
| POST | /payment_intents/{id}/refund | Refund a paid intent |
See the API Reference and the
first payment recipe.
What’s coming
Card-funded confirm, partner webhooks, partial refunds, and a hosted
checkout surface are on the roadmap.