Skip to main content

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.

Subscribe your endpoint to this event

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

FieldTypeRequiredDescription
eventTypestringyesAlways "Transaction.PurchaseApprovalResult"
dataobjectyesPurchase approval result data
data.idstring (UUID)yesApproval request ID, matching the id your product sent to /transaction/request-purchase
data.sessionIdstring (UUID)yesSession ID the purchase was requested for
data.productIdnumberyesProduct ID
data.statusstringyesapproved, denied, or expired
data.resolvedAtstring (date-time)yesWhen 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

statusMeaningWhat to do
approvedThe parent approved the purchase.Complete the purchase.
deniedThe parent declined the purchase.Don't charge. Tell the player their parent declined.
expiredThe 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-purchase returns FEATURE_DISABLED and no request is created.