Post Final Response
Understand and verify the callback data PayOrc sends after a payment is completed. Covers all response fields, signature verification, status handling, and error codes.
Post Final Response
Version: 3.0.0
What is the Post Final Response? After a payment is completed (successful, failed, or cancelled), PayOrc sends a server-to-server POST callback to your configured endpoint with the full transaction details. This is your source of truth for order fulfillment — never rely solely on the client-side redirect URL.
Why This Matters
The client-side redirect (to your success/failure/cancel URL) can be:
- Spoofed — A malicious user could craft a fake redirect URL with fake parameters.
- Lost — Network issues, browser crashes, or popup blockers can prevent the redirect from reaching your customer's browser.
The server-side callback is tamper-proof (when verified) and reliable (sent directly from PayOrc to your server). Always use the callback for:
- Updating order status in your database
- Fulfilling the purchase (shipping, provisioning access, etc.)
- Recording transaction details for reconciliation
How the Callback Works
Step 1: PayOrc processes the transaction (authorization, capture, or decline).
Step 2: PayOrc sends an HTTP POST request to your configured callback URL with the transaction payload as JSON.
Step 3: Your server receives the payload, verifies the signature (recommended), updates the order status, and returns a 200 OK response.
Step 4: PayOrc considers the callback delivered if it receives a 200 OK within 30 seconds. If not, it retries with exponential backoff (up to 5 attempts over 24 hours).
Important: Your callback endpoint must respond with HTTP 200 within 30 seconds. If your processing takes longer, acknowledge immediately with 200 and process the payload asynchronously.
Callback Endpoint Configuration
You configure your callback URL in the PayOrc dashboard:
- Navigate to Developers → Webhooks → Add Endpoint
- Enter your callback URL (must be HTTPS)
- Select the events to subscribe to (payment completed, failed, etc.)
- Save and note the signing secret for signature verification
Response Fields
The callback payload contains the following fields:
Core Transaction Fields
| Field | Type | Description |
|---|---|---|
m_order_id | String | Your merchant order ID from the original request |
p_order_id | Integer | PayOrc's unique order ID |
p_request_id | Integer | PayOrc's unique request ID |
transaction_id | Integer | Unique transaction identifier for this payment attempt |
transaction_date | String | Timestamp of the transaction (format varies) |
status | String | Transaction status (see Status Values below) |
amount | Float | Transaction amount in the smallest currency unit |
currency | String | Three-letter ISO currency code (e.g., AED, USD) |
mode | String | live for production, test for sandbox |
Payment Details Fields
| Field | Type | Description |
|---|---|---|
psp | String | Payment Service Provider that processed the transaction |
psp_ref_id | String | Reference ID returned by the PSP |
psp_txn_id | Integer | Transaction ID assigned by the PSP |
payment_method | String | Payment method used (e.g., VISA, MASTERCARD, APPLEPAY) |
payment_method_data | Object | Additional payment method details (see below) |
apm_name | String | Alternative Payment Method name (if applicable, e.g., Apple Pay, Google Pay) |
m_payment_token | String | Token for recurring/one-click payments (if tokenization was requested) |
Customer and Metadata Fields
| Field | Type | Description |
|---|---|---|
m_customer_id | String | Your customer ID from the original request |
parameters | Object | Custom key-value pairs you passed in the order request |
custom_data | Object | Additional data from PayOrc (e.g., 3DS result, fraud score) |
Payment Method Data Object
The payment_method_data field contains details about the payment instrument used:
| Field | Type | Description |
|---|---|---|
scheme | String | Card network: VISA, MASTERCARD, AMEX, DISCOVER, etc. |
card_country | String | ISO country code of the card issuer |
card_type | String | CREDIT, DEBIT, or PREPAID |
masked_pan | String | Masked card number (e.g., 411111******1111) |
Status Values
| Status | Meaning | Action Required |
|---|---|---|
APPROVED | Payment was successfully authorized and/or captured | Fulfill the order |
DECLINED | Payment was declined by the issuer | Notify customer, suggest retry |
PENDING | Payment is awaiting processing (e.g., bank transfer) | Poll for status updates or wait for callback |
CANCELLED | Customer cancelled the payment | Log the attempt, no fulfillment needed |
ERROR | An error occurred during processing | Log the error, check transaction details |
REFUNDED | Payment was fully refunded | Update order status |
PARTIALLY_REFUNDED | Payment was partially refunded | Update order with refund amount |
Full Callback Example
# Simulate receiving the callback (for testing your endpoint)
curl --location 'https://your-site.com/api/payment-callback' \
--header 'Content-Type: application/json' \
--header 'X-PayOrc-Signature: sha256=abc123def456...' \
--data-raw '{
"m_order_id": "CUST-10042",
"p_order_id": 1000010240,
"p_request_id": 1000010200,
"transaction_id": 5000123456,
"transaction_date": "2024-01-15T14:30:00Z",
"status": "APPROVED",
"amount": 150.00,
"currency": "AED",
"mode": "live",
"psp": "Adyen",
"psp_ref_id": "adyen-ref-789012",
"psp_txn_id": 9876543,
"payment_method": "VISA",
"payment_method_data": {
"scheme": "VISA",
"card_country": "AE",
"card_type": "CREDIT",
"masked_pan": "411111******1111"
},
"apm_name": null,
"m_customer_id": "CUST-10042",
"m_payment_token": "tok_abc123xyz",
"parameters": {},
"custom_data": {
"three_ds_result": "Y",
"fraud_score": 12
}
}'Error Handling and Retries
PayOrc uses automatic retries for failed callback deliveries:
| Attempt | Delay | Condition |
|---|---|---|
| 1st | Immediate | First delivery attempt |
| 2nd | 1 minute | If no 200 response received |
| 3rd | 10 minutes | Still no 200 response |
| 4th | 1 hour | Still no 200 response |
| 5th | 24 hours | Final attempt |
Your callback endpoint must:
- Return HTTP
200within 30 seconds - Handle duplicate callbacks gracefully (idempotency)
- Verify the signature before processing
- Process asynchronously if business logic takes longer than 30 seconds
Idempotency Pattern
Always check if you have already processed a callback before acting on it:
# Test idempotency by sending the same callback twice
BODY='{"m_order_id":"CUST-10042","p_order_id":1000010240,"status":"APPROVED"}'
curl -X POST 'https://your-site.com/api/payment-callback' \
--header 'Content-Type: application/json' \
--data "$BODY"
# First: processes the order
# Second: returns "Already processed" with 200