Riferimento API Pagamenti
Payments API Reference
Complete reference for the Payment Gateway REST API.
Base URL
https://api.sanpay.io/api/v1 Authentication
All API requests require authentication via Bearer token:
Authorization: Bearer YOUR_API_KEY Payments
Create Payment
POST /payments
Create a new payment request.
Request Body| Field | Type | Required | Description |
|---|---|---|---|
fiatAmount | number | ✅ | Importo in valuta fiat (es. 99.99) |
fiatCurrency | string | ✅ | Codice valuta fiat: USD, EUR, ecc. |
coinId | string (UUID) | ❌ | ID specifico della moneta. Se omesso con allowUserSelection: true, il cliente sceglie. |
chainId | string | ❌ | Identificatore blockchain (es. BTC, ETH) |
metadata | object | ❌ | Coppie chiave-valore personalizzate (ritornate nei webhook) |
externalId | string | ❌ | Il tuo ID ordine/riferimento interno |
callbackUrl | string | ❌ | URL per webhook e redirect dopo il pagamento |
ttlSeconds | integer | ❌ | Tempo di vita in secondi (default: 1800) |
allowUserSelection | boolean | ❌ | Permetti al cliente di scegliere la crypto (default: false) |
confirmations | integer | ❌ | Conferme blockchain richieste |
isTestnet | boolean | ❌ | Usa modalità testnet (default: false) |
idempotencyKey | string | ❌ | Chiave unica per prevenire pagamenti duplicati |
curl -X POST https://api.sanpay.io/api/v1/payments \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fiatAmount": 99.99,
"fiatCurrency": "USD",
"chainId": "BTC",
"externalId": "order_12345",
"callbackUrl": "https://example.com/webhook"
}' 201 Created {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "PENDING_ASSIGNMENT",
"requestedFiatAmount": 99.99,
"fiatCurrency": "USD",
"requestedCryptoAmount": "0.00250000",
"coinSymbol": "BTC",
"address": null,
"qrData": null,
"paymentUrl": "https://pay.sanpay.io/p/a1b2c3d4",
"fxRateUsed": "39996.00",
"fxLockedAt": "2024-01-15T11:00:00Z",
"fxLockedUntil": "2024-01-15T11:30:00Z",
"expiresAt": "2024-01-15T11:30:00Z",
"createdAt": "2024-01-15T11:00:00Z"
} Get Payment
GET /payments/{paymentId}
Retrieve a payment by ID.
Response200 OK {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "CONFIRMED",
"requestedFiatAmount": 99.99,
"fiatCurrency": "USD",
"requestedCryptoAmount": "0.00250000",
"coinSymbol": "BTC",
"address": "bc1qxy2kgdygjrsqvzq3rj...",
"txHash": "abc123def456...",
"confirmations": 6,
"confirmedAt": "2024-01-15T11:15:00Z",
"createdAt": "2024-01-15T11:00:00Z"
} Payment Statuses
| Status | Description |
|---|---|
PENDING_ASSIGNMENT | Pagamento creato, in attesa di assegnazione indirizzo |
PENDING_SELECTION | In attesa che il cliente selezioni la crypto (selezione differita) |
AWAITING_PAYMENT | Indirizzo assegnato, in attesa che il cliente invii i fondi |
DETECTED | Transazione vista nella mempool (0 conferme) |
PARTIALLY_PAID | Pagamento parziale ricevuto, in attesa del restante |
CONFIRMING | Transazione ricevuta, in attesa delle conferme richieste |
CONFIRMED | Pagamento confermato con le conferme blockchain richieste |
CONFIRMED_PARTIAL | Importo parziale confermato |
SETTLED | Pagamento completamente processato — stato finale di successo |
PARTIALLY_SETTLED | Importo parziale regolato |
EXPIRED | Finestra di pagamento scaduta senza pagamento |
EXPIRED_PARTIAL | Finestra di pagamento scaduta con pagamento parziale ricevuto |
CANCELLED | Pagamento annullato dal commerciante |
REFUND_PENDING_ADDRESS | Rimborso avviato, in attesa dell'indirizzo di rimborso del cliente |
REFUND_PROCESSING | Transazione di rimborso in elaborazione |
REFUNDED | Rimborso completato con successo |
REFUND_FAILED | Transazione di rimborso fallita |
REFUND_EXPIRED | Raccolta indirizzo di rimborso scaduta |
REORG_DETECTED | Riorganizzazione blockchain rilevata — pagamento in revisione |
List Payments
GET /payments
List all payments for your account.
Query Parameters| Field | Type | Description |
|---|---|---|
status | string | Filter by status |
externalId | string | Filter by order ID |
since | string | ISO 8601 timestamp |
until | string | ISO 8601 timestamp |
limit | integer | Max results (default: 20, max: 100) |
offset | integer | Pagination offset |
200 OK {
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "SETTLED",
"requestedFiatAmount": 99.99,
"fiatCurrency": "USD",
"requestedCryptoAmount": "0.00250000",
"coinSymbol": "BTC",
"createdAt": "2024-01-15T11:00:00Z"
}
],
"pagination": {
"total": 156,
"limit": 20,
"offset": 0
}
} Checkout Sessions
Create Checkout Session
POST /checkout/sessions
Create a hosted checkout session.
Request Body| Field | Type | Required | Description |
|---|---|---|---|
fiatAmount | number | ✅ | Importo in valuta fiat |
fiatCurrency | string | ✅ | Codice valuta fiat: USD, EUR, ecc. |
description | string | ❌ | Descrizione ordine |
externalId | string | ❌ | Il tuo ID ordine interno per correlazione |
successUrl | string | ✅ | URL di reindirizzamento in caso di successo |
cancelUrl | string | ✅ | URL di reindirizzamento in caso di annullamento |
customerEmail | string | ❌ | Pre-compilazione email cliente |
ttlSeconds | integer | ❌ | Tempo di vita in secondi (default: 1800) |
201 Created {
"id": "cs_xyz789",
"url": "https://checkout.sanpay.io/cs_xyz789",
"expiresAt": "2024-01-15T12:00:00Z"
} Refunds
Create Refund
POST /payments/{paymentId}/refunds
Record a refund for a payment.
Request Body| Field | Type | Required | Description |
|---|---|---|---|
amount | string | ✅ | Refund amount in crypto |
txHash | string | ❌ | Refund transaction hash |
reason | string | ❌ | Reason for refund |
201 Created {
"id": "ref_abc123",
"paymentId": "pay_abc123",
"amount": "0.00250000",
"currency": "BTC",
"txHash": "abc123...",
"status": "completed",
"createdAt": "2024-01-16T10:00:00Z"
} Webhooks
Payment events are delivered to your webhook URL:
| Event | Description |
|---|---|
PAYMENT_CREATED | Richiesta di pagamento creata |
PAYMENT_ADDRESS_ASSIGNED | Indirizzo crypto assegnato al pagamento |
PAYMENT_DETECTED | Transazione vista nella mempool |
PAYMENT_CONFIRMATION_UPDATE | Conteggio conferme aggiornato |
PAYMENT_CONFIRMED | Pagamento ha raggiunto le conferme richieste |
PAYMENT_SETTLED | Pagamento completamente regolato — evento finale di successo |
PAYMENT_EXPIRED | Finestra di pagamento scaduta |
PAYMENT_EXPIRED_PARTIAL | Pagamento scaduto con importo parziale ricevuto |
PAYMENT_CANCELLED | Pagamento annullato dal commerciante |
PAYMENT_REFUND_INITIATED | Processo di rimborso avviato |
PAYMENT_REFUND_COMPLETED | Rimborso completato con successo |
PAYMENT_REFUND_FAILED | Transazione di rimborso fallita |
PAYMENT_TX_UNMATCHED | Transazione ricevuta ma non corrispondente |
PAYMENT_REORG | Riorganizzazione blockchain rilevata |
PAYMENT_LATE_DETECTED | Pagamento rilevato dopo la scadenza |
Webhook Payload
{
"eventId": "evt-a1b2c3d4-e5f6",
"eventType": "PAYMENT_CONFIRMED",
"timestamp": "2024-01-15T11:15:00Z",
"tenantId": "your-tenant-id",
"paymentRequestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"address": "bc1qxy2kgdygjrsqvzq3rj...",
"coinSymbol": "BTC",
"chainId": "BTC",
"status": "CONFIRMED",
"confirmations": 6,
"requiredConfirmations": 3,
"requestedFiatAmount": 99.99,
"fiatCurrency": "USD",
"requestedCryptoAmount": "0.00250000"
} Error Responses
{
"error": {
"code": "PAYMENT_EXPIRED",
"message": "The payment request has expired",
"details": {
"paymentId": "pay_abc123",
"expiredAt": "2024-01-15T11:30:00Z"
}
}
} Payment Error Codes
| Code | Status | Description |
|---|---|---|
PAYMENT_NOT_FOUND | 404 | Payment does not exist |
PAYMENT_EXPIRED | 400 | Payment has expired |
INVALID_AMOUNT | 400 | Invalid amount format |
UNSUPPORTED_CURRENCY | 400 | Currency not supported |
RATE_LIMITED | 429 | Too many requests |
Annulla Pagamento
POST /payments/{paymentId}/cancel
Annulla una richiesta di pagamento. Solo i pagamenti con stato `AWAITING_PAYMENT` o `PENDING_SELECTION` possono essere annullati. I pagamenti con transazioni rilevate non possono essere annullati.
Response200 OK {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "CANCELLED",
"cancelledAt": "2026-01-15T11:20:00Z",
"reason": "Richiesta di annullamento dal cliente"
} Ottieni Sessione Checkout
GET /checkout/sessions/{sessionId}
Recupera una sessione checkout tramite ID.
Response200 OK {
"id": "cs_xyz789",
"status": "completed",
"paymentId": "pay_abc123",
"amount": "99.99",
"currency": "USD",
"successUrl": "https://example.com/success",
"cancelUrl": "https://example.com/cancel",
"expiresAt": "2024-01-15T12:00:00Z",
"createdAt": "2024-01-15T11:00:00Z"
} Scadenza Sessione Checkout
DELETE /checkout/sessions/{sessionId}
Fa scadere immediatamente una sessione checkout. La sessione non potrà più essere utilizzata per il pagamento.
Response200 OK {
"id": "cs_xyz789",
"status": "expired",
"expiredAt": "2024-01-15T11:30:00Z"
} Elenco Rimborsi
GET /payments/{paymentId}/refunds
Elenca tutti i rimborsi per uno specifico pagamento.
Response200 OK {
"data": [
{
"id": "ref_abc123",
"paymentId": "pay_abc123",
"amount": "0.00125000",
"currency": "BTC",
"status": "completed",
"reason": "Richiesta cliente",
"createdAt": "2024-01-16T10:00:00Z"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0
}
} Ottieni Rimborso
GET /refunds/{refundId}
Recupera un rimborso tramite ID.
Response200 OK {
"id": "ref_abc123",
"paymentId": "pay_abc123",
"amount": "0.00125000",
"currency": "BTC",
"txHash": "abc123def456...",
"status": "completed",
"reason": "Richiesta cliente",
"createdAt": "2024-01-16T10:00:00Z"
} Link di Pagamento
I link di pagamento sono URL riutilizzabili che permettono ai clienti di pagare qualsiasi importo. Ideali per donazioni, mance o fatture.
Crea Link di Pagamento
POST /payment-links
Crea un link di pagamento riutilizzabile.
Request Body| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
name | string | ✅ | Nome visualizzato per il link di pagamento |
amount | string | ❌ | Importo fisso (se omesso, il cliente inserisce l'importo) |
currency | string | ✅ | Codice valuta fiat: USD, EUR, ecc. |
description | string | ❌ | Descrizione mostrata al cliente |
redirectUrl | string | ❌ | URL di reindirizzamento dopo il pagamento |
metadata | object | ❌ | Coppie chiave-valore personalizzate |
201 Created {
"id": "plink_abc123",
"name": "Abbonamento Premium",
"url": "https://pay.sanpay.io/l/plink_abc123",
"amount": "99.99",
"currency": "USD",
"active": true,
"createdAt": "2024-01-15T11:00:00Z"
} Elenco Link di Pagamento
GET /payment-links
Elenca tutti i link di pagamento del tuo account.
Query Parameters| Campo | Tipo | Descrizione |
|---|---|---|
active | boolean | Filtra per stato attivo |
limit | integer | Max risultati (default: 20, max: 100) |
offset | integer | Offset paginazione |
200 OK {
"data": [
{
"id": "plink_abc123",
"name": "Abbonamento Premium",
"url": "https://pay.sanpay.io/l/plink_abc123",
"amount": "99.99",
"currency": "USD",
"active": true,
"paymentsCount": 42,
"totalCollected": "4199.58",
"createdAt": "2024-01-15T11:00:00Z"
}
],
"pagination": {
"total": 5,
"limit": 20,
"offset": 0
}
} Ottieni Link di Pagamento
GET /payment-links/{linkId}
Recupera un link di pagamento tramite ID.
Disattiva Link di Pagamento
DELETE /payment-links/{linkId}
Disattiva un link di pagamento. L'URL del link non accetterà più pagamenti.
Response200 OK {
"id": "plink_abc123",
"active": false,
"deactivatedAt": "2024-01-20T15:00:00Z"
} Tassi di Cambio
Ottieni tassi di cambio delle criptovalute in tempo reale.
Ottieni Tassi di Cambio
GET /exchange-rates
Recupera i tassi di cambio attuali per le criptovalute supportate.
Query Parameters| Campo | Tipo | Descrizione |
|---|---|---|
base | string | Valuta fiat base (default: USD) |
symbols | string | Simboli crypto separati da virgola (es. BTC,ETH) |
200 OK {
"base": "USD",
"timestamp": "2024-01-15T11:00:00Z",
"rates": {
"BTC": "0.000025",
"ETH": "0.00045",
"USDT": "1.0001",
"USDC": "0.9999"
}
} Account
Ottieni Saldo Account
GET /account/balance
Recupera i saldi attuali del tuo account per tutte le criptovalute.
Response200 OK {
"balances": [
{
"currency": "BTC",
"available": "1.25000000",
"pending": "0.05000000",
"total": "1.30000000"
},
{
"currency": "ETH",
"available": "15.50000000",
"pending": "0.00000000",
"total": "15.50000000"
}
],
"updatedAt": "2024-01-15T11:00:00Z"
} Rate Limiting
Le richieste API sono rate-limited per garantire un utilizzo equo. Le informazioni sui rate limit sono incluse negli header di risposta.
Header Rate Limit
| Header | Descrizione |
|---|---|
X-RateLimit-Limit | Richieste massime consentite per finestra |
X-RateLimit-Remaining | Richieste rimanenti nella finestra corrente |
X-RateLimit-Reset | Timestamp Unix di reset della finestra |
Rate Limit Predefiniti
| Endpoint | Limite | Finestra |
|---|---|---|
| POST /payments | 100 | 1 minuto |
| GET /payments | 300 | 1 minuto |
| POST /checkout/sessions | 100 | 1 minuto |
| GET /exchange-rates | 60 | 1 minuto |
Idempotenza
Usa chiavi di idempotenza per ripetere richieste in sicurezza senza rischiare operazioni duplicate.
Uso delle Chiavi di Idempotenza
Includi un campo `idempotencyKey` nel corpo della richiesta con un valore univoco (es. UUID) per le richieste POST:
curl -X POST https://api.sanpay.io/api/v1/payments \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"fiatAmount": 99.99, "fiatCurrency": "USD", "idempotencyKey": "550e8400-e29b-41d4-a716-446655440000"}' Comportamento Idempotenza
- Le chiavi sono valide per 24 ore dalla prima richiesta
- Richieste successive con la stessa chiave restituiscono la risposta originale
- Le chiavi sono associate alla tua API key
- Raccomandiamo l'uso di UUID v4 per le chiavi di idempotenza
Esempi SDK
Ecco esempi di creazione pagamento nei linguaggi di programmazione più popolari:
Node.js
const response = await fetch('https://api.sanpay.io/api/v1/payments', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SANPAY_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
fiatAmount: 99.99,
fiatCurrency: 'USD',
externalId: 'ORDER-12345',
description: 'Piano Premium'
})
});
const payment = await response.json(); Python
import requests
response = requests.post(
'https://api.sanpay.io/api/v1/payments',
headers={
'Authorization': f'Bearer {os.environ["SANPAY_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'fiatAmount': 99.99,
'fiatCurrency': 'USD',
'externalId': 'ORDER-12345',
'description': 'Piano Premium'
}
)
payment = response.json() PHP
$ch = curl_init('https://api.sanpay.io/api/v1/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SANPAY_API_KEY'),
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'fiatAmount' => 99.99,
'fiatCurrency' => 'USD',
'externalId' => 'ORDER-12345',
'description' => 'Piano Premium'
])
]);
$payment = json_decode(curl_exec($ch), true);