Métriques du dépôt
- Stars
- (268 stars)
- Métriques de merge PR
- (Métriques PR en attente)
Description
Cashier Paddle Version
2.7.0
Laravel Version
12
PHP Version
8.4
Database Driver & Version
MySQL 8.0.19-10
Description
I am seeing a periodic failure in our sandbox environment whereby our transactions table is listing completed transactions with a status of paid and a null invoice_number despite the transaction completing successfully (and an invoice number being generated).
I think this may be caused by a race condition whereby transaction.updated overwrites the status provided by transaction.completed and have attached three notification logs which seem to support this claim.
In the example provided Paddle sends three webhook notifications in quick succession for the same transaction:
- transaction.updated (status: paid) — occurred_at: 2026-03-16T15:49:08.670618Z
- transaction.updated (status: completed) — occurred_at: 2026-03-16T15:49:10.220417Z
- transaction.completed (status: completed) — occurred_at: 2026-03-16T15:49:10.222274Z
I believe the following race condition is occurring:
- Notification 3 (
transaction.completed) creates the local transaction record with status completed - Notification 1 (transaction.updated, status paid) arrives at the handler after the record has been created, and overwrites the status back to paid
The result is a transaction stuck at paid status despite transaction.completed having been received and acknowledged with a 200 response. Replaying notification 2 (transaction.updated, status completed) via the Paddle dashboard corrects the status, confirming the issue is delivery/processing order dependent.
We have a custom listener hooked up via EventListen which successfully fired upon receipt of the transaction.completed notification, verifying that the notification arrived and was processed correctly:
Event::listen(WebhookHandled::class, PaddleHandledEventListener::class);
I'd be keen to hear if this is a configuration issue on our side or something else. Apologies if I've missed something in the documentation. Our code doesn't write or modify the transactions table in any way outside of Paddle Cashier.
Notification payloads for reference (relevant names and urls anonymised but identifiers otherwise left intact):
- transaction.updated (status: paid)
{
"event_id": "evt_01kkvncdxypqgpm6j60b57kp3g",
"event_type": "transaction.updated",
"occurred_at": "2026-03-16T15:49:08.670618Z",
"notification_id": "ntf_01kkvnce76ab69dxrvzw3gfmb8",
"data": {
"id": "txn_01kkvncb7svc6x9302fnmgn9ca",
"items": [
{
"price": {
"id": "pri_01kkh7y92t7qpfnejczb2qstz6",
"name": "Subscription",
"type": "standard",
"status": "active",
"quantity": { "maximum": 999999, "minimum": 1 },
"tax_mode": "location",
"created_at": "2026-03-12T14:41:49.14661Z",
"product_id": "pro_01kkh7s8fhc8s21zdf7bhbvmd2",
"unit_price": { "amount": "14000", "currency_code": "USD" },
"updated_at": "2026-03-13T14:25:30.083513Z",
"custom_data": null,
"description": "Subscription - Monthly",
"trial_period": null,
"billing_cycle": { "interval": "day", "frequency": 1 },
"unit_price_overrides": []
},
"quantity": 1,
"proration": null
}
],
"origin": "subscription_recurring",
"status": "paid",
"details": {
"totals": {
"fee": null,
"tax": "2333",
"total": "14000",
"credit": "0",
"balance": "0",
"discount": "0",
"earnings": null,
"subtotal": "11667",
"grand_total": "14000",
"currency_code": "USD",
"grand_total_tax": "2333",
"credit_to_balance": "0"
},
"line_items": [
{
"id": "txnitm_01kkvncb8pggz1wbrt90wmr9qf",
"totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667" },
"product": {
"id": "pro_01kkh7s8fhc8s21zdf7bhbvmd2",
"name": "Plan",
"type": "standard",
"status": "active",
"image_url": null,
"created_at": "2026-03-12T14:39:04.689Z",
"updated_at": "2026-03-12T14:39:04.689Z",
"custom_data": {
"slug": "plan_2",
"type": "plan",
"credit_amount": "400000",
"max_topup_credits_per_month": "1100000"
},
"description": null,
"tax_category": "saas"
},
"price_id": "pri_01kkh7y92t7qpfnejczb2qstz6",
"quantity": 1,
"tax_rate": "0.2",
"unit_totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667"
}
}
],
"payout_totals": null,
"tax_rates_used": [
{
"totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667" },
"tax_rate": "0.2"
}
],
"adjusted_totals": {
"fee": null,
"tax": "2333",
"total": "14000",
"earnings": null,
"subtotal": "11667",
"grand_total": "14000",
"retained_fee": "0",
"currency_code": "USD",
"grand_total_tax": "2333"
}
},
"checkout": {
"url": "https://example.com/checkout?_ptxn=txn_01kkvncb7svc6x9302fnmgn9ca"
},
"payments": [
{
"amount": "14000",
"status": "captured",
"created_at": "2026-03-16T15:49:06.042973Z",
"error_code": null,
"captured_at": "2026-03-16T15:49:08.212287Z",
"method_details": {
"card": { "type": "visa", "last4": "5556", "expiry_year": 2027, "expiry_month": 12,
"cardholder_name": "Customer" },
"type": "card",
"south_korea_local_card": null
},
"payment_method_id": "paymtd_01kkky4jk2g3p7cqr058y5n6j2",
"payment_attempt_id": "16efcbef-0d41-428e-a2c6-920d4d9f7836",
"stored_payment_method_id": "13663bc1-ae48-4316-99bb-ea165236ef70"
}
],
"billed_at": "2026-03-16T15:49:05.913853Z",
"address_id": "add_01kkkxzss20bmqjny4f96gqad7",
"created_at": "2026-03-16T15:49:05.964293Z",
"invoice_id": null,
"revised_at": null,
"updated_at": "2026-03-16T15:49:08.664472579Z",
"business_id": null,
"custom_data": { "subscription_type": "default" },
"customer_id": "ctm_01kkkxwav252thrbh9wnt577jr",
"discount_id": null,
"receipt_data": null,
"currency_code": "USD",
"billing_period": {
"ends_at": "2026-03-17T15:48:15.785146Z",
"starts_at": "2026-03-16T15:48:15.785146Z"
},
"invoice_number": null,
"billing_details": null,
"collection_mode": "automatic",
"subscription_id": "sub_01kkky4p16q20d5pvdz50ch6eh"
}
}
- transaction.updated (status: completed)
{
"event_id": "evt_01kkvncfectscx1hfy4xrs0q2t",
"event_type": "transaction.updated",
"occurred_at": "2026-03-16T15:49:10.220417Z",
"notification_id": "ntf_01kkvncg12j72575afh9b61exx",
"data": {
"id": "txn_01kkvncb7svc6x9302fnmgn9ca",
"items": [
{
"price": {
"id": "pri_01kkh7y92t7qpfnejczb2qstz6",
"name": "Subscription",
"type": "standard",
"status": "active",
"quantity": { "maximum": 999999, "minimum": 1 },
"tax_mode": "location",
"created_at": "2026-03-12T14:41:49.14661Z",
"product_id": "pro_01kkh7s8fhc8s21zdf7bhbvmd2",
"unit_price": { "amount": "14000", "currency_code": "USD" },
"updated_at": "2026-03-13T14:25:30.083513Z",
"custom_data": null,
"description": "Subscription - Monthly",
"trial_period": null,
"billing_cycle": { "interval": "day", "frequency": 1 },
"unit_price_overrides": []
},
"quantity": 1,
"proration": null
}
],
"origin": "subscription_recurring",
"status": "completed",
"details": {
"totals": {
"fee": "750",
"tax": "2333",
"total": "14000",
"credit": "0",
"balance": "0",
"discount": "0",
"earnings": "10917",
"subtotal": "11667",
"grand_total": "14000",
"currency_code": "USD",
"grand_total_tax": "2333",
"credit_to_balance": "0"
},
"line_items": [
{
"id": "txnitm_01kkvncb8pggz1wbrt90wmr9qf",
"totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667" },
"product": {
"id": "pro_01kkh7s8fhc8s21zdf7bhbvmd2",
"name": "Plan",
"type": "standard",
"status": "active",
"image_url": null,
"created_at": "2026-03-12T14:39:04.689Z",
"updated_at": "2026-03-12T14:39:04.689Z",
"custom_data": {
"slug": "plan_2",
"type": "plan",
"credit_amount": "400000",
"max_topup_credits_per_month": "1100000"
},
"description": null,
"tax_category": "saas"
},
"price_id": "pri_01kkh7y92t7qpfnejczb2qstz6",
"quantity": 1,
"tax_rate": "0.2",
"unit_totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667"
}
}
],
"payout_totals": {
"fee": "750",
"tax": "2333",
"total": "14000",
"credit": "0",
"balance": "0",
"discount": "0",
"earnings": "10917",
"fee_rate": "0.05",
"subtotal": "11667",
"grand_total": "14000",
"currency_code": "USD",
"exchange_rate": "1",
"grand_total_tax": "2333",
"credit_to_balance": "0"
},
"tax_rates_used": [
{
"totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667" },
"tax_rate": "0.2"
}
],
"adjusted_totals": {
"fee": "750",
"tax": "2333",
"total": "14000",
"earnings": "10917",
"subtotal": "11667",
"grand_total": "14000",
"retained_fee": "0",
"currency_code": "USD",
"grand_total_tax": "2333"
}
},
"checkout": {
"url": "https://example.com/checkout?_ptxn=txn_01kkvncb7svc6x9302fnmgn9ca"
},
"payments": [
{
"amount": "14000",
"status": "captured",
"created_at": "2026-03-16T15:49:06.042973Z",
"error_code": null,
"captured_at": "2026-03-16T15:49:08.212287Z",
"method_details": {
"card": { "type": "visa", "last4": "5556", "expiry_year": 2027, "expiry_month": 12,
"cardholder_name": "Customer" },
"type": "card",
"south_korea_local_card": null
},
"payment_method_id": "paymtd_01kkky4jk2g3p7cqr058y5n6j2",
"payment_attempt_id": "16efcbef-0d41-428e-a2c6-920d4d9f7836",
"stored_payment_method_id": "13663bc1-ae48-4316-99bb-ea165236ef70"
}
],
"billed_at": "2026-03-16T15:49:05.913853Z",
"address_id": "add_01kkkxzss20bmqjny4f96gqad7",
"created_at": "2026-03-16T15:49:05.964293Z",
"invoice_id": "inv_01kkvnce546j6xkngqfw0h84qj",
"revised_at": null,
"updated_at": "2026-03-16T15:49:10.214506971Z",
"business_id": null,
"custom_data": { "subscription_type": "default" },
"customer_id": "ctm_01kkkxwav252thrbh9wnt577jr",
"discount_id": null,
"receipt_data": null,
"currency_code": "USD",
"billing_period": {
"ends_at": "2026-03-17T15:48:15.785146Z",
"starts_at": "2026-03-16T15:48:15.785146Z"
},
"invoice_number": "81667-10017",
"billing_details": null,
"collection_mode": "automatic",
"subscription_id": "sub_01kkky4p16q20d5pvdz50ch6eh"
}
}
- transaction.completed (status: completed)
{
"event_id": "evt_01kkvncfeep1yg680a261n1090",
"event_type": "transaction.completed",
"occurred_at": "2026-03-16T15:49:10.222274Z",
"notification_id": "ntf_01kkvncg18kaybwrgs3zvtqr3c",
"data": {
"id": "txn_01kkvncb7svc6x9302fnmgn9ca",
"items": [
{
"price": {
"id": "pri_01kkh7y92t7qpfnejczb2qstz6",
"name": "Subscription",
"type": "standard",
"status": "active",
"quantity": { "maximum": 999999, "minimum": 1 },
"tax_mode": "location",
"created_at": "2026-03-12T14:41:49.14661Z",
"product_id": "pro_01kkh7s8fhc8s21zdf7bhbvmd2",
"unit_price": { "amount": "14000", "currency_code": "USD" },
"updated_at": "2026-03-13T14:25:30.083513Z",
"custom_data": null,
"description": "Subscription - Monthly",
"trial_period": null,
"billing_cycle": { "interval": "day", "frequency": 1 },
"unit_price_overrides": []
},
"quantity": 1,
"proration": null
}
],
"origin": "subscription_recurring",
"status": "completed",
"details": {
"totals": {
"fee": "750",
"tax": "2333",
"total": "14000",
"credit": "0",
"balance": "0",
"discount": "0",
"earnings": "10917",
"subtotal": "11667",
"grand_total": "14000",
"currency_code": "USD",
"grand_total_tax": "2333",
"credit_to_balance": "0"
},
"line_items": [
{
"id": "txnitm_01kkvncb8pggz1wbrt90wmr9qf",
"totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667" },
"product": {
"id": "pro_01kkh7s8fhc8s21zdf7bhbvmd2",
"name": "Plan",
"type": "standard",
"status": "active",
"image_url": null,
"created_at": "2026-03-12T14:39:04.689Z",
"updated_at": "2026-03-12T14:39:04.689Z",
"custom_data": {
"slug": "plan_2",
"type": "plan",
"credit_amount": "400000",
"max_topup_credits_per_month": "1100000"
},
"description": null,
"tax_category": "saas"
},
"price_id": "pri_01kkh7y92t7qpfnejczb2qstz6",
"quantity": 1,
"tax_rate": "0.2",
"unit_totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667"
}
}
],
"payout_totals": {
"fee": "750",
"tax": "2333",
"total": "14000",
"credit": "0",
"balance": "0",
"discount": "0",
"earnings": "10917",
"fee_rate": "0.05",
"subtotal": "11667",
"grand_total": "14000",
"currency_code": "USD",
"exchange_rate": "1",
"grand_total_tax": "2333",
"credit_to_balance": "0"
},
"tax_rates_used": [
{
"totals": { "tax": "2333", "total": "14000", "discount": "0", "subtotal": "11667" },
"tax_rate": "0.2"
}
],
"adjusted_totals": {
"fee": "750",
"tax": "2333",
"total": "14000",
"earnings": "10917",
"subtotal": "11667",
"grand_total": "14000",
"retained_fee": "0",
"currency_code": "USD",
"grand_total_tax": "2333"
}
},
"checkout": {
"url": "https://example.com/checkout?_ptxn=txn_01kkvncb7svc6x9302fnmgn9ca"
},
"payments": [
{
"amount": "14000",
"status": "captured",
"created_at": "2026-03-16T15:49:06.042973Z",
"error_code": null,
"captured_at": "2026-03-16T15:49:08.212287Z",
"method_details": {
"card": { "type": "visa", "last4": "5556", "expiry_year": 2027, "expiry_month": 12,
"cardholder_name": "Customer" },
"type": "card",
"south_korea_local_card": null
},
"payment_method_id": "paymtd_01kkky4jk2g3p7cqr058y5n6j2",
"payment_attempt_id": "16efcbef-0d41-428e-a2c6-920d4d9f7836",
"stored_payment_method_id": "13663bc1-ae48-4316-99bb-ea165236ef70"
}
],
"billed_at": "2026-03-16T15:49:05.913853Z",
"address_id": "add_01kkkxzss20bmqjny4f96gqad7",
"created_at": "2026-03-16T15:49:05.964293Z",
"invoice_id": "inv_01kkvnce546j6xkngqfw0h84qj",
"revised_at": null,
"updated_at": "2026-03-16T15:49:10.214506971Z",
"business_id": null,
"custom_data": { "subscription_type": "default" },
"customer_id": "ctm_01kkkxwav252thrbh9wnt577jr",
"discount_id": null,
"receipt_data": null,
"currency_code": "USD",
"billing_period": {
"ends_at": "2026-03-17T15:48:15.785146Z",
"starts_at": "2026-03-16T15:48:15.785146Z"
},
"invoice_number": "81667-10017",
"billing_details": null,
"collection_mode": "automatic",
"subscription_id": "sub_01kkky4p16q20d5pvdz50ch6eh"
}
}
Steps To Reproduce
- Setup Paddle Cashier
- Process transactions via the in-built webhook
- Observe that occasionally
transactionswill list astatusofpaiddespite the Paddle dashboard listing them as completed with a 2xx response code notification being sent in the logs