# Stripe Payments for GoCommerce — Open-Source Module

> Take cards and wallets through Stripe PaymentIntents in a GoCommerce store: two keys, the webhook URL, refunds, and what the module does not do.

- Canonical: https://kitcommerce.store/integrations/payments-stripe/
- Last updated: 2026-09-25

---

Payments

## Stripe payments for GoCommerce

A Go package that creates a Stripe PaymentIntent at checkout and marks the GoCommerce order paid when Stripe’s signed webhook says the payment succeeded. Two keys to set, one webhook URL to register, and no Stripe SDK in your build.

- **Payments** module
- **4** settings
- **6** tests
- **ext/payments-stripe**

### What it does

The module registers “stripe” as a payment method. At checkout — after the order is written, so a slow answer from Stripe never holds a database lock — it creates a PaymentIntent for the order’s total, in minor units, with automatic payment methods switched on, and hands the storefront the client secret to confirm it with.

Stripe then calls POST /api/checkout/stripe/webhook, a route the engine owns and hands to the module with the body untouched. On payment_intent.succeeded the module asks the engine to mark the order paid; on payment_intent.payment_failed, to mark the payment failed. The engine makes the transition and records the event — the module never writes to an order.

In the admin it describes itself as “Cards and wallets through Stripe PaymentIntents, with the signed webhook marking orders paid.” It speaks Stripe’s REST API over Go’s standard library rather than stripe-go: creating a PaymentIntent is one form POST and verifying a webhook is one HMAC, so, in the package’s words, the SDK would buy little and would put its whole dependency tree into every store that installs it.

### Configuration

Two settings are required: the secret key and the webhook endpoint’s signing secret. Set them in Config from your own main(), or leave Config empty and type them under Settings › Payment methods in the admin.

*Stripe module settings — 4 settings, 2 required*

| Setting | Environment variable | Required | What it does |
| --- | --- | --- | --- |
| `SecretKey` Secret key | `STRIPE_SECRET_KEY` | Yes | The secret API key — the panel’s hint reads sk_live\_… or sk_test\_…, so the key decides the mode. Sent as a bearer token; not sent to the storefront. |
| `WebhookSecret` Webhook signing secret | `STRIPE_WEBHOOK_SECRET` | Yes | The endpoint’s whsec\_… secret, used to verify the Stripe-Signature header. Required because, as the code puts it, without it any caller could mark orders paid. |
| `BaseURL` API base URL | — | No | Overrides https://api.stripe.com, for tests. Empty for production. |
| `Client` | — | No | Replaces the HTTP client, which otherwise times out after 20 seconds. Go only; not in the panel. |

The module reads its Config struct, not the environment. The variable names are the ones the package’s own example or the reference binary uses; in your own `main()` you choose where each value comes from. Where a setting has a panel label, the admin’s settings drawer can hold it too, and a value typed there wins over Config.

### Setting it up

1. **Register the webhook** — In Stripe, add an endpoint at https://your-api-host/api/checkout/stripe/webhook for payment_intent.succeeded and payment_intent.payment_failed, and copy its signing secret.
2. **Install the module** — Import it and pass stripe.New to gocommerce.New, as below — or run the reference binary with -gateways, which installs every payment module idle.
3. **Give it the keys** — Secret key and webhook signing secret, in Config or under Settings › Payment methods. A key typed into the panel counts on the next request, with no restart.
4. **Take a payment** — POST /api/checkout/stripe answers with the order and a client_action intent carrying the client_secret. The storefront confirms the payment with it; the webhook marks the order paid.

main.go

```
import (
	"os"

	"github.com/itswadesh/gocommerce/core"
	stripe "github.com/itswadesh/gocommerce/ext/payments-stripe"
)

app, err := gocommerce.New(cfg,
	stripe.New(stripe.Config{
		SecretKey:     os.Getenv("STRIPE_SECRET_KEY"),
		WebhookSecret: os.Getenv("STRIPE_WEBHOOK_SECRET"),
	}),
)
```

The package doc’s own example, with its imports; cfg is your gocommerce.Config. examples/store/main.go installs it only when STRIPE_SECRET_KEY is set, and then insists on the webhook secret. Import path `github.com/itswadesh/gocommerce/ext/payments-stripe`.

