Overview
The JIL Sovereign Wallet API provides programmatic access to self-custody MPC wallet infrastructure. Users hold their own keys via MPC 2-of-3 threshold signing with WebAuthn passkeys. All transactions are signed client-side and verified on the JIL L1 ledger with SCN validator consensus (scaling toward a 14-of-20 target).
Base URLs
| Environment | Base URL |
|---|---|
| Production | https://wallet.jilsovereign.com |
| Devnet | https://devnet-wallet.jilsovereign.com |
| Local (Docker) | http://wallet-api:8002 |
Protocol
| Property | Value |
|---|---|
| Transport | HTTPS (TLS 1.3 required in production) |
| Content Type | application/json |
| Character Encoding | UTF-8 |
| Date Format | ISO 8601 (2026-02-09T14:30:00.000Z) |
| Amount Precision | String-encoded decimals (e.g. "1500.00") |
| Auth Model | JWT Bearer token + WebAuthn passkey signing |
Authentication
The Wallet API uses a two-layer authentication model. All requests require a JWT Bearer token. Transaction signing additionally requires a WebAuthn passkey challenge-response.
Bearer Token
Include the JWT token in the Authorization header with every request.
Two-Phase Transaction Signing
Sending funds uses a two-phase flow: (1) request a WebAuthn challenge via /send/options,
(2) sign with the user's passkey and submit via /send/submit. This ensures the user's
private key never leaves their device.
Passkey Management
POST /auth/passkey/register/options
Get WebAuthn registration options for creating a new passkey. Returns the challenge and public key creation parameters for the authenticator.
Response (200 OK)
POST /auth/passkey/register/verify
Verify and complete passkey registration with the attestation response from the authenticator.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
id | string | required | Credential ID from the authenticator |
rawId | string | required | Raw credential ID (base64url-encoded) |
response.clientDataJSON | string | required | Client data JSON from authenticator (base64url) |
response.attestationObject | string | required | Attestation object from authenticator (base64url) |
Response (200 OK)
POST /auth/passkey/authenticate/options
Get WebAuthn authentication options for signing in with an existing passkey.
Response (200 OK)
POST /auth/passkey/authenticate/verify
Verify the passkey assertion and issue a JWT Bearer token.
Response (200 OK)
Wallet Operations
GET /wallet/balances
Get all asset balances for the authenticated user's wallet. Returns each asset with its balance and USD value.
Response (200 OK)
POST /wallet/send/options
Get transaction intent and WebAuthn challenge for signing a payment. This is the first step of the two-phase send flow. The challenge must be signed by the user's passkey before submitting.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
to | string | required | Recipient address or @handle (e.g., "@alice.jil") |
asset | string | required | Asset symbol (e.g. JIL, USDC, wBTC-JIL) |
amount | string | required | Amount to send as decimal string (e.g. "100.00") |
memo | string | optional | Optional memo (max 256 characters) |
Response (200 OK)
POST /wallet/send/submit
Submit a signed payment transaction. Requires the transaction intent from /send/options and the signed WebAuthn credential from the user's passkey.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
txIntent | object | required | Transaction intent object from /send/options |
credential | object | required | WebAuthn assertion response from passkey signing |
Response (200 OK)
GET /wallet/transactions
Get transaction history for the authenticated wallet. Supports cursor-based pagination and filtering.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
cursor | string | optional | Cursor for pagination. Omit for first page. |
limit | integer | optional | Results per page, 1-100. Default: 25. |
asset | string | optional | Filter by asset symbol. |
Response (200 OK)
GET /wallet/wrapped-assets
List available wrapper tokens (wBTC-JIL, wETH-JIL, wUSDC-JIL) with deposit and unwrap information.
Response (200 OK)
Handle Resolution
GET /handle/resolve/{handle}
Resolve a human-readable @handle to its on-chain address. No authentication required.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
handle | string | required | Handle without @ prefix (e.g., "alice.jil") |
Response (200 OK)
POST /handle/register
Register a new @handle for the authenticated user's account.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
handle | string | required | Handle (3-20 chars, lowercase alphanumeric + underscore) |
displayName | string | optional | Display name (max 50 characters) |
Response (201 Created)
Account Recovery
Social recovery enables account access restoration through guardian approvals with a 24-hour timelock. This protects against unauthorized recovery attempts while ensuring legitimate users can always regain access.
POST /wallet/recovery/start
Initiate an account recovery ceremony. This begins the social recovery process with a 24-hour timelock. No authentication required (the user has lost access).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
accountId | string | required | Account ID to recover |
newCredentialCommitment | string | required | SHA-256 hash of the new passkey public key |
Response (201 Created)
POST /wallet/recovery/approve
Submit a guardian approval for an ongoing recovery ceremony. Each guardian signs with their Ed25519 key.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
ceremonyId | string | required | Recovery ceremony ID |
guardianId | string | required | Guardian's identifier |
guardianSignature | string | required | Ed25519 signature over the ceremony ID + new credential commitment |
Response (200 OK)
POST /wallet/recovery/finalize
Finalize recovery after the timelock expires and required approvals are met. Binds the new credential to the account and revokes all previous passkeys.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
ceremonyId | string | required | Recovery ceremony ID |
newCredential | object | required | WebAuthn attestation response for the new passkey |
Response (200 OK)
Transaction Proofs
GET /api/proof/tx/{txId}
Get a cryptographic proof receipt for a transaction. Includes the Merkle inclusion proof and SCN validator quorum signatures (target: 14-of-20 (planned Q4 2026 target)). No authentication required.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
txId | string | required | Transaction ID (e.g. tx_7f3a9b2c4e1d) |
Response (200 OK)
The threshold/signers values below reflect JIL's target validator topology (14-of-20 (planned Q4 2026 target)). Current production signer count may be lower while the SCN validator fleet is being provisioned toward this target.
Error Codes
All error responses include a JSON body with error containing code,
message, and optional details fields.
Error Response Format
HTTP Status Codes
| Status | Error Code | Description |
|---|---|---|
400 | VALIDATION_ERROR | Request body failed Zod schema validation. Check details for field-level errors. |
401 | UNAUTHORIZED | Missing, invalid, or expired JWT Bearer token. |
401 | PASSKEY_VERIFICATION_FAILED | WebAuthn assertion verification failed. |
404 | ACCOUNT_NOT_FOUND | Account ID does not exist. |
404 | HANDLE_NOT_FOUND | Handle does not exist in the registry. |
404 | TRANSACTION_NOT_FOUND | Transaction ID does not exist. |
409 | HANDLE_ALREADY_TAKEN | The requested handle is already registered. |
422 | INSUFFICIENT_BALANCE | Account does not have enough funds for the requested transfer. |
423 | TIMELOCK_NOT_EXPIRED | Recovery finalization attempted before 24-hour timelock expired. |
429 | RATE_LIMIT_EXCEEDED | Too many requests. Includes retry_after_ms field. |
Code Examples
Complete JavaScript/TypeScript examples for common wallet operations.