Three webhook URLs
There's nothing to register in a portal. You name the URLs in the body of each request, and every post carries your reference_id so you can match it to the request that started it.
webhook_urlgets the payment link and status callbacks. Withtransaction_flag=4andlinktopay_url=0, this is where the customer's payment link arrives.webhook_url_transactiongets the payment gateway's result. It's required for bank capture and bank out-payment.webhook_url_tokengets the card token, if you send it.
If you don't want webhook outcomes at all, for example because you already take them from the payment gateway itself, talk to Paytia first.
Payment link webhook
Posted to webhook_url as application/json when linktopay_url=0, which is the default. Send linktopay_url=1 instead and the link comes back on the API response, with no webhook.
| Field | Values |
|---|---|
| status | true / false |
| status_code | 200 |
| linktopay_url | The URL the customer pays on |
| reference_id | Your unique ID for the request |
Transaction webhook
Posted to webhook_url_transaction as application/x-www-form-urlencoded, on one line. These are form fields, not JSON.
| Field | Values |
|---|---|
| success | 1 = successful. 0 = failed or not completed. |
| reference_id | Your session ID from the original request. |
| authcode | Bank authorisation code. |
| AVSCV2 · AddressResult · PostCodeResult · CV2Result | MATCHED / NOTMATCHED |
| token_id · token_expiry | Tokenise flows only. token_expiry is YYYY-MM-DD. |
It comes in three shapes:
# 1. Authorise or direct payment, AVS matched success=1&reference_id=&authcode=&AVSCV2=MATCHED&AddressResult=MATCHED&PostCodeResult=MATCHED&CV2Result=MATCHED # 2. Tokenise or pre-auth success=1&reference_id=&authcode=&token_id=&AVSCV2=MATCHED&AddressResult=MATCHED&PostCodeResult=MATCHED&CV2Result=MATCHED&token_expiry=YYYY-MM-DD # 3. Authorise, no AVS match success=1&reference_id=&authcode=&AVSCV2=NOTMATCHED&AddressResult=NOTMATCHED&PostCodeResult=NOTMATCHED&CV2Result=MATCHEDtext
Exactly which fields arrive can vary by payment service provider. An aborted call posts custabort=1 or agentabort=1, both with success=0.
MOTO stage webhooks
On a phone payment you can get a webhook at every stage of the call, from agent verification through to card capture, so your own screen can follow along. This needs the sendCdrOnDetails v2 licence. Stage posts are form-encoded.
| payment_stage | When it fires | Form params |
|---|---|---|
| agent_id | Paytia has matched the agent ID typed on the keypad or sent in a SIP header. | agent_id=100 · payment_stage=agent_id · reference_id={your ref} |
| amount_verify | The customer presses 1 to confirm the amount. Rejecting it posts success=0 and ends the session. | amount_verify=accepted · payment_stage=amount_verify · reference_id={your ref} |
| card_number | The customer made a key-entry mistake, and again after they press 1 to confirm or 2 to restart card entry. | payment_stage=card_number · reference_id={your ref} |
| pan_digit | Each card-number digit the customer enters. Show it on the agent's screen as X, XX, XXX… | pan_digit=XXXXXXXXXXXXXXXX · payment_stage=pan_digit |
| card_type / card_verify | Card brand found by BIN check on the first 6 or 8 digits, and the last four digits. Both repeat on re-entry. | card_type=visa · card_verify=4242 · payment_stage=card_type / card_verify |
| card_date / expiry_digit | The expiry stage. expiry_digit arrives as four posts, one character each: M, M, Y, Y. | payment_stage=card_date · expiry_digit=M |
Dropped calls, rejected amounts and aborts arrive on these webhooks too. Exception handling →
Embedded checkout: postMessage events
These are separate from webhooks. When you embed the checkout or Agent Capture Assist frame (is_embedded_url=1), the iframe sends browser postMessage events to the page you name in iframeevent_url. That value must be the exact URL of the page hosting your listener, because an origin-only value receives nothing.
resize-iframecarriesiframeHeight, often fractional, so round it up.payment-statuscarriesstatus(success, failed or error) pluscard_brand,transaction_id,amountandcustomer_message.payment-methodcarriespayment_type: card, google, paypal, bank, apple or empty.
window.addEventListener("message", (event) => {
const ok = ["https://accounts.paytia.com",
"https://accounts.pay729.net"];
if (!ok.includes(event.origin)) return;
const d = event.data;
if (d?.type === "resize-iframe")
iframe.style.height = Math.ceil(d.iframeHeight) + "px";
if (d?.type === "payment-status") { /* d.status */ }
if (d?.type === "payment-method") { /* d.payment_type */ }
});javascriptAlways check event.origin against Paytia's checkout hosts before you trust a message. Set payment_completionscreen=0 if you'd rather show your own completion screen than Paytia's.