Skip to main content

Creating Transactions

Merchant Callback API →

When a customer buys one of your Deals products, we call your callback API to create the transaction. This is part of the standard callback API you already host; there is no separate Deals service to stand up.

POST https://api.your-company.com/trx/transaction

One call covers exactly one product. The transaction UUID travels in the body as trx_id.

Your 200 is the approval gate

We do not approve the transaction or disburse until this call succeeds. Your success response is the confirmation that you have accepted the order; only then does money move on our side.

So the ordering is: you accept → you respond 200 → we disburse. Return 200 only once the order is durably committed on your side, and return an error if it is not.

Creating a transaction

What we send

{
"order_id": "order-123",
"trx_id": "9f1c2b7a-3e5d-4c11-8a6f-2b9d0e7c1a42",
"product_id": "1000001",
"amount": 24999,
"currency": "PHP",
"created": "2026-07-23T08:30:00+08:00",
"customer": {
"full_name": "Juan Dela Cruz",
"first_name": "Juan",
"last_name": "Dela Cruz",
"email": "[email protected]",
"phone": "+639171234567",
"adr_shipping": {
"addr_type": "shipping",
"country": "PH",
"region": "NCR",
"province": "Metro Manila",
"city": "Makati",
"barangay": "Poblacion",
"street": "123 Rizal St.",
"postal_code": "1210",
"address": "123 Rizal St., Poblacion, Makati, Metro Manila 1210"
}
}
}

product_id is the same id you sync to us. order_id is our order reference; store it, you send it back on every delivery-status update. trx_id is the transaction UUID and goes in the path of those updates.

customer is the recipient. For gift purchases such as vouchers we also send a sender object with the buyer's details; it is absent otherwise.

What you return

{ "status": "OK", "in_stock": 41 }

in_stock is the remaining quantity after this order. We write it straight into the Deals catalog, so return the true post-decrement count. 0 marks the product out of stock immediately, with no separate sync call needed.

Out of stock

If you cannot fulfil because the product is out of stock, do not create the transaction. Return 409:

{ "code": "OUT_OF_STOCK", "message": "Product is out of stock" }

We match on code, so message is yours to word however you like. This is a soft failure: we set the product's stock to 0 and cancel the transaction quietly, without treating it as an integration error.

One attempt, no retries

We call this exactly once

We do not retry POST /trx/transaction. Each transaction order is attempted a single time. We wait up to 40 seconds for your response; if none arrives we stop waiting and treat the call as failed.

If the call does not clearly succeed (any 4xx or 5xx, or the 40-second timeout), we treat the order as failed and cancel the customer's transaction on our side. We do not approve and we do not disburse.

Because there is only ever one attempt, return 200 only once the order is durably committed on your side. A late or uncertain response is safer failed than accepted: if your 200 does not reach us within the 40 seconds we cancel, so a success that arrives too late leaves you holding an order we have already cancelled. The outcome is visible in the Merchants Portal.

To settle a case where you are unsure whether your response reached us, read our view of the transaction back:

GET /trx/{id}/status

APR means we approved and disbursed; anything else means we did not. GET /trx/{id}/history gives the full timestamped sequence. Both are on the Billease Transaction API and need no extra setup.

Existence check (manual, for debugging)

You also host a lightweight, read-only endpoint we can use to check whether a transaction order reached you. It exists purely for manual debugging on our side; nothing automated calls it, and it plays no part in approval or disbursement. Your 200 on POST /trx/transaction is still the only approval gate; this is not a confirmation step.

GET https://api.your-company.com/trx/transaction/{trx_id}

{trx_id} is the transaction UUID we sent you on POST /trx/transaction. As with the POST endpoint, the exact path is yours to choose; just give it to us at onboarding. Secure it with the same scheme as your other callback endpoints.

We look only at the HTTP status and ignore the response body: any 2xx means the order exists on your side; any 4xx / 5xx means it does not, or could not be confirmed.

Checking the price

We do not require you to verify amount, and we do not verify it either. But a price change on your side goes through our approval queue, so the Deals catalog price can lag yours for as long as approval takes.

Compare amount against your live price before accepting, and reject rather than confirming at a stale one; remember that your 200 is what triggers disbursement.

Cancelling

A Deals order cannot be cancelled or reversed with a status. It is already approved on our side, so POST /trx/{id}/update with status: CAN, or any other status value, does not change the transaction: such calls are rejected. (Standard checkout differs, where status: CAN cancels the transaction.) The status field is inert here; you still send delivery_status to report fulfilment progress.

Any reversal must go through a refund, whether or not the order has already shipped:

POST /trx/{id}/refund

It settles the amount, marks the items refunded, folds into your net-proceeds accounting and returns a refund_id you can poll with GET /trx/refund/{refund_id}. See POST /trx/{id}/refund.