UnivaPay Webhook Events — Contract
UnivaPay Webhook Events — Contract
Source: https://docs.univapay.com/docs/guide/detail/webhook/ (fetched 2026-08-03)
Delivery
- HTTP POST to the merchant-configured URL (local URLs not allowed)
Authorizationheader contains the merchant-definedauth_token(6+ chars) — the per-supplier
verification value Yoyacoo stores- Receiver MUST return 2xx within 3 seconds (slower = treated as failure, retried)
- Retries may deliver the same event more than once → idempotent handling required (record the
top-levelid/webhook_id; replay returns 200 without re-processing) - Retry stops permanently after 3xx; 4xx/500-502 retry up to 10 times then stop
Verification
- Identify supplier by
data.store_id(matchesuser_payment_univapays.store_id) - Compare the incoming
Authorizationheader with the storedauth_tokenfor that supplier - Reject with 401 on mismatch; log and 200 (no side effects) on replay
Events to subscribe to (MVP)
| Trigger (console) | Event | Resource | Statuses |
|---|---|---|---|
| 課金 (Charge) | charge_finished |
Charge | successful / failed / error / canceled (refunded) |
| 返金 (Refund) | refund_finished |
Refund | successful / failed |
| キャンセル完了 (Cancel) | cancel_finished |
Cancel | successful / failed / error |
Sample payloads
charge_finished — successful
{
"id": "11ef1288-37b0-2f15-a097-d3a0d4243d4c",
"event": "charge_finished",
"data": {
"id": "11ef1288-399b-eb84-a215-038628c5c460",
"store_id": "11ecda54-12g0-1c78-bd0f-73aa270d700f",
"transaction_token_id": "11ef1118-3766-4fdc-baed-b72c5ac3e0ba",
"transaction_token_type": "one_time",
"subscription_id": null,
"requested_amount": 100,
"requested_currency": "JPY",
"requested_amount_formatted": 100,
"charged_amount": 100,
"charged_currency": "JPY",
"charged_amount_formatted": 100,
"fee_amount": null,
"fee_currency": null,
"fee_amount_formatted": null,
"only_direct_currency": true,
"capture_at": null,
"descriptor": null,
"descriptor_phone_number": null,
"status": "successful",
"metadata": {},
"mode": "test",
"created_on": "2024-05-15T06:56:12.852465Z",
"redirect": {}
},
"created_on": "2024-05-15T06:56:13.140163783Z",
"webhook_id": "11ee8cf5-2be5-67d8-bc18-7b7c584c5735",
"successful": true,
"fired_on": "2024-05-15T06:56:13.092717474Z"
}
charge_finished — failed
{
"id": "11ef1288-37b0-2f15-a097-d3a0d7843d4c",
"event": "charge_finished",
"data": {
"id": "11ef1288-399b-eb84-a215-038628c5c460",
"store_id": "11ecda54-12g0-1c78-bd0f-73aa270d700f",
"transaction_token_id": "11ef1118-3766-4fdc-baed-b72c5ac3e0ba",
"transaction_token_type": "one_time",
"subscription_id": null,
"requested_amount": 100,
"requested_currency": "JPY",
"requested_amount_formatted": 100,
"charged_amount": 100,
"charged_currency": "JPY",
"charged_amount_formatted": 100,
"fee_amount": null,
"fee_currency": null,
"fee_amount_formatted": null,
"only_direct_currency": true,
"capture_at": null,
"descriptor": null,
"descriptor_phone_number": null,
"status": "failed",
"error": {
"code": 309,
"message": "Test charge failed purposely",
"details": "Test charge failed purposely"
},
"metadata": {},
"mode": "test",
"created_on": "2024-05-15T06:56:12.852465Z",
"redirect": {}
},
"created_on": "2024-05-15T06:56:13.140163783Z",
"webhook_id": "11ee8cf5-2be5-67d8-bc18-7b7c584c5735",
"successful": true,
"fired_on": "2024-05-15T06:56:13.092717474Z"
}
refund_finished
{
"id": "11-0009a6-384c-69d6-accd-eb0c9d8852e7",
"event": "refund_finished",
"data": {
"id": "11-0009a6-384c-69d6-accd-eb0c9d8852e7",
"store_id": "18886460c-abc6-1cf2-add5-0f8e9e11c64e",
"charge_id": "118724a6-1d48-4a88-accd-4f1a93609236",
"status": "successful",
"amount": 100,
"currency": "JPY",
"amount_formatted": 100,
"reason": null,
"message": null,
"error": null,
"metadata": {},
"mode": "test",
"created_on": "2025-09-30T02:36:08.314626Z"
}
}
cancel_finished
{
"id": "10033f4a-f683-cc96-b301-77d51deca417",
"event": "cancel_finished",
"data": {
"id": "10033f4a-f683-cc96-b301-77d51deca417",
"charge_id": "11877f4a-ea7f-1a5e-b301-93a839636a7e",
"store_id": "11e2200c-a996-1cf2-add5-0f8e9e11c64e",
"status": "successful",
"error": null,
"metadata": {},
"mode": "test",
"created_on": "2025-10-02T04:47:56.071145Z"
}
}
Handling rules
charge_finished→ look up application bydata.metadata(application ID) → update status:successful→ payment completed (+ confirmation email, same as Stripe)failed/error→ payment failed (customer can retry)canceled→ treated as refunded (status mapping)
refund_finished/cancel_finished→ look up application bydata.charge_id→
orders.univapay_charge_id→ update status + send notification emails (same as Stripe)- Replays: record the top-level
id(orwebhook_id) — skip processing, return 200 - Cross-environment guard: validate
data.modematches the environment (test vs live) - Unknown
store_idor unmatched metadata/charge_id → log as error; never guess another application