hlhunt.js (Browser SDK)

hlhunt.js is HL Hunt's browser tokenization library. It sends card or bank details from the customer's browser straight to HL Hunt's PCI vault and gives you back a token; the number never reaches your server or HL Hunt's API servers. It is the only client-side library HL Hunt ships — there is no Node SDK, no Python SDK and no MCP server; on the server you call the REST API directly.

Load it

html

<script src="https://payments.hlhunt.org/js/hlhunt.js"></script>

The script is served only from payments.hlhunt.org. A request for the script on the API host (https://api.hlhunt.org/js/hlhunt.js, with or without a /v1 prefix) is redirected there with a 302, so an integration that derives the script URL from its API base still works.

Initialise

javascript

var hlhunt = HLHunt('pk_live_xxx');            // or pk_test_xxx
// optional: HLHunt('pk_live_xxx', { apiBase: 'https://payments.hlhunt.org' })

HLHunt throws if the key is missing or does not start with pk_live_ or pk_test_. Never put a secret key in a page. apiBase defaults to the origin the script was loaded from.

createToken(params)

Tokenizes a card. The browser first calls POST {apiBase}/api/v1/capture-session with the publishable key ({ ttl: "10m" }), then POSTs the card to the returned capture_url with the X-PCIVault-Capture-Secret header.

javascript

hlhunt.createToken({
  card: {
    number: '4242 4242 4242 4242',   // digits, spaces or dashes
    exp_month: 12,                   // 1-12
    exp_year: 2029,                  // 4-digit (2-digit is expanded)
    cvc: '123',                      // 3-4 digits
    name: 'Jenny Rosen'              // optional
  }
}).then(function (result) {
  if (result.error) { /* result.error.code, result.error.message */ return; }
  // result.token     — send to your server
  // result.reference — optional, send alongside
  // result.card      — { last4, exp_month, exp_year, brand }
});

Returns a Promise that never rejects. Success: { token, reference, card: { last4, exp_month, exp_year, brand } } where brand is detected locally (visa, mastercard, amex, discover, jcb, diners or unknown). Failure: { error: { type, code, message, param? } }.

Client-side validation errors (type: "validation_error"): missing_card, missing_card_number, missing_exp_month, missing_exp_year, missing_cvc, invalid_card_number (13–19 digits and Luhn), invalid_exp_month, card_expired, invalid_cvc. Session errors come back as the API's own error object (for example invalid_api_key, merchant_not_onboarded, vault_error). A vault rejection is { type: "card_error", code: "card_declined" }; a network failure is { type: "api_error", code: "tokenization_failed" }.

createBankToken(params)

Tokenizes a US bank account the same way (same capture session; the vault accepts bank fields on the same endpoint).

javascript

hlhunt.createBankToken({
  bank_account: {
    routing_number: '021000021',   // 9 digits
    account_number: '9876543210',  // 4-17 digits
    account_type: 'checking',      // 'checking' | 'savings'
    account_holder: 'Jenny Rosen'  // optional
  }
}).then(function (result) {
  // result.token, result.reference,
  // result.bank_account: { last4, account_type, routing_last4 }
});

Validation errors: missing_bank_account, invalid_routing_number, invalid_account_number, invalid_account_type. A vault rejection is { type: "bank_error", code: "bank_tokenization_failed" }.

What to do with the token

GoalCall from your server
Charge once, do not keep the cardPOST /v1/charges with source: result.token (and vault_reference: result.reference). For a bank token add payment_type: "ach".
Save the card for laterPOST /v1/payment-methods with type: "card", payment_token: result.token, token_reference: result.reference, card: result.card, optional customer_id. Charge the returned id later.
Save a bank accountDo not tokenize it in the browser; send routing and account numbers from your server to POST /v1/payment-methods with type: "bank_account" so the microdeposit verification flow applies.

A token is derived from the card itself, so the same card always produces the same token. Tokens made with a pk_test_ key live in the sandbox vault and only work with sk_test_ keys.

The endpoints behind the library

EndpointHostAuthPurpose
POST /v1/capture-sessionapi.hlhunt.org (also payments.hlhunt.org/api/v1/…)publishable keyOpens the vault capture endpoint hlhunt.js uses. Returns capture_url, capture_secret, capture_id, expires_at, key_user, livemode.
POST /api/tokenize/session (legacy)payments.hlhunt.org or api.hlhunt.orgsecret or publishable keyOlder flow. Returns tokenizeUrl, tokenSecret, tokenSecretHeader (X-Tokenize-Secret), expiresAt; the browser POSTs card fields to tokenizeUrl with that header and receives { token, reference }. Still served, but new integrations should use hlhunt.js.

Older pages described only the legacy /api/tokenize/session flow with its camelCase field names; both flows end in the same token and the same POST /v1/payment-methods call.

Embedded and popup checkout

A second script, https://payments.hlhunt.org/js/hlhunt-checkout.js, mounts a Checkout Session inside your page or opens it as a popup. It takes a session's session_key, not a card. See the Embedded Checkout and Popup Checkout guides.