Skip to content

Hosted checkout overview

The end-to-end flow for handing a customer to Topiic's PCI-safe card-capture page and receiving them back via webhook.

Hosted checkout is the recommended way to onboard a paying customer. Your product handles the “Subscribe” click; Topiic handles the rest — contact confirmation, secure card capture, and provisioning of the member + payment method + subscription. You get a signed webhook when it’s done.

The card number never touches your server, so you stay out of PCI scope.

A successful hosted checkout produces three things on Topiic’s side:

  1. A Member (created or updated from the contact details).
  2. A PaymentMethod with the card token from the gateway.
  3. An active Subscription on the merchant’s chosen Plan, billed against that payment method.

The checkout.completed webhook fires once all three exist. Topiic does not wait for the first charge to clear before firing — if a trial period is configured the first charge may be days away.

If anything fails, checkout.failed fires with a failureReason.

sequenceDiagram
    autonumber
    participant U as User browser
    participant S as Your server
    participant T as Topiic
    participant G as Gateway

    U->>S: Click "Subscribe"
    S->>S: Build signed deep link (HMAC)
    S-->>U: 303 redirect → /c?d=…&s=…
    U->>T: GET /c?d=…&s=…
    T->>T: Verify HMAC, mint session JWT
    U->>T: Confirm contact details
    T->>G: Init capture
    G-->>T: Iframe URL
    U->>G: Enter card in gateway iframe
    G-->>T: Card token
    T->>T: Create Member + PaymentMethod + Subscription, enqueue webhook
    T-->>U: 303 redirect → ret URL
    U->>S: GET ret URL?status=ok
    T-)S: Webhook POST (signed)
    S->>S: Verify signature, mark customer subscribed

The numbers map to the steps in the Quickstart.

https://pay.topiic.com/c?d=<base64url(payload)>&s=<base64url(HMAC-SHA256(secret, d))>

The payload identifies:

  • Which integration (akid — your API key id) — Topiic uses this to find the signing secret to verify the signature.
  • Which merchant + plan (mid, plan).
  • Who the customer is on your side (ref) — echoed in the webhook so you can match.
  • Optional prefill contact (contact) — pre-fills the contact form so the user only confirms.
  • Where to send them back (ret).
  • Which events to subscribe to (evts).
  • Replay protection (nonce — single-use; exp — Unix timestamp expiry).

See Signing deep links for the full schema, signing algorithm, and code samples.

When the browser hits pay.topiic.com/c, Topiic verifies the HMAC, checks that the merchant + plan are valid, confirms the link hasn’t expired, and rejects any nonce that’s already been used. If anything fails the user sees a friendly error page and your server is not notified.

A breakdown of the possible error responses — useful when you’re testing your link builder — lives in the deep-link signing reference.

  1. Contact step — prefilled from contact in the payload; user confirms or edits.
  2. Payment step — the secure card-capture form. The card never touches Topiic — it’s tokenised by the payment gateway directly from the browser.
  3. Completion — brief “Activating your subscription…” then redirect to ret.

If the user clicks Cancel, the session ends and a checkout.failed webhook fires.

The hosted page uses Topiic’s brand colours and merchant name. Per-merchant theming (custom logo / accent colour) is on the roadmap but not in v1.

  • Don’t parse the ret URL’s ?status= to decide whether the customer is subscribed. The webhook is the source of truth — the return URL is a UX cue and can be reached even when provisioning failed.
  • Don’t poll any Topiic endpoint waiting for the subscription to appear. Use the webhook.
  • Don’t mint a deep link in browser JavaScript. The signing secret must stay server-side.
  • Don’t reuse a nonce. Generate a fresh random value (≥16 bytes) for every link.