# Clover integration in Go (GoCommerce module)

> Take card payments through Clover’s Hosted Checkout in a GoCommerce store: three keys, the webhook URL, refunds, USD or CAD, and what the module leaves out.

- Canonical: https://kitcommerce.store/integrations/payments-clover/
- Last updated: 2026-10-28

---

Payments

## Clover integration in Go

A Go package that sends the shopper to Clover’s Hosted Checkout page for the order’s total and marks the GoCommerce order paid when Clover’s signed webhook says the payment was approved. Card numbers never reach the store, and there is no Clover SDK in your build.

- **Payments** module
- **8** settings
- **16** tests
- **ext/payments-clover**

### What it does

The module registers “clover” as a payment method. At checkout it creates a Hosted Checkout session for the order’s total and answers with a redirect intent carrying the session’s URL. The shopper types their card on Clover’s page and comes back to the return URL — which, in the package’s words, proves nothing: the signed webhook is what settles the order.

The order goes to Clover as one line for its total, with tips switched off. The engine has already worked out tax, shipping and discounts, and Clover would otherwise apply its own; Clover also refunds part of a payment only when the payment was one line with no tax or tip, so this is what makes a partial refund possible.

A Hosted Checkout session carries no currency and no reference of the store’s. So the module is told the merchant account’s currency, USD or CAD, and refuses an order in any other rather than charge 2500 Canadian cents for 2500 US ones; and it keeps its own table from session to order, with the amount each session asked for. The package notes that Hosted Checkout is offered in the United States and Canada only.

### Configuration

Three settings are required: the merchant ID, the Ecommerce private token and the webhook signing secret. Set them in Config from your own main(), or leave Config empty and type them under Settings › Payment methods in the admin.

*Clover module settings — 8 settings, 3 required*

