Security Best Practices
Hilt’s security model is intentionally split by role:
- browsers and merchant app sessions use JWTs
- servers and automation use API keys
- provider callbacks use signed webhook secrets
- Telegram and Discord connect flows use dedicated connector credentials
The easiest way to stay safe is to keep those boundaries sharp.
Keep API keys server-side only
Treat X-Hilt-Key as a backend credential.
Best practice:
- create the key in the dashboard or merchant app
- store the raw key in a secret manager
- only use it from your backend, job runner, or support tooling
- rotate it when people or deployments change
Do not:
- embed it in browser JavaScript
- ship it inside mobile apps
- paste it into client-side analytics or support widgets
Use JWTs only for user-facing sessions
JWTs are the right choice for:
- merchant app login
- browser-side workspace actions
- account settings
- support and billing actions inside the hosted app
API keys are the right choice for:
- product automation
- membership lookup from your backend
- receipt retrieval in support tooling
- buyer handoff creation from your own bot or app
Verify webhooks against the raw body
Hilt expects provider signatures to be verified against the raw request body, not a re-serialized JSON payload.
Current webhook secrets in the Hilt stack:
helius_auth_secretforhelius-signaturestripe_webhook_secretforStripe-Signaturecheckout_telegram_webhook_secretfor Telegram’s webhook secret headerconnector_handoff_secretfor trusted connector handoff calls
If you proxy or transform incoming webhook bodies before verification, signature validation can fail.
Lock down OAuth callbacks
Keep local and production callback URLs explicit and minimal.
Best practice:
- register only the callback URLs you actually use
- separate local and production callbacks cleanly
- use the app domain for browser sign-in flows
- keep the API domain for provider callbacks that resolve on the backend
Keep connector secrets out of merchant-facing code
Telegram connect, Discord connect, and signed buyer handoff flows should be driven by:
- the shared Hilt connector flow
- a merchant-owned backend
- or a bot/app that already knows who the buyer is
The browser should never hold the secret that can mint trusted handoff tokens.
Treat payment retries carefully
For buyer-facing flows:
- keep the original
payment_id - keep the original
tx_signature - use
GET /v1/payments/{payment_id}during confirmation - only ask the buyer to pay again if the original session actually failed
This avoids duplicate payment attempts and confused support trails.
Rate limits and quotas
Hilt exposes standard rate-limit headers on /v1/* routes:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetRetry-After
Treat the headers as the source of truth instead of hard-coding assumptions in your client.
Current plan-level API key quotas from the merchant plan model:
| Plan | Max API keys |
|---|---|
| Free | 10 |
| Starter | 25 |
| Growth | 50 |
| Scale | 100 |
| Enterprise | Unlimited by default contract |
Watch key activity and rotate with intent
Hilt stores API key usage summaries and recent activity.
Use that for:
- spotting unexpected routes
- confirming whether an integration is still alive
- deciding when to revoke an old key
Good rotation moments:
- deployment changes
- contractor offboarding
- bot or worker replacement
- suspicious or unexplained activity
Prefer the app for sensitive setup
The merchant app is the safest place to:
- create keys
- configure billing
- set checkout branding
- set support and delivery defaults
The API is strongest once the workspace is already shaped correctly.
Incident posture
If something looks wrong:
- stop issuing new keys or rotate the affected one
- confirm payment state from receipts and memberships, not just wallet screenshots
- inspect support history and key activity
- re-run delivery only through the dedicated retry route
- escalate billing-only issues through Stripe history, not buyer payment records
That keeps the merchant operating trail intact while you fix the problem.