High Wire Payments

Security & server verification

Protect credentials, bind payments to orders, and verify payment status on your server.

Browser credentials

Use a publishable key in the browser: hw_pk_test_… for sandbox or hw_pk_live_… for production. Keep secret API keys, HTTP Basic credentials, and other server credentials on your backend. A publishable key identifies the checkout configuration. It does not authorize access to an order or prove that a payment succeeded.

The publishable key and apiBase must belong to the same environment and account. The key does not redirect a mismatched URL. fieldsOrigin defaults to apiBase; set it only to the separate origin issued for your account. Use HTTPS for apiBase, fieldsOrigin, and the checkout page, except for localhost development.

Checkout origins

Provide HighWire with each checkout origin during onboarding. Scheme, hostname, and port matter: https://shop.example.com, https://staging.shop.example.com, and http://localhost:5173 are separate origins. Preview deployments may need separate registration.

A refused key or unregistered checkout origin can report HW_UNAUTHORIZED. Some gateway refusals are not readable by browser code and can appear as HW_NETWORK. For either error, check the full publishable key, gateway URL, account status, and registered origin before treating it as a network problem.

SDK-managed payment sessions

The mounted checkout runs its own device session and attaches the session key to its own payments. For a Direct API charge, take the key from the collector's riskSessionKey(), created with the same publishableKey and apiBase as HighWire.init(). Without the key it always resolves null; without apiBase it uses the production gateway. It resolves to a string or null. Send the string to your backend and forward it unchanged as the top-level riskSessionKey on the authorization or authorization-and-capture request. Omit the field when the value is null. See Device screening for Direct API charges.

Treat the value as optional context, not authentication or proof of payment. Do not log it or put it in URLs.

Bind and verify orders on your server

Use this sequence for every order:

  1. Before mount(), call your backend's eligibility route (the examples return canStartPayment). It must authenticate the owning account or validate a guest session scoped to the order, load the server-authoritative total and currency, and reconcile any existing payment. Start a new checkout only when the backend permits it.
  2. As soon as mount() resolves, send checkout.paymentId to the same backend and keep the checkout non-interactive until binding succeeds. A wallet or drop-in form can start payment without your Pay button.
  3. At binding time, repeat the authorization and eligibility checks. Retrieve the payment with server credentials, confirm that it belongs to your merchant, and compare it with the order's server-side amount and currency.
  4. Bind the payment and order in one transaction. Enforce unique constraints so one payment belongs to one order and one order has at most one active payment. Treat the same payment-order pair as idempotent. Reject a payment bound elsewhere, and reject replacement when the current payment is paid or unresolved. After reconciliation, create a replacement through an explicit transition that retains the earlier payment history.
  5. Fulfill only after your server verifies the bound payment's captured status, amount, and currency through GET /v1/payments/{paymentId} or a verified gateway webhook. Keep reconciling pending orders after the shopper leaves because a payment can complete later.

Browser callbacks, browser amounts, and a browser-supplied payment ID do not authorize fulfillment.

Protect same-origin binding routes

For each state-changing JSON route used by the checkout:

  • Require an Origin header that exactly matches the merchant checkout origin. Reject a missing or different origin.
  • Require Content-Type: application/json before parsing the body.
  • Apply the application's normal cookie and session policy, including its SameSite setting. If the application uses CSRF tokens, validate the token on this route too.

The same-origin JSON fetch examples in this guide omit a CSRF token because the route contract requires the exact origin and JSON content type. Add the application's token whenever its session policy requires one.

Use the Gateway authentication guide for server credentials.

Safe diagnostics

Share SDK_VERSION, browser version, timestamp, checkout origin, and HighWireError.code with support. Do not send secret credentials, card values, session or risk keys, cookies, authorization headers, or full payment request and response bodies.

On this page