| Setting | Environment variable | Required | What it does |
| --- | --- | --- | --- |
| `MerchantID` Merchant ID | `CLOVER_MERCHANT_ID` | Yes | The Clover merchant the payments go to, sent as the X-Clover-Merchant-Id header. The panel’s hint: from the Clover dashboard’s address bar or Account & Setup. |
| `PrivateToken` Ecommerce private token | `CLOVER_PRIVATE_TOKEN` | Yes | The merchant’s Ecommerce API private token, from Settings › Ecommerce › Ecommerce API Tokens in the Clover dashboard. Sent as a bearer token; not sent to the storefront. |
| `WebhookSecret` Webhook signing secret | `CLOVER_WEBHOOK_SECRET` | Yes | The Hosted Checkout signing secret. Required because, as the code puts it, without it any caller could mark orders paid. |
| `Currency` Account currency | — | No | USD or CAD; USD by default. Clover charges in the account’s own currency, so an order in any other is refused before a session is made. |
| `ReturnURL` Return URL | — | No | Where the shopper lands after paying, when the checkout sends no return_url of its own. It must be https: Clover sends the shopper back to nothing else, and the module refuses the checkout otherwise. |
| `Sandbox` Sandbox | — | No | Points the module at apisandbox.dev.clover.com, with a test merchant’s own token and secret. |
| `BaseURL` API base URL | — | No | Overrides https://api.clover.com, and the sandbox switch, for tests. Empty for production. It must be a public address: a private or loopback one is refused unless the install sets GOCOMMERCE_ALLOW_PRIVATE_URLS. |
| `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. **Set the webhook in Clover** — In the Clover dashboard, under Settings › Ecommerce › Hosted Checkout, set the webhook URL to https://your-api-host/api/checkout/clover/webhook and generate the signing secret.
2. **Install the module** — Pass clover.New to gocommerce.New, as below, or run the reference binary with -gateways, which installs every payment module idle.
3. **Give it the keys** — Merchant ID, private token, signing secret and the account’s currency, in Config or under Settings › Payment methods, with a return URL if the storefront sends none.
4. **Take a payment** — POST /api/checkout/clover answers with a redirect intent whose url is Clover’s Hosted Checkout page. The PAYMENT webhook marks the order paid.

main.go

```
import (
	"os"

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

app, err := gocommerce.New(cfg,
	clover.New(clover.Config{
		MerchantID:    os.Getenv("CLOVER_MERCHANT_ID"),
		PrivateToken:  os.Getenv("CLOVER_PRIVATE_TOKEN"),
		WebhookSecret: os.Getenv("CLOVER_WEBHOOK_SECRET"),
	}),
)
```

The package doc’s own example, with its imports; cfg is your gocommerce.Config. With an empty clover.Config the module installs idle and waits for the panel, which is how examples/store/main.go and the reference binary install it. Import path `github.com/itswadesh/gocommerce/ext/payments-clover`.

### How it works

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

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

- **Signed and timed**

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

- **The session’s amount is the check**

  The webhook carries no amount, so the module compares the amount and currency its session asked for with the order’s. An order whose total changed since is logged as an error and not settled, for an operator who can see both sides.

- **Each outcome once**

  A decline and then an approval can arrive for one session, so the claim is on the payment and its outcome, in the module’s own table with ON CONFLICT DO NOTHING. A redelivery is answered 200 and changes nothing; a decline arriving after the approval leaves the order paid.

- **A failed update is retried**

  If marking the order paid or failed does not go through, the module releases its claim and answers 500, so Clover’s retry finds work to do.

- **Refunds, whole or in part**

  A refund from the admin posts to Clover’s refunds endpoint against the payment id the webhook recorded, for the amount asked. Clover’s refund id is kept; a refund Clover marks failed or cancelled comes back as an error with its reason.

### 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.

- **USD and CAD only** — Hosted Checkout is offered in the United States and Canada, and charges in the merchant account’s currency. The store’s settlement currency has to be that one; any other order is refused at checkout.
- **The return proves nothing** — The shopper’s return to the storefront does not settle the order. Until the webhook arrives the order reads unpaid, and an order with no working webhook stays that way.
- **A changed total waits for a person** — An approved payment whose session asked for a different amount or currency than the order now holds is acknowledged and not applied. The order stays unpaid until an operator reconciles it.
- **Refunds need the webhook first** — Until the webhook records Clover’s payment id, the order holds only the checkout session, which Clover cannot refund; the module says so rather than try.
- **Dashboard refunds and disputes** — The module acts on PAYMENT notifications only. A refund made in Clover’s dashboard, or a dispute, does not change the GoCommerce order.
- **Nothing travels with the session** — Extra data the storefront sends at checkout is not passed to Clover: a Hosted Checkout session has nowhere to carry it. The order’s email goes as the customer’s.

FAQ

### Questions about the Clover module

**What is the webhook URL?**

POST /api/checkout/clover/webhook on the host that serves your GoCommerce API — a route the engine owns, so the module mounts nothing itself. Set it in the Clover dashboard under Settings › Ecommerce › Hosted Checkout, where the signing secret is generated.

**Does the shopper leave the storefront?**

Yes. Checkout answers with a redirect to Clover’s Hosted Checkout page, where the card is typed, so card numbers never reach the store. Clover then sends the shopper back to the return URL, which has to be https.

**How do I test it?**

Switch on Sandbox, which points the module at apisandbox.dev.clover.com, and give it a test merchant’s ID, token and signing secret — Clover issues those separately. The module’s own tests answer in Clover’s place with a local test server; none calls Clover.

**Can I sell in euros or pounds?**

No. Hosted Checkout is offered in the United States and Canada, and the module accepts USD or CAD as the account’s currency, refusing an order in any other.

**Is this a Clover partnership?**

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

### Related modules

Each is a directory under `ext/`, imported the same way. Where this one fits in the store: [Checkout and payments in GoCommerce](https://kitcommerce.store/features/checkout/).

- [Creem integration in Go Sell through Creem as merchant of record from a GoCommerce store: the placeholder product, keys, webhook URL, full-only refunds and the module’s limits.](https://kitcommerce.store/integrations/payments-creem/)
- [Helcim integration in Go Take card payments through Helcim’s HelcimPay.js in a GoCommerce store: API token, verifier token, webhook URL, refunds, and what the module leaves out.](https://kitcommerce.store/integrations/payments-helcim/)
- [Hyperswitch integration in Go Route payments through Hyperswitch, the open-source payments router, from a GoCommerce store: keys, payment links, webhook URL, refunds and limits.](https://kitcommerce.store/integrations/payments-hyperswitch/)
- [Lemon Squeezy integration in Go Sell through Lemon Squeezy as merchant of record from a GoCommerce store: the placeholder variant, four settings, webhook URL, refunds and limits.](https://kitcommerce.store/integrations/payments-lemonsqueezy/)

### Source

Everything on this page is read from [`ext/payments-clover`](https://github.com/itswadesh/gocommerce/tree/main/ext/payments-clover) in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.Clover 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-clover on GitHub](https://github.com/itswadesh/gocommerce/tree/main/ext/payments-clover)
- [Clover](https://www.clover.com)
- [All GoCommerce modules](https://kitcommerce.store/integrations/)

### Try it against a store of your own

The backend + admin quick start runs GoCommerce’s API and admin on your own machine, without a storefront. Add this module to it and try it on test orders before a real one depends on it.

[Backend + admin quick start](https://kitcommerce.store/#one-command) · [Read the module](https://github.com/itswadesh/gocommerce/tree/main/ext/payments-clover) · [All integrations](https://kitcommerce.store/integrations/)