### How it works

- **One route, owned by the engine**

  Stripe calls POST /api/checkout/stripe/webhook. The engine hands the module the request body untouched, because the signature is over the exact bytes Stripe sent.

- **Signed and timed**

  Stripe-Signature’s t=…,v1=… is checked as an HMAC-SHA256 over the timestamp, a dot and the body, in constant time. A timestamp more than five minutes from now is refused as a replay, as is a missing or wrong signature (400).

- **Each event once**

  The module claims Stripe’s event id with INSERT … ON CONFLICT DO NOTHING in its own table — atomic even across several instances. A redelivered event is answered 200 and changes nothing.

- **A failed update is retried**

  If marking the order paid fails, the module releases its claim and answers 500, so Stripe’s retry finds work to do rather than a record saying it was handled.

- **Refunds keep Stripe’s id**

  A refund from the admin posts to Stripe’s refunds endpoint against the order’s PaymentIntent, for the amount asked. The refund id is recorded on the refund row; a refund Stripe marks failed comes back as an error, id included.

- **Metadata that cannot collide**

  The order id and number travel in the PaymentIntent’s metadata. Extra data the storefront sends at checkout goes in under client\_… keys, so it cannot overwrite what the webhook reads. The order’s email is passed as receipt_email.

### What it does not do

Read these before an order depends on it. No store is known to run GoCommerce in production yet, so these come from the code, not from anyone’s experience.

- **Two event types** — Only payment_intent.succeeded and payment_intent.payment_failed change an order. Every other event is acknowledged; charge.refunded is logged and nothing more.
- **Dashboard refunds are not applied** — A refund made in Stripe’s dashboard is logged, and the GoCommerce order does not change. Refund from the admin if the order and Stripe are to agree.
- **No disputes** — Disputes and chargebacks are not handled. Their events are acknowledged and ignored, so the order keeps reading as paid.
- **The storefront confirms** — The module returns a client secret, not a page. Collecting card details and confirming the PaymentIntent is the storefront’s job.
- **The store’s one currency** — The PaymentIntent is created in the store’s single settlement currency, unconverted. Which currencies and methods are offered is decided in Stripe.

FAQ

### Questions about the Stripe module

**What is the webhook URL?**

POST /api/checkout/stripe/webhook on the host that serves your GoCommerce API — a route the engine owns, so the module mounts nothing itself. Subscribe it to payment_intent.succeeded and payment_intent.payment_failed; other events are acknowledged.

**Which payment methods does it offer?**

The PaymentIntent is created with automatic_payment_methods enabled, so Stripe decides which methods to offer from your own Stripe settings. The module has no per-method code.

**How do I test it?**

Give it a test-mode secret key and the signing secret of a test-mode endpoint. The key decides the mode; the module has no separate sandbox switch.

**Can I use it without writing Go?**

Yes. The reference binary’s -gateways flag installs every payment module with an empty Config. Switch Stripe on under Settings › Payment methods and type both keys there. Your own main() is the route when the keys should come from the environment.

**Is this a Stripe partnership?**

No. The module calls Stripe’s public API with keys you supply. Stripe does not endorse GoCommerce, and no store is known to run this module in production yet.

### Source

Everything on this page is read from [`ext/payments-stripe`](https://github.com/itswadesh/gocommerce/tree/main/ext/payments-stripe) in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.Stripe is a trademark of its owner; this module talks to its public API and implies no endorsement. See [trademarks](https://kitcommerce.store/about/#trademarks).

- [ext/payments-stripe on GitHub](https://github.com/itswadesh/gocommerce/tree/main/ext/payments-stripe)
- [Stripe](https://stripe.com)
- [All GoCommerce modules](https://kitcommerce.store/integrations/)

### Try it against a store of your own

The one-command stack gives you GoCommerce’s API and admin on your own machine in minutes. Add this module to it and try it on test orders before a real one depends on it.

[Deploy in minutes](https://kitcommerce.store/#one-command) · [Read the module](https://github.com/itswadesh/gocommerce/tree/main/ext/payments-stripe) · [All integrations](https://kitcommerce.store/integrations/)
