API and Authentication
Manatee is a server-side, on-chain payment API. Keep API keys on your backend and never expose them in browser code, mobile apps, or public repositories.
API keys
Each API key is scoped to an environment and shared by the assets enabled in that environment:
| Key type | Network | Use for |
|---|---|---|
| Test key | testnet | BTC Testnet4, BCH Testnet4, and XMR Stagenet integration tests |
| Mainnet key | mainnet | BTC, BCH, and XMR payments using real funds |
Receive-wallet configuration remains asset-specific. The same Test API key can use a BTC descriptor, a BCH account tpub, and an XMR Stagenet view-only wallet, while each payment route enforces its asset and mapped network. Use test networks until the full payment and webhook flow works.
Asset routes
| Asset | Base route | Availability |
|---|---|---|
| Bitcoin | /v1/btc/payments | Testnet and mainnet |
| Bitcoin Cash | /v1/bch/payments | Testnet and mainnet |
| Monero | /v1/xmr/payments | Stagenet and mainnet |
Each base route supports create, list, retrieve, cancel, and webhook-event operations. Responses contain explicit asset and network fields. XMR uses decimal-string amount_atomic values in piconero and never accepts a manual destination address. See the BTC, BCH, and XMR quickstarts or the generated API Reference.
Authentication
Send the API key as a bearer token:
Authorization: Bearer $MANATEE_API_KEY
Most API calls also require JSON:
Content-Type: application/json
For payment creation, send an Idempotency-Key so retries do not create duplicate payment instructions for the same order:
Idempotency-Key: order-10042-create-payment
Read more in Idempotency Keys.
Create a payment
The following example uses the Bitcoin route. Send exactly one amount mode: either amount_sats, or fiat_amount with fiat_currency. BCH uses the same satoshi fields on its own route; XMR uses amount_atomic as a decimal string.
curl -sS -X POST "$MANATEE_API_URL/v1/btc/payments" \
-H "Authorization: Bearer $MANATEE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-10042-create-payment" \
-d '{
"amount_sats": 10000,
"webhook_url": "https://yourapp.example/webhooks/btc",
"required_confirmations": 1,
"expires_in": 3600,
"reference": "order-10042"
}'
For fiat-priced orders, let Manatee create the fixed satoshi quote for the payment. Pricing is handled server-side by the configured provider chain; API clients and shop plugins do not send provider credentials.
curl -sS -X POST "$MANATEE_API_URL/v1/btc/payments" \
-H "Authorization: Bearer $MANATEE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-10042-create-payment" \
-d '{
"fiat_amount": "51.00",
"fiat_currency": "EUR",
"webhook_url": "https://yourapp.example/webhooks/btc",
"required_confirmations": 1,
"expires_in": 3600,
"reference": "order-10042"
}'
Example response:
{
"id": "pay_abc123",
"address": "tb1q...",
"amount_sats": 85000,
"fiat_amount": "51.00",
"fiat_currency": "EUR",
"exchange_rate": "60000",
"exchange_rate_timestamp": "2026-05-07T10:00:00Z",
"pricing_source": "coinbase",
"status": "pending",
"confirmations": 0,
"required_confirmations": 1,
"asset": "btc",
"network": "testnet",
"webhook_url": "https://yourapp.example/webhooks/btc",
"reference": "order-10042",
"created_at": "2026-05-07T10:00:00Z",
"expires_at": "2026-05-07T11:00:00Z"
}
Show the returned address, amount_sats, and expiry time in your checkout. Store the returned payment id next to your own order ID. If you created the payment from fiat, store the returned quote metadata for reconciliation.
The returned amount_sats is fixed for this payment. Use expires_in to limit how long the checkout quote is valid. Manatee may cache exchange rates briefly on the server side, but the customer-facing quote is bounded by the payment's expires_at.
Retrieve a payment
Fetch the payment by ID:
curl -sS "$MANATEE_API_URL/v1/btc/payments/pay_abc123" \
-H "Authorization: Bearer $MANATEE_API_KEY"
Use retrieval for reconciliation, support views, or fallback polling. For normal order updates, use signed webhooks.
Invalid API key
If a request returns unauthorized:
- Confirm that the
Authorizationheader usesBearer. - Use the key for the same network as the payment you want to create.
- Make sure the key was not rotated or revoked.
- Keep dashboard login separate from API keys; dashboard credentials are not API credentials.
For all endpoints and response schemas, see the generated API Reference.