Riferimento della Merchant API
Le convenzioni comuni a tutti i metodi, più i metodi di sola lettura del catalogo. Le pagine metodo per metodo: fatture e rimborsi, trasferimenti e buoni, abbonamenti, webhook.
Per i metodi documentati qui, l’API segue le convenzioni di Crypto Bot. Cambia l’URL di base e il token, poi prova sulla testnet i metodi usati dall’integrazione. Le funzionalità aggiuntive sono indicate come estensione.
È disponibile anche una specifica OpenAPI 3.1 utilizzabile dagli strumenti di sviluppo: crypto-pay-openapi.yaml · crypto-pay-openapi.json. Passala a un generatore di codice, a un client API o ai tuoi strumenti di AI, ma consulta anche le pagine dei singoli metodi: lo schema potrebbe non includere ancora le estensioni più recenti.
Base URL e autenticazione
Tutti i metodi stanno su https://app.tgpaycrypto.com/pay/api/<methodName>.
Sulla testnet la base è
https://testnet.tgpaycrypto.com/pay/api: app e token separati e fondi di prova senza
valore reale.
Autentica ogni richiesta con il token nell’intestazione
TgPayCrypto-API-Token (TgCryptoPay-API-Token, il nome in uso prima del
2026-09-07, e Crypto-Pay-API-Token sono accettate come alias di
compatibilità; se ne mandi più di una, vince quella ufficiale). Un token mancante,
non valido o revocato, un token limitato scaduto, il token di un’app eliminata
o quello il cui proprietario è bloccato restituiscono
401 unauthorized.
Il token ha la forma <app_id>:<secret> e si vede una volta sola, alla
creazione o alla rigenerazione; il server ne conserva solo l’hash. Vedi
iniziare da sviluppatore.
Token e ambiti
Ci sono due tipi di credenziali, che si autenticano allo stesso modo:
- Il token principale — accesso completo a ogni metodo, ed è l’unica chiave che firma i webhook.
- I token con permessi limitati (estensione) — fino a 10 non revocati per app, compresi quelli scaduti. Apri Altro → Merchant API, scegli l’app e poi Accesso e token. Creali sotto Token con permessi limitati, ciascuno con un’etichetta e un sottoinsieme di ambiti. Revocarne uno è immediato e non tocca gli altri; nemmeno rigenerare il token principale li tocca. Un token può anche avere una scadenza: dopo quel termine non consente più di autenticarsi.
| Ambito | Metodi che sblocca |
|---|---|
| (qualsiasi token valido) | getMe, getCurrencies, getExchangeRates |
read | getBalance, getStats, getInvoices, getChecks, getTransfers, getSubscriptionPlans, getSubscriptions |
invoices | createInvoice, deleteInvoice |
refunds | refundInvoice |
payouts | transfer, transferBatch |
checks | createCheck, deleteCheck |
subscriptions | createSubscriptionPlan, archiveSubscriptionPlan, cancelSubscription |
webhooks | updateApp |
Gli ambiti si sommano e sono indipendenti: invoices non implica read, quindi
un server che si limita a creare fatture può avere un token senza accesso ai saldi o allo storico dei pagamenti. Chiamare un metodo che il token non copre restituisce
403 scope_required. getMe riporta gli scopes del token in uso (null per
il token principale) e il suo token_name, così sai sempre che cosa hai in
mano.
Modalità dei pagamenti
Un ambito dice quali metodi può chiamare un token; la modalità dei
pagamenti dell’app dice a chi può pagare qualsiasi suo token, compreso
quello principale. Un’app nuova paga chiunque fin dal primo minuto; il
proprietario può restringerla aprendo l’app in Altro → Merchant API, poi Impostazioni dei pagamenti → Pagamenti tramite API. Come il
limite giornaliero, limita le conseguenze della perdita del token. Per consentire pagamenti a più destinatari servono la biometria o il PIN; l’API può
solo leggerla (getMe → payout_mode).
payout_mode | Che cosa possono fare transfer, transferBatch e createCheck |
|---|---|
any | pagare qualsiasi utente, lasciare in attesa un pagamento per uno @username sconosciuto, creare buoni al portatore: è l’impostazione predefinita, la stessa di Crypto Bot |
allowlist | pagare solo gli utenti Telegram in elenco. Ogni destinatario riservato o nominativo di un buono deve essere in elenco. Altri destinatari, @username sconosciuti e buoni al portatore restituiscono 403 recipient_not_allowed |
off | niente: ogni chiamata di pagamento restituisce 403 payouts_disabled; fatture, abbonamenti, rimborsi e webhook funzionano come sempre |
Se un pagamento viene rifiutato, il proprietario riceve una notifica su Telegram e può cambiare la modalità. Il limite giornaliero dei pagamenti si applica in aggiunta alla modalità. Per che cosa puoi pagare lo stabiliscono le condizioni della Merchant API.
Richieste e risposte
- I metodi di lettura sono
GET, con i parametri nella query. I metodi che muovono denaro sono soloPOST: parametri come corpo JSON, come form-urlencoded o nella query (in caso di conflitto vince il corpo);multipart/form-dataviene rifiutato. - Le risposte dei metodi API usano un formato JSON comune: in caso di successo
{"ok": true, "result": …}, in caso di errore{"ok": false, "error": {"code": <stato HTTP>, "name": "<nome_errore>"}}. Gestisci l’errore in base aerror.name: è una stringa stabile, pensata per essere letta dal codice. - Un valore di query del tipo sbagliato su un metodo GET (per esempio
offset=abc) può essere rifiutato prima dell’esecuzione del metodo API. Controlla lo stato HTTP: non tutte le risposte di errore seguono il formato sopra. Invia i valori della query nei tipi previsti.
Gli importi
- Gli importi in cripto sono stringhe decimali espresse nell’unità dell’asset
(
"10.5"), mai numeri JSON. Le risposte portano ancheamount_minor(estensione): il valore intero nelle unità minori, come stringa, perché gli interi su scala wei possono superare la precisione intera esatta di unNumberdi JavaScript. - I
decimalsdi ogni asset arrivano dagetCurrencies: fai i tuoi conti a partire da lì, invece di scriverli fissi nel codice. - Gli importi in valuta fiat hanno al massimo 2 decimali.
- I tassi sono stringhe a virgola fissa, mai numeri.
La paginazione
I metodi che restituiscono elenchi (getInvoices, getChecks, getTransfers,
getSubscriptions) accettano offset (predefinito 0) e count (predefinito 100, al
massimo 1000; per getSubscriptions al massimo 500) e restituiscono
{"items": […]}, dal più recente. I filtri per ID (invoice_ids, check_ids,
transfer_ids) sono elenchi di interi separati da virgola. Le date e gli orari,
ovunque, sono stringhe ISO 8601.
Idempotenza: spend_id
I metodi che muovono denaro accettano una chiave spend_id generata da chi
chiama (da 1 a 64 caratteri): obbligatoria su transfer e su ogni elemento di
transferBatch, facoltativa su createCheck e refundInvoice (estensione:
usala lo stesso). Ritentare con la stessa chiave e gli stessi parametri ripete
il risultato originale invece di muovere denaro due volte, quindi una richiesta
andata in timeout si può sempre ritentare senza rischi. La stessa chiave con
parametri diversi restituisce 409 idempotency_conflict; un tentativo mentre
l’originale è ancora in esecuzione restituisce 409 idempotency_in_progress.
I limiti di frequenza
Sono per app e condivisi tra tutti i suoi token; superarli restituisce
429 rate_limited:
| Metodo | Limite |
|---|---|
createInvoice, createCheck | 60 al minuto |
refundInvoice | 30 al minuto |
transfer | 30 al minuto |
transferBatch | 10 al minuto |
updateApp | 10 al minuto |
createSubscriptionPlan | 20 al minuto |
Possono applicarsi altri limiti alle richieste. In caso di 429 rate_limited,
aumenta l’attesa prima di riprovare. Durante la manutenzione della
piattaforma i metodi di scrittura restituiscono 503 maintenance, mentre le
letture continuano a funzionare.
Metodi di catalogo e di account
getMe
GET /pay/api/getMe — nessun parametro. Restituisce l’identità dell’app:
app_id, name, payment_processing_bot_username, webhook_url,
webhook_events (i tipi di webhook estesi che l’app ha attivato), i campi di
introspezione del token scopes / token_name descritti sopra, e
payout_mode (off / allowlist / any),
daily_payout_max_usd_cents (0 = nessun limite impostato dal proprietario) e
daily_payout_spent_usd_cents (spesa nelle ultime 24 ore).
updateApp
POST /pay/api/updateApp — ambito webhooks. Parametri facoltativi:
name (1–64 caratteri), webhook_url (un URL HTTPS pubblico; una stringa
vuota lo rimuove) e webhook_events (un array o un elenco separato da
virgole dei nomi degli eventi aggiuntivi supportati). Un elenco vuoto
lascia solo invoice_paid. Restituisce gli stessi campi dell’app di getMe.
getBalance
GET /pay/api/getBalance — nessun parametro. Restituisce un elenco con una riga
per ogni asset supportato, anche a zero: currency_code, available (il saldo
spendibile), onhold (i fondi nei buoni non riscossi e nei pagamenti in attesa a @username) e
amount_minor.
getCurrencies
GET /pay/api/getCurrencies — nessun parametro. L’elenco che fa fede su quello
che l’API supporta: le righe delle cripto (is_blockchain: true) e le valute
fiat in cui si possono prezzare le fatture (is_fiat: true). Ogni riga
porta code, name, decimals e il flag is_stablecoin.
getExchangeRates
GET /pay/api/getExchangeRates — nessun parametro. Le quotazioni da cripto a
valuta fiat: source, target, rate (una stringa a virgola fissa) e
is_valid. Considera i tassi indicativi: is_valid: true non garantisce
che una quotazione sia aggiornata. Se non è possibile ottenere i tassi,
il risultato può essere un array vuoto. Per riconciliare un pagamento
effettivo, usa gli importi e i tassi registrati nella fattura.
getStats
GET /pay/api/getStats — start_at / end_at facoltativi (ISO 8601; per impostazione predefinita
la finestra è le ultime 24 ore). Restituisce volume (il valore in dollari
delle fatture pagate nella finestra, stimato ai tassi attuali; gli asset
senza prezzo contribuiscono per zero), conversion (pagate su create, in
percentuale), unique_users_count, created_invoice_count,
paid_invoice_count e gli estremi effettivi della finestra. Una data
illeggibile restituisce 400 invalid_date.
Errori che può restituire qualsiasi metodo
| HTTP | error.name | Quando |
|---|---|---|
| 401 | unauthorized | token mancante, non valido o revocato |
| 403 | scope_required | al token manca l’ambito del metodo |
| 403 | payouts_disabled | la modalità dei pagamenti dell’app è off (solo nei metodi che fanno uscire denaro) |
| 403 | recipient_not_allowed | il destinatario non è nell’elenco dei destinatari dell’app (solo nei metodi che fanno uscire denaro) |
| 400 | invalid_request | parametri illeggibili o non validi (POST) |
| 403 | daily_cap_exceeded | verrebbe superato il limite giornaliero dei pagamenti dell’app |
| 403 | verification_required | le operazioni in uscita del proprietario sono limitate; riguarda trasferimenti, buoni e rimborsi |
| 503 | merchant_payouts_paused | gli addebiti sul saldo dell’app sono temporaneamente sospesi |
| 429 | rate_limited | limite di frequenza superato |
| 503 | maintenance | manutenzione della piattaforma (metodi di scrittura) |
| 500 | internal_error | errore imprevisto del server |
Gli errori specifici di ogni metodo sono elencati nella sua pagina.
Errori senza la struttura JSON
Una risposta di errore in testo semplice o HTML non basta a identificare il livello da cui proviene. Controlla lo stato HTTP, il corpo e gli header della risposta.
Se Cloudflare restituisce error code: 1010, ha rifiutato il client in base alla firma del browser prima che la richiesta raggiungesse l’API. Gli ambiti del token non sono la causa di questo errore di Cloudflare. Un User-Agent mancante o non standard può attivare la protezione di rete. Prova a inviare un header User-Agent che identifichi il tuo client, come MyShop/1.0, e ripeti la richiesta; non è una soluzione garantita. Se l’errore persiste, invia all’assistenza lo stato HTTP, il corpo e gli header della risposta, dopo aver rimosso token e cookie.
Questa guida ti è stata utile?
Grazie del riscontro.