Fulfill purchases through the backend API
Implement your own backend that listens to purchase events and tracks your player's entitlements.
Read time 5 minutesLast updated a month ago
If your game uses server-authoritative entitlements, implement a backend system that does the following:
- Validate the webhook event (JWT).
- Parse the event.
- Update entitlements or inventory in your system based on the event type.
- Mark the order as fulfilled.
- Return an event response.
This ensures both your system and Unity IAP are in sync.
Validate webhook events (JWT)
To enable validation, Unity IAP signs webhook requests with a JSON Web Token (JWT). Verify the following information for this token in your backend to ensure events are authentic:
- Authorization header:
Bearer <token> - Signature: Signed with a private key. Fetch and cache the JWKS (public key) to verify:
https://services.api.unity.com/webhooks/.well-known/jwks.json - Issuer:
https://services.api.unity.com/webhooks/ - Audience claims (array): (Unity Project Id),
upid(Environment Id)envId - Token expiration: Ensure (expiration) has not passed.
exp
There are libraries for most languages that you can use to validate JWTs.
Webhook event shape
Unity IAP normalizes events from all supported payment providers into this consistent format. Refer to the following example:
{ "id": "018d5e5e-5e5e-7e5e-5e5e-5e5e5e5e5e5e", "version": "1.0.0", "eventType": "order.paid", "time": "2024-01-15T14:30:00Z", "projectId": "018d5e5e-1111-7e5e-5e5e-111111111111", "environmentId": "018d5e5e-2222-7e5e-5e5e-222222222222", "dataType": "order", "data": { "id": "018d5e5e-3333-7e5e-5e5e-333333333333", "playerId": "player_12345", "paymentProvider": "stripe", "paymentProviderResourceId": "cs_test_a1b2c3d4e5f6", "url": "https://checkout.stripe.com/pay/cs_test_a1b2c3d4e5f6", "lineItems": [ { "sku": "com.game.coins_100", "productType": "Consumable", "price": { "amountMicros": 4990000, "currency": "USD" } } ], "total": { "amountMicros": 4990000, "currency": "USD", "refundedAmountMicros": 0 }, "status": "paid", "customReferenceId": "order_xyz_789", "metadata": { "campaign": "summer_sale", "platform": "iOS" }, "createdAt": "2024-01-15T14:25:00Z", "updatedAt": "2024-01-15T14:30:00Z", "paidAt": "2024-01-15T14:30:00Z", "fulfilledAt": null }}
Refer to the following fields in webhook events:
Event types
Unity IAP sends the following webhook event types:
order.paid
Unity IAP sends the event when a player successfully completes a purchase. When you receive this event, grant the player the entitlements or currency they purchased and mark the order as fulfilled.
order.paidorder.updated
Unity IAP sends the event every time the order is updated. This includes changes such as the following:
order.updated- The order being marked as fulfilled.
- A refund being processed.
- Other order modifications.
The field in reflects the current total refunded amount.
refundedAmountMicrosdata.totalRefunds are developer-initiated. For example, you might issue a refund to a player through the payment provider's dashboard.
Unity IAP doesn't automatically revoke entitlements when a refund occurs. If you want to revoke entitlements on refund, you can listen for this event and handle it in your own entitlement system.
order.revoked
Unity IAP sends the event when the order status changes to . When you receive this event, revoke the player's entitlements or currency that was granted for the original purchase.
order.revokedrevokedChargebacks are player-initiated. For example, a player might dispute a charge through their credit card company or bank.
When a chargeback dispute closes and the player wins the dispute, Unity IAP automatically revokes the order and sends this event. Unlike refunds, Unity IAP revokes entitlements on chargebacks.
Mark orders as fulfilled via API
After granting entitlements on your backend, use the Orders API to mark the order as fulfilled. This updates the timestamp and ensures the order status is tracked correctly.
fulfilledAtAuthentication
To call these endpoints, you need to authenticate using one of the following methods:
- Service account: Create a service account in the Unity Dashboard and use it to authenticate your backend server. For more information, refer to Service account authentication.
- Cloud Code: Call the endpoint from a Cloud Code script or module, which can authenticate on behalf of your project. For more information, refer to Use a Cloud Code module to fulfill purchases.
Get order
Call the endpoint to retrieve the order.
GETGET https://iap.services.api.unity.com/v1/projects/{projectId}/environments/{environmentId}/orders/{orderId}
Order statuses
Status | Description |
|---|---|
| Order has been created but payment has not been completed. Can transition to |
| Payment has been received and confirmed by the payment provider. Can transition to |
| Order has been fulfilled and the player has been rewarded. Can transition to |
| Order failed. This is a terminal state. |
| Order has been revoked. This is a terminal state. |
| Order has been cancelled before payment. This is a terminal state. |
Example response body
Both and endpoints return the full order object:
GETPATCH{ "id": "018d5e5e-3333-7e5e-5e5e-333333333333", "projectId": "018d5e5e-1111-7e5e-5e5e-111111111111", "environmentId": "018d5e5e-2222-7e5e-5e5e-222222222222", "playerId": "player_12345", "paymentProvider": "stripe", "paymentProviderResourceId": "cs_test_12345", "url": "https://checkout.stripe.com/pay/cs_test_12345", "lineItems": [ { "sku": "com.game.coins_100", "productType": "Consumable" } ], "status": "paid", "fulfilledAt": null, "revokedAt": null, "customReferenceId": "order_xyz_789", "metadata": { "campaign": "summer_sale" }, "createdAt": "2024-01-15T14:25:00Z", "updatedAt": "2024-01-15T14:30:00Z"}
Update an order
Call the endpoint to update an order's status:
PATCHPATCH https://iap.services.api.unity.com/v1/projects/{projectId}/environments/{environmentId}/orders/{orderId}
Request body
{ "status": "fulfilled"}
The new status to set for the order. Allowed values:
- : Set after granting entitlements to the player. Can only be set on
fulfilledorders.paid - : Set to revoke the player's entitlements (for example, after a refund). Can only be set on
revokedorpaidorders.fulfilled - : Set to cancel the order. Can only be set on
cancelledorders (before payment).created
Once an order is or , its status cannot be changed.
revokedcancelledYou can refer to the IAP Client API documentation for the HTTP response status codes.
Return an event response
You need to return an event response to indicate the success or failure of processing the event.
- response: Indicates successful event processing.
2xx - Non-response: Indicates a failure. Unity IAP will replay the event according to the replay policy.
2xx
Event replay behavior
When your webhook endpoint returns a non- response, Unity IAP automatically retries delivery of the event. Ensure your webhook handler is idempotent so that replayed events don't result in duplicate entitlements.
2xxNext steps
This page is part of a workflow to set up Direct-to-Consumer (D2C) payment providers with IAP. To continue this workflow, choose one of the following options: