API reference
Forypay REST API
Plain JSON over HTTPS with bearer authentication. Two endpoints cover the whole payment lifecycle; a third verifies a single transaction you already have a hash for.
Authentication
Every request carries a project API key as a bearer token. Keys are created in the dashboard, on the project they belong to — see Projects — are shown once at creation, and are stored only as a hash — if you lose one, revoke it and issue another.
Authorization: Bearer fp_live_9f2c…Keys are secrets
Create a payment
POST/api/v1/payments
Registers the payment you expect to receive and starts chain monitoring. The response tells you when the window closes.
Try it| Field | Type | Description |
|---|---|---|
| required | Chain the payer will send on. | |
| required | Your receiving address. 0x… on BSC, T… on TRON. | |
| required | Decimal amount as a string, e.g. "25.00". Sent as a string to avoid float rounding. | |
| optional | Your own reference, up to 191 characters. Echoed back on every webhook. | |
| optional | Seconds until the payment window closes. Minimum 60. Omit for no expiry. | |
| optional | Restricts matching to transfers from this address. |
Pass an Idempotency-Key header to make retries safe: a repeat call with the same key returns the original payment instead of creating a second one.
curl -X POST https://your-host/api/v1/payments \
-H "Authorization: Bearer $FP_API_KEY" \
-H "Idempotency-Key: ORDER-1042" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ORDER-1042",
"network": "bsc",
"receiver": "0x2f1a…9c3e",
"amount": "25.00",
"expires_in": 1800
}'{
"id": "pay_8Fq2mZx1LrKd",
"order_id": "ORDER-1042",
"network": "bsc",
"token": "USDT",
"amount": "25.00",
"receiver": "0x2f1a…9c3e",
"status": "PENDING",
"expires_at": "2026-08-17T14:35:00.000Z"
}Retrieve a payment
GET/api/v1/payments/{id}
Returns the current state plus every matched transfer. Use this to reconcile, or as a fallback if your webhook endpoint was unreachable.
Try itcurl https://your-host/api/v1/payments/pay_8Fq2mZx1LrKd \
-H "Authorization: Bearer $FP_API_KEY"{
"id": "pay_8Fq2mZx1LrKd",
"order_id": "ORDER-1042",
"network": "bsc",
"token": "USDT",
"expected_amount": "25.00",
"detected_amount": "25.00",
"status": "CONFIRMED",
"transaction_hash": "0x9d4c…7b21",
"sender": null,
"receiver": "0x2f1a…9c3e",
"created_at": "2026-08-17T14:05:00.000Z",
"detected_at": "2026-08-17T14:05:12.000Z",
"confirmed_at": "2026-08-17T14:05:21.000Z",
"transfers": [ /* … */ ]
}List payments
GET/api/v1/payments
Returns recent payments, newest first, wrapped in a data array. Pass limit to change the page size — the default is 20 and the maximum is 100.
curl "https://your-host/api/v1/payments?limit=50" \
-H "Authorization: Bearer $FP_API_KEY"Verify a transaction
POST/api/v1/verify
A one-shot check for a hash you already have. This reads the chain directly and does not create or update a payment record — useful for manual reconciliation and for migrating historical orders.
Try it| Field | Type | Description |
|---|---|---|
| required | Chain to read. | |
| required | Hash of the transfer to inspect. | |
| required | Address the transfer must have credited. |
curl -X POST https://your-host/api/v1/verify \
-H "Authorization: Bearer $FP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"network": "bsc",
"transaction_hash": "0x9d4c…7b21",
"receiver": "0x2f1a…9c3e"
}'{
"valid": true,
"status": "CONFIRMED",
"network": "bsc",
"transaction_hash": "0x9d4c…7b21",
"sender": "0x8f2a…1b4e",
"receiver": "0x2f1a…9c3e",
"amount": "25.00"
}Payment statuses
A payment starts at PENDING and moves forward only. These are the states you will see in webhooks, API responses and the dashboard.
| Status | Meaning |
|---|---|
| Pending | Created and waiting for a matching transfer on chain. |
| Detected | A matching transfer was found; the payment settles immediately. |
| Confirmed | Settled. Safe to fulfil the order. |
| Overpaid | Settled, but the payer sent more than the expected amount. |
| Expired | The window closed before a matching transfer arrived. |
Webhooks
Set a webhook URL on the project and we POST JSON as the payment progresses. Events are queued and retried with exponential backoff until your endpoint returns a 2xx, so treat handlers as idempotent — the same event may arrive twice.
payment.detected— a matching transfer appeared on chain and was settledpayment.confirmed— the payment moved to its final settled statepayment.expired— the window closed unpaid
Each delivery carries an HMAC-SHA256 signature derived from the project webhook secret, computed over the timestamp header and the raw request body joined by a dot. Compare it with a constant-time comparison before trusting the payload, refuse anything older than five minutes, and rotate the secret from project settings if it is ever exposed.
POST /your/webhook
Content-Type: application/json
X-Forypay-Event: payment.confirmed
X-Forypay-Delivery: whk_3Kd9vQ2mTz
X-Forypay-Timestamp: 1755820800
X-Forypay-Signature: sha256=6f1b…a92c
{
"event": "payment.confirmed",
"data": {
"payment_id": "pay_8Fq2mZx1LrKd",
"order_id": "ORDER-1042",
"status": "CONFIRMED",
"transaction_hash": "0x9d4c…7b21"
}
}Errors
Errors use conventional HTTP status codes and a consistent body. The request_id is worth logging — quote it when asking for help and we can find the exact request.
{
"error": {
"code": "INVALID_AMOUNT",
"message": "Invalid amount",
"request_id": "req_7bQ1xKp0Za"
}
}| Code | HTTP | Cause |
|---|---|---|
| 400 | Body failed schema validation. The message names the field. | |
| 400 | Amount was not a plain decimal string. | |
| 400 | Token is not enabled for that network. | |
| 401 | Missing, malformed, revoked or unknown bearer token. | |
| 404 | No payment with that id. | |
| 500 | Token metadata is incomplete on our side. | |
| 500 | The chain read failed — retry, then contact us. |
Try it without writing code
The playground sends a real request to any documented endpoint with a key you paste in, and shows the raw response.
Open API playground