Skip to main content

Auth, Workspace, and Keys

This section covers the server-authenticated side of Hilt: account bootstrap, merchant workspace settings, OAuth, and API key management.

If you are integrating the buyer checkout itself, jump to Products and Checkout.

Authentication modes

Hilt supports two main auth patterns:

  • Dashboard and browser sessions use a JWT:
Authorization: Bearer <jwt>
  • Server-side merchant integrations use an API key:
X-Hilt-Key: hk_live_...

Use JWTs for merchant sign-in and app bootstrapping. Use API keys from your backend for operational calls once the merchant workspace is already set up.

OpenAPI and live schema discovery

The live API also exposes:

GET /v1/openapi.json
GET /v1/docs
GET /v1/redoc

Use those for live schema inspection. The docs below focus on the supported launch contract and practical examples.

Auth routes

Register

POST /v1/auth/register
Content-Type: application/json
{
"email": "merchant@example.com",
"password": "StrongPass123!",
"display_name": "Example Merchant"
}

Successful response:

{
"token": "JWT_TOKEN",
"user_id": "uuid",
"tier": "free",
"email": "merchant@example.com",
"claims": {
"hilt_score": false,
"hilt_pay": true,
"hilt_ops": false,
"is_staff": false
}
}

Common failures:

  • 409 if the email is already registered
  • 422 if the payload is invalid

Login

POST /v1/auth/login
Content-Type: application/json
{
"email": "merchant@example.com",
"password": "StrongPass123!"
}

Successful response matches the register response shape.

Common failures:

  • 401 invalid email or password
  • 403 account suspended or deleted

Wallet login

POST /v1/auth/wallet
Content-Type: application/json
{
"wallet_address": "BUYER_OR_MERCHANT_WALLET",
"signed_message": "BASE58_SIGNATURE",
"message_nonce": "ORIGINAL_NONCE"
}

This creates or resumes a wallet-backed merchant account on the free tier.

OAuth provider status

GET /v1/auth/oauth/providers

This returns whether Google and GitHub login are configured, along with their callback URLs and missing settings.

OAuth start

GET /v1/auth/oauth/google/start?mode=login&next=/dashboard
GET /v1/auth/oauth/github/start?mode=register&next=/dashboard

Successful response:

{
"provider": "google",
"callback_url": "https://app.hilt.so/api/auth/oauth/google/callback",
"authorization_url": "https://accounts.google.com/o/oauth2/v2/auth?..."
}

The callback route is browser-oriented and normally handled by the hosted app:

GET /v1/auth/oauth/{provider}/callback

Refresh and logout

POST /v1/auth/refresh
POST /v1/auth/logout

refresh reissues a JWT using the current account state, so plan or claim changes are reflected immediately.

Account bootstrap routes

These are the routes the merchant app uses to load and maintain the workspace.

Get the current workspace

GET /v1/account/me
Authorization: Bearer <jwt>

Representative response:

{
"user_id": "uuid",
"email": "merchant@example.com",
"wallet_address": null,
"display_name": "Example Merchant",
"tier": "growth",
"status": "active",
"email_verified": false,
"timezone": "UTC",
"created_at": "2026-04-14T12:00:00+00:00",
"key_id": null,
"sandbox": false,
"notification_prefs": {},
"merchant_settings": {
"checkout_brand_name": "Example Merchant",
"checkout_logo_url": "https://cdn.example.com/logo.png"
},
"claims": {
"hilt_score": false,
"hilt_pay": true,
"hilt_ops": false,
"is_staff": false
},
"has_password": true,
"auth_providers": ["google"]
}

Workspace summary

GET /v1/account/summary
Authorization: Bearer <jwt>

This returns the dashboard-level merchant snapshot:

  • active templates
  • paying members
  • renewals due
  • open support threads
  • receipts issued
  • total confirmed payments
  • asset-by-asset gross, net, and fee totals

Update workspace settings

PATCH /v1/account/me
Authorization: Bearer <jwt>
Content-Type: application/json
{
"display_name": "Example Merchant",
"timezone": "Europe/London",
"merchant_settings": {
"checkout_brand_name": "Example Merchant",
"checkout_logo_url": "https://cdn.example.com/logo.png",
"checkout_hero_image_url": "https://cdn.example.com/hero.png",
"checkout_success_button_label": "Join now",
"checkout_accent_hex": "#1d4ed8",
"default_redirect_url": "https://example.com/welcome",
"default_support_url": "https://example.com/support"
}
}

Successful response:

{
"detail": "Profile updated",
"updated_fields": ["display_name", "timezone", "merchant_settings"]
}

Update email or password

PATCH /v1/account/me/security
Authorization: Bearer <jwt>
Content-Type: application/json
{
"email": "owner@example.com",
"current_password": "OldPassword123!",
"new_password": "NewPassword123!"
}

Common failures:

  • 401 current password incorrect
  • 409 email already registered
  • 422 new password too short or no changes submitted

Delivery readiness and tests

GET /v1/account/delivery/readiness
POST /v1/account/delivery/test

Use these to verify whether a merchant’s Telegram or Discord delivery settings are ready before publishing a template.

Example test request:

{
"provider": "telegram"
}

Delete account

DELETE /v1/account/account

Note:

  • in practice this is mounted as DELETE /v1/account/account because the router is included with the /v1/account prefix
  • it soft-deletes the account and revokes active keys

API key routes

List keys

GET /v1/keys
X-Hilt-Key: hk_live_... or Authorization: Bearer <jwt>

Response items include:

  • key id
  • key prefix
  • permissions
  • sandbox flag
  • revoked state
  • usage summary
  • recent activity

Representative item:

{
"id": "uuid",
"name": "Production integration",
"key_prefix": "hk_live_",
"permissions": ["read", "execute"],
"sandbox_mode": false,
"last_used_at": "2026-04-14T11:45:00+00:00",
"created_at": "2026-04-10T09:30:00+00:00",
"revoked_at": null,
"usage_summary": {
"total_calls": 42,
"success_calls": 40,
"error_calls": 2,
"credits_burned": 0,
"latest_activity_at": "2026-04-14T11:45:00+00:00",
"latest_endpoint": "/v1/products"
},
"recent_activity": []
}

Create a key

POST /v1/keys
Authorization: Bearer <jwt>
Content-Type: application/json
{
"name": "Production integration",
"sandbox_mode": false,
"permissions": ["read", "execute"]
}

Successful response:

{
"key": {
"id": "uuid",
"name": "Production integration",
"key_prefix": "hk_live_",
"permissions": ["read", "execute"],
"sandbox_mode": false,
"last_used_at": null,
"created_at": "2026-04-14T12:00:00+00:00",
"revoked_at": null,
"usage_summary": {
"total_calls": 0,
"success_calls": 0,
"error_calls": 0,
"credits_burned": 0,
"latest_activity_at": null,
"latest_endpoint": null
},
"recent_activity": []
},
"raw_key": "hk_live_..."
}

The raw key is only shown once.

Common failures:

  • 403 if a non-staff user tries to create an admin key
  • 422 invalid permissions
  • 429 plan key limit reached

Revoke a key

DELETE /v1/keys/{key_id}
Authorization: Bearer <jwt>

Successful response: 204 No Content

For a backend integration, the clean sequence is:

  1. merchant signs in through the app
  2. merchant creates an API key
  3. your backend stores the raw key securely
  4. your backend calls product, membership, receipt, and support routes using X-Hilt-Key

Use JWTs for user-facing browser workflows. Use API keys for server automation.