Skip to main content
A hosted checkout reports its result through the payer’s browser. GroGov redirects the payer to your return_url or cancel_url and adds the result as query parameters, signed with the portal’s signing secret. When the payer presses Done on the receipt, they go to your return_url with:
Here the items came to 100.00andtheservicefeewas100.00 and the service fee was 3.00, so amount_cents is 10300.

Cancelled

When the payer cancels on the checkout page, they go to your cancel_url with intent_id, reference_id, status=cancelled, and sig. The checkout can no longer be paid. If the payer reopens its link, they see an empty checkout with no line items; start a new checkout if they want to pay.

Failed to start

When the request to start a checkout fails, no checkout exists. The payer goes to your cancel_url with error=validation_error, detail=<code>, and sig, or to the GroGov error page. See Errors for the codes.

What is not reported today

  • You hear about a payment only if the payer presses Done. If they close the receipt page instead, nothing reaches your return_url, even though the payment succeeded.
  • Nothing is sent when a checkout expires or a card is declined. A declined payer can try again on the same page; an expired link simply stops working.
  • amount_cents includes the service fee. Compare it with your item total plus the fee, not with the item total alone.
Treat a missing result as unknown, not as unpaid. Do not ask the payer to pay again only because no result arrived. Contact GroGov support to confirm a payment’s status.

Verifying the signature

Verify sig before you act on a result. Anyone can type a URL with status=paid in it, but only GroGov has the portal’s signing secret. The signature is a hex HMAC-SHA256, keyed with the portal’s signing secret, of the result’s parameters:
  1. Take the parameters GroGov added, except sig. Your own query parameters on the address are not signed. GroGov’s parameters are intent_id, reference_id, transaction_id, status, amount_cents, error, and detail, whichever are present. Do not use these names in your own return_url or cancel_url.
  2. Sort them by name.
  3. Join them as name=value pairs with &, using the decoded values.
  4. Compute the HMAC-SHA256 of that text with the signing secret, as lowercase hex.
  5. Compare it with sig using a constant-time comparison.
A result without a sig, or with one that does not match, is unverified. Results carry no timestamp yet, so you cannot reject an old result by its age. Record each intent_id you have processed and ignore repeats.

Worked example

With this signing secret (an example, not a real one):
and a payer returning to https://partner.example.com/checkout/return?order=42, the browser arrives at:
order is yours, so it is left out. The other parameters, sorted and joined, are the text to sign:
Its HMAC-SHA256 with the secret is 26dcd59a32e0af4e1f4b6dbfed67927d29c4f4fc534e54825a7e0fed03763fbe, which matches sig.
On your return page, pass the full URL the browser requested, including the query string. Once the signature checks out, match reference_id to your record and check amount_cents before you mark it paid.