tgpay cryptoAPI
crypto-payapiwebhookssignature

Riferimento API: webhook

4 min di letturaAggiornata il 9 ott 2026

I webhook inviano gli eventi al tuo server dopo che si verificano. Imposta l’URL del webhook (facoltativo) sulla tua app in Altro → Merchant API: da lì in poi la piattaforma manda in POST un corpo JSON firmato per ogni evento a cui sei iscritto.

La struttura del messaggio

{
  "update_id": 123,
  "update_type": "invoice_paid",
  "request_date": "2026-08-11T12:00:00Z",
  "payload": { … }
}

update_id resta lo stesso a ogni riconsegna dello stesso evento: usa quello per deduplicare. request_date viene registrato a ogni tentativo di consegna. payload è l’oggetto completo del tipo di evento: l’oggetto fattura per gli eventi delle fatture, l’oggetto buono, trasferimento o abbonamento (le loro forme stanno nelle rispettive pagine di riferimento).

I tipi di evento

update_typeQuando partePayload
invoice_paiduna fattura viene pagata — non richiede attivazioneoggetto fattura
invoice_expireduna fattura supera la scadenza senza essere pagataoggetto fattura
check_activatedviene riscattato un buono o la quota di un destinatariooggetto buono; il riscatto da un elenco nominativo include anche activated_slot
check_expiredscade un buono nominativo e le quote non riscosse tornano all’appoggetto buono con recipients e i relativi valori claimed_at
transfer_completedun trasferimento viene completato o un pagamento sulla blockchain viene confermatooggetto trasferimento o prelievo
transfer_returnedun trasferimento in attesa non riscosso torna all’app, oppure un pagamento sulla blockchain fallisce e l’importo bloccato viene restituitooggetto trasferimento o prelievo
refund_completedun rimborso viene eseguitooggetto fattura con i campi refunded_*
subscription_activatedun utente approva un pianooggetto abbonamento
subscription_chargedviene incassato il pagamento di un periodo — charge.kind dice quale: initial, renewal o resubscribeoggetto abbonamento + charge: {period_no, kind, asset, amount, fee, paid_at}
subscription_cancelledun abbonamento viene disdetto da una delle due partioggetto abbonamento
subscription_expiredil periodo di tolleranza finisce senza pagamentooggetto abbonamento

I pagamenti sulla blockchain creati nell’app usano gli stessi eventi dei trasferimenti. Il payload contiene kind: "withdrawal", campi della blockchain come network, address e txid, e lo stato completed o failed. Il loro transfer_id appartiene a una sequenza di ID separata: distingui i payload tramite kind prima di usarlo. Il riferimento OpenAPI scaricabile descrive entrambe le varianti.

Tutto tranne invoice_paid è facoltativo (è un’estensione rispetto a Crypto Bot: un’integrazione che gestisce solo gli eventi di Crypto Bot non riceve un update_type sconosciuto, a meno che tu non lo abbia attivato). Si attivano per app sotto Eventi webhook aggiuntivi, nella sezione Webhook dell’app. Le opzioni usano gli identificativi della tabella qui sopra. Salva un URL per i webhook per ricevere gli eventi.

Verificare la firma

Ogni consegna porta l’intestazione TgPayCrypto-API-Signature (TgCryptoPay-API-Signature e Crypto-Pay-API-Signature ne sono alias di compatibilità, con lo stesso valore): l’HMAC-SHA256 in esadecimale del corpo grezzo della richiesta, con chiave il digest SHA-256 del token API principale della tua app. È lo schema di Crypto Bot, quindi il codice di verifica che hai già funziona senza modifiche:

import hashlib, hmac

secret = hashlib.sha256(API_TOKEN.encode()).digest()
expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, headers["TgPayCrypto-API-Signature"])

Verifica sui byte grezzi ricevuti: un JSON riserializzato dopo il parsing può differire byte per byte e far fallire il controllo. A firmare è solo il token principale; i token con permessi limitati non firmano mai. Rigenerare il token principale cambia all’istante la chiave di firma dei webhook, quindi aggiorna il segreto sul tuo server nello stesso momento.

Consegne e tentativi

  • Una consegna si considera riuscita con una risposta 2xx ricevuta prima del timeout del tentativo. Rispondi rapidamente ed esegui separatamente le operazioni lunghe.
  • Uno stato di errore, un timeout o un problema di connessione avviano nuovi tentativi con attese crescenti, fino al limite previsto dalla piattaforma. La consegna non è garantita: usa getInvoices per riconciliare i pagamenti dopo un’interruzione.
  • Dopo l’ultimo tentativo la consegna viene abbandonata. L’URL del webhook, però, non viene mai disattivato automaticamente, neanche se il tuo endpoint risponde in modo intermittente.
  • Siccome i tentativi si ripetono, il tuo gestore dev’essere idempotente: deduplica su update_id prima di agire.

⚠️ Verifica prima di evadere

Al tuo URL può mandare un POST chiunque. Finché il controllo della firma non passa, tratta il corpo come input non fidato: non spedire un ordine, non accreditare un utente, non segnare niente come pagato. L’ordine giusto è: verifica la firma → deduplica su update_id → agisci.