Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Statamic Payments Laravel Package

goldnead/statamic-payments

Goldnead Statamic Payments is a Statamic addon for handling payments in your site, letting you integrate checkout flows and payment providers with your content. It aims to simplify common payment tasks for Statamic developers.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package, publish its config and migrations, then run php artisan migrate. v1.30.0 adds payments.checkout_key as a nullable unique column, so existing installations must migrate before deploying the new checkout behavior.

Configure your Mollie API key and webhook endpoint first. The webhook route must be reachable by Mollie and excluded from CSRF protection. A typical first use case is:

  1. Build a basket for the buyer.
  2. Call Checkout::start() to create or reuse an open payment.
  3. Redirect the buyer to the returned checkout URL.
  4. Let Mollie call your webhook.
  5. In the webhook, fetch the payment from Mollie and fulfil the order only when the status is paid.

Start by reading the Checkout class, MollieGateway, the PaymentGateway contract, the payments migration, and the webhook controller. The v1.30.0 upgrade path is short but mandatory: run the migration, and update any custom PaymentGateway implementation to accept the new idempotencyKey field in the createPayment() payload.

Implementation Patterns

Use Checkout::start() as the single entry point for beginning a payment. It now deduplicates repeated starts of the same basket by the same buyer within ten minutes. The deduplication key is based on address, products, quantities, discount, return URL, and payment methods. A double click therefore returns the existing open payment and checkout URL instead of creating a second Mollie payment.

Persist your own order before redirecting the buyer, and associate it with the package payment. The unique index on payments.checkout_key is the concurrency guard: two simultaneous requests for the same basket should end on one payment row. Do not rely on lockForUpdate() for this, especially on SQLite where it does nothing.

For webhook handling, let the package fetch the payment from Mollie rather than trusting the webhook body. In v1.30.0, MollieGateway::fetch() throws ProviderUnavailable for network errors, timeouts, 5xx, 429, and 408 responses. The webhook endpoint answers 503 in that case, which causes Mollie to redeliver. A 404 remains an answer and does not trigger the unavailable path.

Keep webhook work small and idempotent. Verify the payment, transition your order state once, and dispatch heavier fulfilment work to a queue. Mollie may redeliver webhooks, so fulfilment must tolerate duplicates. Use the Mollie payment ID or your own order ID as the idempotency boundary for order fulfilment.

If you implement a custom PaymentGateway, update createPayment() to handle the new idempotencyKey payload field. Send it as your provider’s idempotency header where supported, or drop it if the provider has no equivalent. Do not pass it through in the request body. For Mollie, the package maps it to the Idempotency-Key header, so retries after a lost response return the first payment instead of creating a second one.

Test the new behavior explicitly: simulate a repeated Checkout::start() call and assert one payment; simulate a ProviderUnavailable from the gateway and assert the webhook returns 503; simulate a 404 and assert it follows the normal answer path. SQLite test runs are useful because they exercise the unique-index guard without row-lock support.

Gotchas and Tips

Run php artisan migrate before deploying v1.30.0. Without payments.checkout_key, the deduplication guarantee is absent and the new unique-index behavior will fail.

The ten-minute reuse window is deliberately narrow and basket-specific. Changing the return URL, payment methods, quantities, discount, or buyer address creates a different basket and therefore a new payment. If your checkout flow mutates basket data between clicks, expect less deduplication.

The unique index is nullable, so payments created outside the checkout flow can keep a NULL key. Ensure your key generation is deterministic for the same basket and collision-resistant across different baskets.

Treat ProviderUnavailable as retryable and return 503. Do not catch it and return 200, because that stops Mollie’s redelivery and can leave a paid order unfulfilled. Conversely, a 404 is treated as an answer; log it and alert if it is unexpected, but do not turn it into a retry loop.

Because Mollie redelivers on anything but a 200, your webhook must be safe under repeated calls over the retry window. Make order fulfilment idempotent by checking current order/payment state before transitioning. Avoid doing slow external work before returning the webhook response.

Custom gateways must not leak idempotencyKey into request bodies. Some providers reject unknown fields or include them in signatures. Map it to the provider’s idempotency header or ignore it.

When debugging, log the Mollie payment ID, your order ID, checkout_key, and the idempotencyKey. Those values make duplicate-payment and redelivery issues much easier to trace. If you need to reproduce the unavailable path, use a fake PaymentGateway that throws ProviderUnavailable rather than trying to force real network failures.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings