Transaction.PurchaseApprovalResult
Emitted when a purchase-approval request is resolved: the parent approved it, the parent denied it, or it expired unanswered. This is the answer to a /transaction/request-purchase call, and it's the only way your product learns the outcome.
k-ID delivers Transaction.PurchaseApprovalResult only to endpoints subscribed to it, and drops it for the rest without a delivery attempt or an error. Select it for your endpoint on the product's Developer Settings page. See Before you start.
One request produces exactly one Transaction.PurchaseApprovalResult. Correlate it with the request through data.id, which is the id your product sent to /transaction/request-purchase.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
eventType | string | yes | Always "Transaction.PurchaseApprovalResult" |
data | object | yes | Purchase approval result data |
data.id | string (UUID) | yes | Approval request ID, matching the id your product sent to /transaction/request-purchase |
data.sessionId | string (UUID) | yes | Session ID the purchase was requested for |
data.productId | number | yes | Product ID |
data.status | string | yes | approved, denied, or expired |
data.resolvedAt | string (date-time) | yes | When the request reached this outcome, RFC 3339 |
Example
{
"eventType": "Transaction.PurchaseApprovalResult",
"data": {
"id": "9d4e2f81-7a3b-4c56-8e90-1f2a3b4c5d6e",
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"productId": 42,
"status": "approved",
"resolvedAt": "2026-06-24T15:12:00Z"
}
}
Statuses
status | Meaning | What to do |
|---|---|---|
approved | The parent approved the purchase. | Complete the purchase. |
denied | The parent declined the purchase. | Don't charge. Tell the player their parent declined. |
expired | The parent didn't answer within 24 hours of the request. | Don't charge. The player can be offered the purchase again. |
expired isn't an error and isn't a delivery failure. A player can be offered the purchase again after a request expires.
Approve before you charge
The outcome gates the purchase; it doesn't record one. Complete the purchase only on approved, and treat both denied and expired as "don't charge." Because the request expires after 24 hours, don't wait on the webhook indefinitely: the expiresAt returned by /transaction/request-purchase is the point past which no answer comes.
Delivery is at-least-once, so the same result can arrive more than once. Make your handler idempotent on data.id, as described in the webhooks overview.
When it doesn't fire
- No approval was requested for the purchase.
- The Purchase Controls capability (which requires Transactions) is off for the product, so
/transaction/request-purchasereturnsFEATURE_DISABLEDand no request is created.