Wallet Keys

Fetch the protectedSymmetricKey needed for wallet payouts.

POST /api/wallet/keys

Returns the user's protectedSymmetricKey and email. You'll pass protectedSymmetricKey in every POST /api/wallet/payout request.

Call this endpoint once per user and cache both values in your database. They only change if the user resets their PIN.

Gated by feature flag. Requires the WALLET_PAYOUT_API per-user feature flag. Without it the endpoint responds 403. Contact Hodle to enable it.

How the PIN is established

Hodle wallets are non-custodial: the wallet mnemonic is encrypted with a symmetric key that is itself protected by the user's wallet PIN. Hodle never stores the PIN in plaintext — a payout works only because you pass the PIN back per request, and the server uses it to transiently decrypt and sign.

Because of this, the PIN must be established before a payout-capable wallet exists — it cannot be minted by the API out of thin air:

  1. The account holder sets a wallet PIN on the Hodle platform (web/app onboarding). This creates the first PIN-protected wallet and its protectedSymmetricKey.
  2. To create an additional payout-capable wallet (e.g. a second network) through the API, call POST /api/wallet/create with a walletPin field. The endpoint verifies that walletPin matches the PIN already registered on the platform, then provisions the wallet under that same PIN.
    • If the user has no PIN registered on the platform, the call fails: This user has no wallet PIN registered on the platform.... Establish the PIN first.
    • If walletPin does not match: walletPin does not match the PIN registered on the platform (403).
  3. POST /api/wallet/create without walletPin still creates a legacy server-custodial wallet — but that wallet has no protectedSymmetricKey, so /api/wallet/keys returns 404 for it and it cannot be used for payouts.

The walletPin you pass to /api/wallet/payout and /api/wallet/transfer is this same platform PIN.

PIN format

Six digits. That is what the Hodle platform asks the account holder for, so it is what these endpoints expect. Collect six digits in your UI.

The API validates only that walletPin is a non-empty string — it has no way to compare against the PIN the user chose, only to try it. A four-digit value is therefore not rejected by the schema; it simply fails to unlock the wallet and comes back as 400 Invalid PIN.

Rate limit

1 request per minute per API key. Hitting the limit responds 429 with a Retry-After header.

Request

The body is empty. The user is identified from the API key.

curl --request POST \
  --url https://api.hodle.com.br/api/wallet/keys \
  --header "Authorization: Bearer $API_KEY" \
  --header "Accept: application/json"
const res = await fetch('https://api.hodle.com.br/api/wallet/keys', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.HODLE_API_KEY}`,
    Accept: 'application/json',
  },
})
const data = await res.json()
import os, requests

res = requests.post(
    "https://api.hodle.com.br/api/wallet/keys",
    headers={
        "Authorization": f"Bearer {os.environ['HODLE_API_KEY']}",
        "Accept": "application/json",
    },
)
data = res.json()

Response

200 OK
{
  "success": true,
  "data": {
    "protectedSymmetricKey": "AoofiKHyVRLvdrknnXzoIh1Gd1YTwLaOBn4ibm103a4dpwHZA36dU9DiiZdDvQmNn...",
    "email": "[email protected]"
  }
}
FieldTypeDescription
data.protectedSymmetricKeystringPass this in POST /api/wallet/payout body.
data.emailstringThe user's email — keep alongside the key in your records.

Errors

403 Forbidden — feature flag disabled
{ "success": false, "error": "WALLET_PAYOUT_API feature flag is not enabled for this user" }
404 Not Found — wallet missing
{ "success": false, "error": "Wallet not found" }
404 Not Found — wallet has no PIN-protected key
{ "success": false, "error": "Wallet has no protected symmetric key" }

A Wallet has no protected symmetric key response means the user's default wallet was created without a PIN (e.g. via /api/wallet/create with no walletPin). See How the PIN is established.

429 Too Many Requests
{ "success": false, "error": "Too many requests. Retry in 47 seconds" }

When to refetch

Almost never. Re-fetch only if:

  • You don't have the value cached yet for this user.
  • A previous payout returned Invalid PIN despite the user typing correctly — could mean the user reset their PIN and your cache is stale.