HASH PAY Docs
Docs/Reference/Authentication
API reference

Authentication

HashPay has two kinds of key and one capability rule. The split mirrors Stripe: a publishable key is safe in the browser, a secret key never leaves your server.

API keys

KeyPrefixWhere it lives
Publishablepk_test_… · pk_live_…In your front-end. Safe to expose.
Secretsk_test_… · sk_live_…Server-side only. Never ship it to a browser.

Keys are formatted <kind>_<mode>_<random>, so the prefix tells you both the kind and the mode at a glance. The mode is binding: a pk_test_ key only ever creates test data; a pk_live_ key only live.

Using a publishable key

Publishable-key endpoints (checkout) take the key in the JSON body as publishableKey, not in a header. The embed sets it for you from the script's data-pk.

POST /checkout/infojson
{ "publishableKey": "pk_live_8sd7Fk…", "priceId": "price_123" }

Origin policy

The publishable key alone resolves your store; the request's Origin is a per-store policy filter on top:

  • Live keys are blacklist-only: the only origin that's refused is one you've explicitly rejected. Unknown, pending and approved origins all transact — an unknown origin is surfaced on your store for review after it produces a confirmed payment. A valid Origin header is still required.
  • Test keys are lenient — any origin works, localhost included, so you can integrate before reviewing anything.

A copied pk_live_ can only ever create payments that settle to your wallets — and the moment a foreign domain shows up in your review queue, rejecting it shuts checkout off there. Manage domains on the Domains page.

Using a secret key

Secret-key endpoints — Checkout Sessions, plus the whole store & account management surface under /v1/stores/… — authenticate with a bearer header from your backend:

authorization headerhttp
Authorization: Bearer sk_live_2kfPqRsTuVwXyZ…

Capability access

Buyer-facing reads on a single payment — GET /payments/{id} and POST /payments/{id}/cancel — need no key at all. The unguessable pay_… id is the capability, which is what lets the widget poll status cross-origin without exposing anything sensitive. These responses contain only non-sensitive display fields.

What disables a live key

Live keys work by default. They go inert when any of these is true:

ConditionResult
Account suspended or banned403 account_disabled
Email not yet verified (email/password sign-ups)403 email_unverified
Origin's domain is rejected (blacklisted), or the Origin header is missing403 origin_not_allowed / 400 origin_required
Account's monthly volume ceiling reached (checkout create only)402 volume_cap_reached

Test keys are unaffected by the volume ceiling and email verification, and accept any origin — so your integration keeps working while you sort the above out. Full list on the Errors page.

Managing keys

Create, reveal, rotate and revoke keys on the Integration page of the dashboard.

  • Publishable keys are shown in full any time — they're not secret.
  • Secret keys are shown once at creation and then stored only as a hash; the dashboard displays a masked form afterward. Lost it? Mint a new one and revoke the old.
  • Rotating is just minting a new key and revoking the previous one; revocation takes effect immediately.