Riferimento API: trasferimenti e buoni
I metodi per effettuare pagamenti. Un trasferimento invia fondi dal saldo
della tua app al portafoglio di un utente Telegram oppure li tiene bloccati
finché un nuovo destinatario non apre il bot. Un buono è un link da
riscattare che finanzi in anticipo. Le convenzioni comuni (autenticazione,
struttura delle risposte, importi, spend_id) sono descritte nella pagina
Riferimento della Merchant API.
Tutti e tre i metodi che fanno uscire denaro rispettano la
modalità dei pagamenti dell’app: un’app
nuova paga chiunque fin dall’inizio; se il proprietario l’ha ristretta, si
possono pagare solo i destinatari in elenco (403 recipient_not_allowed)
oppure nessuno (403 payouts_disabled). La modalità la imposta il
proprietario nella Mini App; dall’API non si può. A che cosa possono servire
i pagamenti lo stabiliscono le condizioni della Merchant API.
transfer
POST /pay/api/transfer — ambito payouts, limite 30 al minuto. Un destinatario
già registrato riceve subito il pagamento. Uno username sconosciuto crea un
trasferimento pending: i fondi restano bloccati in garanzia finché il
destinatario non apre il bot con quello username. I fondi non riscossi
tornano sul saldo dell’app dopo la scadenza di 30 giorni (expires_at).
Prima di registrare il rimborso in contabilità, verifica che lo stato sia
returned. Inoltra tu l’invite_url: il bot non
può scrivere a chi non l’ha mai avviato. Lo stato finale è completed oppure
returned; attiva i webhook transfer_completed e
transfer_returned per ricevere gli aggiornamenti oppure interroga periodicamente
getTransfers. Indica esattamente uno tra user_id e username.
Se li ometti entrambi o li invii insieme, la richiesta viene rifiutata perché
i parametri non sono validi.
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
user_id | intero | uno tra user_id e username | l’ID Telegram del destinatario, che deve essere già un utente dell’app |
username | stringa | uno tra user_id e username | lo username del destinatario, con o senza @; uno username sconosciuto crea un pagamento in attesa |
asset | stringa | sì | il codice dell’asset |
amount | stringa | sì | stringa decimale positiva; deve rispettare anche il minimo e il massimo per trasferimento della piattaforma (un controvalore stimato in dollari ai tassi del momento) |
spend_id | stringa | sì | chiave di idempotenza, da 1 a 64 caratteri, unica per ogni pagamento |
comment | stringa | no | fino a 1024 caratteri, mostrato a chi riceve |
disable_send_notification | booleano | no | true disattiva la notifica al destinatario per un pagamento immediato; quando un trasferimento in attesa viene accreditato, la notifica viene comunque inviata |
Il risultato è l’oggetto trasferimento: transfer_id, hash, user_id,
recipient_username, asset, amount, amount_minor, spend_id,
comment, status (pending / completed / returned), created_at,
completed_at, expires_at, invite_url. user_id può essere null mentre
si attende un nuovo destinatario; completed_at è null fino al completamento.
Errori: 403 payouts_disabled / 403 recipient_not_allowed (la
modalità dei pagamenti),
404 user_not_found (ID sconosciuto o destinatario non disponibile),
400 invalid_recipient (username del destinatario non valido),
400 amount_too_small / 400 amount_too_big (fuori
dai limiti per trasferimento), 409 insufficient_funds, 400 unknown_asset,
400 invalid_amount, e la coppia dello spend_id:
409 idempotency_conflict / 409 idempotency_in_progress.
transferBatch
POST /pay/api/transferBatch — ambito payouts, limite 10 al minuto.
Un’estensione per i pagamenti di massa: fino a 100 trasferimenti in una
chiamata sola.
Un parametro solo: items, un array in cui ogni elemento è un set completo di
parametri di transfer (user_id o username, asset, amount, spend_id, più
comment e disable_send_notification facoltativi). Gli spend_id devono
essere unici dentro il lotto, altrimenti tutta la chiamata fallisce con
400 duplicate_spend_id prima di eseguire qualsiasi cosa. Anche una struttura
non valida degli elementi, la modalità dei pagamenti o il limite giornaliero
dell’app possono far rifiutare l’intera richiesta prima di qualsiasi pagamento.
Una volta accettata, i risultati si trovano in result.items.
Gli elementi vengono elaborati in ordine e in modo indipendente l’uno dall’altro: un
elemento che non riesce non annulla mai gli altri. La chiamata restituisce un HTTP 200
con ok: true anche quando alcuni elementi non sono riusciti, quindi controllali
sempre uno per uno:
- riuscito:
{"ok": true, "spend_id": "…", "result": <oggetto trasferimento>} - non riuscito:
{"ok": false, "spend_id": "…", "error": {"code": …, "name": "…"}}con gli stessi nomi d’errore di untransfersingolo.
Gli elementi di un lotto condividono lo spazio dell’idempotenza con i
trasferimenti singoli: ritentare tutto il lotto — o rimandare un elemento come
transfer singolo con lo stesso spend_id — ripete la risposta invece di
pagare due volte.
getTransfers
GET /pay/api/getTransfers — ambito read. Filtri: asset, transfer_ids
(separati da virgola), spend_id (corrispondenza esatta: ritrovi un pagamento
con la tua stessa chiave), status (pending / completed / returned),
più offset / count. Restituisce
{"items": [trasferimento, …]}, dal più recente.
createCheck
POST /pay/api/createCheck — ambito checks, limite 60 al minuto. Per impostazione
predefinita crea un buono a riscatto singolo dal saldo della tua app. Può
riscattarlo chiunque abbia il link, oppure solo l’utente a cui lo riservi.
L’estensione recipients crea un elenco nominativo con un importo separato
per ogni destinatario. Il totale viene bloccato alla creazione (passa da
available a onhold in getBalance). Valgono gli stessi limiti di importo
e di pagamento giornaliero dei trasferimenti.
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
asset | stringa | sì | il codice dell’asset |
amount | stringa | se non imposti recipients | stringa decimale positiva; con recipients, il totale viene calcolato dall’elenco |
pin_to_user_id | intero | no | può riscattarlo solo questo id Telegram |
pin_to_username | stringa | no | può riscattarlo solo questo @username (la @ è facoltativa; ignorato quando c’è anche pin_to_user_id). Lo username deve appartenere a un utente esistente dell’app |
spend_id | stringa | no | chiave di idempotenza (estensione): usane una |
recipients | array | no | estensione: da 1 a 100 elementi, ciascuno con user_id o username e un amount come stringa decimale positiva. Non si può combinare con un utente riservato |
password | stringa | no | estensione: password richiesta per il riscatto, fino a 64 caratteri |
expires_in | intero | no | estensione: durata in secondi; assente o 0 = nessuna scadenza |
Il risultato è l’oggetto buono: check_id, hash, asset, amount,
amount_minor, bot_check_url (il link t.me per riscattare), status
(active / activated), pin_to_user_id, created_at, activated_at,
expires_at e recipients (null per un buono ordinario; altrimenti ogni
voce contiene user_id, username, amount, amount_minor, claimed_at).
Ogni riscatto genera il webhook facoltativo check_activated;
un riscatto da un elenco nominativo include anche activated_slot. Alla
scadenza viene restituito il residuo non riscosso; per un elenco nominativo
può essere inviato l’evento check_expired.
La risposta attuale assegna status: "active" a ogni buono non riscattato
completamente, anche se è scaduto. Controlla anche expires_at: lo stato
active, da solo, non dimostra che il link sia ancora riscattabile.
Errori: 403 payouts_disabled / 403 recipient_not_allowed (la
modalità dei pagamenti: in modalità
allowlist ogni destinatario riservato o nominativo deve essere nell’elenco),
400 unknown_asset, 400 invalid_amount, 404 user_not_found (lo
username riservato non corrisponde a nessuno), 409 insufficient_funds, e la
coppia dello spend_id.
deleteCheck
POST /pay/api/deleteCheck — ambito checks. Un parametro solo: check_id.
Annulla un buono attivo e restituisce il residuo non riscosso al saldo
della tua app; restituisce true. Errori: 404 check_not_found,
409 check_not_active (riscattato completamente, scaduto o eliminato).
getChecks
GET /pay/api/getChecks — ambito read. Filtri: asset, check_ids
(separati da virgola), status (active / activated), più offset /
count. Restituisce {"items": [buono, …]}, dal più recente; i buoni eliminati
non compaiono mai.
Questa guida ti è stata utile?
Grazie del riscontro.