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
| Goal | Call from your server |
|---|---|
| Charge once, do not keep the card | POST /v1/charges with source: result.token (and vault_reference: result.reference). For a bank token add payment_type: "ach". |
| Save the card for later | POST /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 account | Do 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
| Endpoint | Host | Auth | Purpose |
|---|---|---|---|
POST /v1/capture-session | api.hlhunt.org (also payments.hlhunt.org/api/v1/…) | publishable key | Opens 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.org | secret or publishable key | Older 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.