Grofomo API
Browse the docs

Examples use a fictional festival, summer-fest. Sign in at events.grofomo.com and they switch to your own events.

Start payment

POST/v1/events/{slug}/tickets/orders/{checkoutToken}/pay

Create the payment for a detailed order and return what Stripe.js needs to take the card on your page: the PaymentIntent's clientSecret and the publishable key to initialise Stripe with. Mount a Payment Element with the secret and confirm it; the selling tickets guide has the snippet.

The card form is Stripe's, rendered in an iframe on your page, so card numbers never touch your site or ours. The publishable key is Grofomo's platform key and is meant to be public; the client secret pays this one order and nothing else.

Calling again returns the same secret while the payment is still open, so a page reload does not create a second charge. Once the buyer has confirmed, tickets are issued when the payment is confirmed server-side, usually within a minute: poll order status until it reads completed.

On a payment plan the amount is the deposit plus the booking fee; the card is saved for the instalments. Free orders are refused here (nothing_to_pay): use complete free.

Send ?surface=webOmit it and the request is treated as coming from the mobile app, which is gated on a different visibility setting — so a perfectly live event can return 404 not_found for no visible reason.

Request

curl -sS \
  -X POST \
  -H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \
  'https://api.grofomo.com/v1/events/summer-fest/tickets/orders/YzNhMWU1ZDctOWIyZi00ZTZhLThjMGQtMmY0YjZhOGMwZTEyOjE3ODk2NDM2MDAwMDA6dGt0LWNoZWNrb3V0.ZXhhbXBsZS1zaWduYXR1cmU/pay?surface=web'

Path parameters

slugstringrequired
The event's URL slug. Globally unique. It can change if the organiser renames the event, but an old slug keeps reaching the same event, so a stored one never breaks. Example: `summer-fest`.
checkoutTokenstringrequired
The order's `checkoutToken` from the reserve response. It authorises this checkout only and expires a day after the reserve; keep it out of logs and analytics. Example: `YzNhMWU1ZDctOWIyZi00ZTZhLThjMGQtMmY0YjZhOGMwZTEyOjE3ODk2NDM2MDAwMDA6dGt0LWNoZWNrb3V0.ZXhhbXBsZS1zaWduYXR1cmU`.

Query parameters

surface'web'required
Must be `web` for a website. Omit it and you get the mobile-app surface, which is gated on a different visibility setting — so a perfectly live event can return 404. Example: `web`.

Response

200 OK
{
  "apiVersion": 1,
  "data": {
    "clientSecret": "pi_3QbXk2Hn7v1Zq9Lm0aB1cD2e_secret_Fg3Hi4Jk5Lm6No7Pq8Rs9Tu0",
    "publishableKey": "pk_live_51Hn7v1Zq9Lm0aB1cD2eFg3Hi4Jk5Lm6No7Pq8Rs9Tu0",
    "paymentIntentId": "pi_3QbXk2Hn7v1Zq9Lm0aB1cD2e"
  }
}
clientSecretstring
The PaymentIntent client secret. Pass it to `stripe.elements({ clientSecret })` and confirm with `stripe.confirmPayment`. It only ever pays this one order.
publishableKeystring
The Stripe publishable key to initialise Stripe.js with. It is Grofomo's, not the organiser's, and it is meant to be public.
paymentIntentIdstring
The Stripe PaymentIntent id, for your own records.
Generated from PaymentIntentResponse

Errors

unauthorizedHTTP 401
No key was sent and the organiser requires one — or the key is invalid, revoked, belongs to another organisation, or is scoped to a different event.
origin_not_allowedHTTP 403
Your site's domain is not on the organiser's allowed list. Browser calls only: a server sends no Origin header and is unaffected.
not_foundHTTP 404
No order for that `checkoutToken` on this event (or the token has expired), or no event with that slug on this surface.
details_requiredHTTP 409
The buyer's details have not been sent yet. Call the details endpoint first.
expiredHTTP 409
The 15-minute hold has ended. Start again from reserve.
order_not_openHTTP 409
The order is no longer `reserved`: it has been paid, completed or cancelled.
nothing_to_payHTTP 409
The order total is zero. Use complete-free.
already_processingHTTP 409
A payment on this order is mid-flight. Poll order status rather than starting another.
unavailableHTTP 409
The organiser has not finished connecting Stripe.

Notes

  • Rate limited to roughly 20 requests per minute per caller. Guidance, not a contract — see caching and rate limits.
  • Cache-Control: no-store