Skip to main content

Webhooks (Callbacks)

When an order's status changes, the system sends an HTTP POST to the notifyUrl specified on the order (or your merchant profile default).

Payload Format

Legacy API callbacks use the compact UTpay format:

{
"refCode": "ORD-260601103045-A1B2",
"orderId": "INV-2026-00123",
"totalAmount": 50000,
"status": "PAID",
"paidAt": "2026-06-01 10:38:12"
}

Fields

FieldTypeDescription
refCodestringPGA internal reference code
orderIdstringYour original order ID (the orderId you sent in the create request)
totalAmountintegerFull IDR integer — same value you sent in totalAmount
statusstringPAID, PENDING, or FAILED
paidAtstringWIB timestamp ("YYYY-MM-DD HH:MM:SS"); null if not paid

Status Mapping

PGA StatusCallback Status
PAIDPAID
PENDINGPENDING
PROCESSINGPENDING
EXPIREDFAILED
FAILEDFAILED
CANCELLEDFAILED
REFUNDEDFAILED
note

PENDING callbacks may fire while an order is still awaiting payment. Always wait for PAID before fulfilling orders.

Timezone

All timestamps in Legacy API callbacks are in WIB (Asia/Jakarta, UTC+7). Format: "YYYY-MM-DD HH:MM:SS".

Responding

Return HTTP 200 to acknowledge. Any other response triggers a retry on the same schedule as V1 webhooks:

AttemptDelay
1Immediate
2+30s
3+2m
4+10m
5+30m
6 (final)+2h

No Signature Header

Legacy callbacks do not include an X-Signature header. If you need to verify the source, consider IP allowlisting or use the query endpoint to confirm order status.

Minimal Handler

PHP — minimal callback handler
<?php
$payload = json_decode(file_get_contents('php://input'), true);

http_response_code(200);
echo json_encode(['received' => true]);

if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}

if ($payload['status'] === 'PAID') {
// Lookup your order by $payload['orderId']
// Mark as paid in your database
}