Skip to main content
Webhooks

Payment outcomes, posted back to you

The API response only says Paytia accepted your request. Everything after that (the payment link, each stage of a phone payment, the gateway result) is posted to the webhook URLs you send on the request.

API reference menu

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_url gets the payment link and status callbacks. With transaction_flag=4 and linktopay_url=0, this is where the customer's payment link arrives.
  • webhook_url_transaction gets the payment gateway's result. It's required for bank capture and bank out-payment.
  • webhook_url_token gets 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.

FieldValues
statustrue / false
status_code200
linktopay_urlThe URL the customer pays on
reference_idYour 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.

FieldValues
success1 = successful. 0 = failed or not completed.
reference_idYour session ID from the original request.
authcodeBank authorisation code.
AVSCV2 · AddressResult · PostCodeResult · CV2ResultMATCHED / NOTMATCHED
token_id · token_expiryTokenise 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=MATCHED
text

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_stageWhen it firesForm params
agent_idPaytia 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_verifyThe 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_numberThe 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_digitEach 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_verifyCard 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_digitThe 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-iframe carries iframeHeight, often fractional, so round it up.
  • payment-status carries status (success, failed or error) plus card_brand, transaction_id, amount and customer_message.
  • payment-method carries payment_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 */ }
});
javascript

Always 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.

Next

Ready to build with Paytia?

The docs are open. Keys are gated — drop us a line and we'll issue sandbox credentials so you can try every flow against a real endpoint.