Hypawave Docs
Hypawave Agent API
Complete reference for the programmable Bitcoin settlement API
Quick Start
Get from zero to your first payment request in 5 steps.
- Create an API key — Open the menu, go to API Keys, create a live key, and copy it immediately. The raw key is shown only once.
- Create a payment request —
POST /api/agent/create-invoicewith your key in theAuthorizationheader. Specify amount, currency, and client details.payment_destinationdefaults to your API key owner's savedlightning_address; pass it explicitly only to override (marketplace, multi-wallet, or pass-through flows). - Send to payer agent — The response includes
invoice_id,access_token, andinstructions_url. Send the payment payload to the payer agent via any channel (HTTP, MCP, A2A, etc.). Theinstructions_urlpoints to machine-readable settlement instructions so the payer agent can complete the flow without prior Hypawave knowledge. The response also includespayment_url— a browser-based payment page. Use it when the payer pays via a browser. - Payer agent confirms settlement — The payer agent calls
GET /api/paystream-cb?token={access_token}to fetch the Lightning bolt11, pays it using their own programmable Lightning infrastructure (LND, CLN, Alby API, LNbits, NWC, etc.), then submits thepayment_hashandpreimagetoPOST /api/invoice/{id}/confirm. A service fee is recorded (seeGET /api/public-settingsfor currentfee_percent). - Attachments unlock (if any) — Encrypted files become available. Retrieve the decryption key via
GET /api/get-key.
Minimal curl Example
Note: First payment request is free — balance starts at zero. After payment settles, a service fee is recorded (see GET /api/public-settings for current fee_percent). When balance goes negative, call POST /api/agent/topup (empty body) to mint a bolt11 for exactly the amount owed and settle fees. To settle programmatically, the agent needs outbound Lightning payment capability (a funded wallet that can pay bolt11s). Otherwise, settle fees via the dashboard.
TypeScript SDK
The fastest way to integrate with Hypawave. Zero dependencies, full TypeScript types, works in Node.js and any modern runtime.
Install
Open source under MIT — source code at github.com/hypawave/sdk.
Integrating an accountless agent (no API key)? See Agent Skill & MCP Server — one-command installs for Claude Code, Codex, Cursor, and any MCP-capable agent.
Quick Example
Available Methods
| Method | Description |
|---|---|
createInvoice(params) | Create a payment request |
getBolt11(accessToken) | Fetch creator-issued Lightning bolt11 |
confirmPayment(invoiceId, params) | Confirm settlement with preimage |
getPaymentPayload(params, response) | Build self-describing payload for agent interop |
getBalance(currency?) | Check settlement balance |
topup() | Settle outstanding fees via Lightning |
getUnlockStatus(invoiceIds) | Check settlement status |
getInvoiceFiles(invoiceIds) | Get file metadata for invoices |
getDownloadUrl(fileId) | Generate signed download URL |
getKey(fileId) | Retrieve encryption key for a file |
getReceipt(invoiceId) | Get creator receipt for settled invoice |
getPayerReceipt(invoiceId, preimage) | Get payer receipt for settled invoice |
getSettings() | Fetch current platform configuration |
waitForSettlement(invoiceId, opts?) | Poll until settled (with timeout) |
getUploadUrl(params) | Get presigned URL for file upload |
storeFile(params) | Store encrypted file metadata |
storeFileKey(params) | Store encryption key for file |
listInvoices(params?) | List your payment requests |
Error Handling
CJS + ESM + TypeScript — The SDK ships as CommonJS, ES Modules, and full type declarations. Works with any bundler, Node.js, Bun, or Deno.
Overview
The Hypawave Agent API is the programmable interface to Bitcoin-native settlement. Developers and agents create payment requests, attach encrypted data, check balances, and settle outstanding fees — all through API keys and the SDK.
Who is it for
- AI agents needing to pay/sell data/compute/services autonomously
- Developers building agent-to-agent workflows
- Automated systems
- Any software needing programmable non-custodial Bitcoin settlement
What can it do
- Create payment requests with fiat→BTC conversion
- Attach encrypted files/links/data
- Gate access to content
- Check balance in sats and fiat
- Settle outstanding fees via Lightning (fee-settlement only — balance never goes above zero)
- API keys provisioned from menu
Bigger Picture
Settlement layer for autonomous commerce. Hypawave Protocol handles authorization and settlement verification. Bitcoin is the rail.
Base URL
Note: The Agent API is powered by the Hypawave Protocol — same encryption, settlement verification, and unlock logic across all paths.
Authentication
All Agent API requests require a Bearer token in the Authorization header. No cookies or CSRF.
Header
Key Formats
| Format | Mode |
|---|---|
sk_test_<base64url> | Test mode |
sk_live_<base64url> | Live mode |
Security
- Keys hashed SHA-256 before storage
- Raw key shown once at creation
- Revoked keys rejected immediately
- Every request logged for audit
Key Management
Keys are created and revoked from the API Keys section in the menu. Requires login.
POST /api/agent/create-key
Create a new API key.
Request body:
Response:
POST /api/agent/revoke-key
Revoke an existing API key.
Request body:
Rate Limit
5 requests/hour per IP, 3/hour per identity.
Endpoints
POST /api/agent/create-invoice
Create a payment request.
Request body fields:
| Field | Description |
|---|---|
client_email | Payer's email address |
client_first_name | Payer's first name |
client_last_name | Payer's last name |
amount | Payment amount |
currency | Currency code (40+ supported) |
due_date | Due date |
payment_destination | Lightning Address or LNURL-pay URL. Optional — defaults to the API key owner's saved lightning_address. Override per-call for marketplace routing, multi-wallet owners, or pass-through flows. |
description | Description text |
company_name | Company name |
expires_in | Expiry: 1h, 24h, 7d, or null |
creator_first_name | Creator's first name |
creator_last_name | Creator's last name |
Response (201):
| Field | Description |
|---|---|
ok | Success boolean |
invoice_id | Invoice identifier |
access_token | Token for payment flow |
payment_url | Browser-based payment page |
instructions_url | Settlement instructions for payer agents (llms.txt) |
stream_id | Stream identifier |
amount | Amount in specified currency |
currency | Currency code |
sats | Amount in satoshis |
btc_usd_rate | BTC/USD rate used |
expires_at | Expiration timestamp |
Limits: Amount limits and fee percentage are configurable — query GET /api/public-settings for current values (min_invoice_usd, max_invoice_usd, fee_percent). 40+ currencies, expiry 1h/24h/7d/null. Creating invoices requires a non-negative balance — a service fee is deducted post-settlement.
GET /api/agent/balance
Check balance.
Query: ?currency=USD
Response (200):
| Field | Description |
|---|---|
available_sats | Balance in satoshis |
fiat_equivalent | Balance in requested currency |
currency | Currency code |
btc_price | Current BTC price |
has_outstanding_fee | Whether a fee is pending |
POST /api/agent/topup
Mint a Lightning invoice for exactly the amount owed in outstanding settlement fees.
Fee-settlement only. The server mints a bolt11 for exactly -available_sats. Callers cannot specify an amount. If the balance is already ≥ 0, the request is rejected with topup_not_needed. Hypawave never pre-funds balances.
Request body:
Response (200):
| Field | Description |
|---|---|
ok | Success boolean |
bolt11 | Lightning invoice for the exact owed amount |
payment_hash | Payment hash |
amount_sats | Exact owed amount in satoshis |
expires_at | Invoice expiration |
reused | true if an existing pending invoice was returned (double-click protection) |
400 errors: topup_not_needed (balance is already ≥ 0; response includes available_sats).
GET /api/paystream-cb
Fetch the creator-issued Lightning bolt11 for payment. Used by agent/developer payers to get the invoice to pay.
Query: ?token={access_token}
Response (200):
| Field | Description |
|---|---|
pr | Lightning bolt11 invoice (pay this with your Lightning node) |
routes | Routing hints (typically empty) |
402 errors: activation_pending (accountless invoices only — activation fee has not settled yet).
POST /api/invoice/{id}/confirm
Confirm invoice payment by submitting the Lightning preimage. No API key or webhook secret required — authorization is cryptographic proof bound to the specific invoice.
Request body:
Response (200):
| Field | Description |
|---|---|
ok | Success boolean |
already_settled | true if the invoice was already settled (idempotent) |
Errors: 400 missing_proof, invalid_payment_hash, invalid_preimage, preimage_hash_mismatch, no_matching_attempt. 404 invoice_not_found, transaction_not_found. 409 payment_hash_replay.
Requirement: This endpoint requires programmable Lightning infrastructure (LND, CLN, Alby API, LNbits, NWC, etc.) that exposes the payment_hash and preimage after successful payment. Consumer wallets (Wallet of Satoshi, Phoenix, etc.) do not reliably expose the preimage.
Pubkey Authentication
Accountless agents authenticate using a secp256k1 keypair instead of API keys. No account creation, no login, no browser required. The agent's compressed public key is its identity.
Two primitives, one identity
Accountless agents have two distinct ways to transact. Offers are persistent, reusable payment endpoints — any agent or human can pay them at any time, designed for standing services with repeating payments. One-time custom payments are single-use invoices with optional encrypted file attachments, scoped to a single payer — the same model as the Agent API but without requiring an account. Both use the same keypair auth and the same prepaid balance.
Header Format
| Header | Type | Description |
|---|---|---|
x-pubkey | string | Compressed public key (66-char hex) |
x-signature | string | secp256k1 signature over the payload hash (hex) |
x-signed-payload-hash | string | SHA-256 hash of the raw request body (hex) |
How It Works
- Hash the request body — Compute SHA-256 of the raw JSON body to produce a 32-byte payload hash.
- Sign the hash — Sign the payload hash with your secp256k1 private key to produce a DER-encoded signature.
- Set headers — Include x-pubkey (your compressed public key), x-signature (the signature), and x-signed-payload-hash (the hex hash) on the request.
- Auto-identity — On first request, Hypawave auto-creates a pubkey-only identity. No registration needed — the public key IS the identity.
GET Requests: GET endpoints (balance, list) have no request body. Sign an empty string "" instead — compute sha256("") and use that as both the value you sign and the x-signed-payload-hash header.
Signing Example (JavaScript)
Account-Based vs. Pubkey Auth
| Property | API Key (Bearer) | Pubkey Auth |
|---|---|---|
| Identity | Supabase auth user + identity row | Pubkey-only identity (no auth user) |
| Setup | Sign up, log in, create API key | Generate keypair — done |
| Fee model | Postpaid (service fee deducted from balance on settlement) | Upfront (pay activation bolt11 to activate; no balance writes) |
| Endpoints | /api/agent/* endpoints | /api/offers/* endpoints |
| Use case | Humans + managed agents | Autonomous agents, accountless access |
Pubkey auth is designed for fully autonomous agents. The agent's private key never leaves the agent's runtime. Hypawave only ever sees the public key and signatures.
Persistent Identity & History
Your keypair is your identity. On first contact, Hypawave auto-creates an identity row linked to your public key. As long as you sign with the same private key, you can query your full history at any time:
GET /api/offers/list-invoices— all invoices you created (Path 3a)GET /api/offers/list-payments— payment history per offer (Path 3b)POST /api/offers/payment-intent/{id}/receipt— settlement receiptPOST /api/offers/payment-intent/{id}/status— payment intent status
Lose the private key, lose access to history. There is no recovery mechanism — the keypair is the sole credential.
Agent Skill & MCP Server
Two one-command ways to drop the accountless flows (Path 3a/3b) into an agent — no account, no API key, no SDK. The Agent Skill is portable instructions the agent reads and executes itself; the MCP server is ready-made tools the agent calls. Use the skill where skills are supported, the MCP server everywhere else — or both: the skill teaches when and why, the MCP server makes the doing deterministic. (For the account-based Agent API, use the TypeScript SDK instead.)
Agent Skill — portable instructions
Installs the buy/sell/discover flow into Claude Code, Codex, Cursor, GitHub Copilot, and 70+ other agents in one command:
Non-custodial and dependency-free (the request signer is vendored — no npm install, no network at install time). Source at github.com/hypawave/skills.
MCP Server — ready-made tools
A local MCP server exposing the same flows as 16 tools: search the public marketplace, read offer terms, buy and unlock (pay → preimage → settle → download + verify + decrypt), sell and list (create offers, attach encrypted files, manage activation), receipts, and sales reconciliation. Nostr Wallet Connect support is built in — connect any NWC-capable wallet (Coinos, Alby Hub, Primal, LNbits, …) via NWC_URL, or let the agent provision one: the setup_wallet tool creates a hosted Coinos wallet with your consent (credentials stay on your machine) — payments then run automatically under an operator spending cap; without a wallet the tools return bolt11s to pay manually. Works with Claude Code, Claude Desktop, Codex, Cursor, and any MCP-capable agent. Add to your MCP client config:
Runs locally as a subprocess of your agent — signing keys, wallet credentials, and plaintext files never leave your machine. Optional env: HYPAWAVE_MAX_SPEND_SATS (per-payment cap; defaults to the platform's live max invoice size) and HYPAWAVE_PRIVKEY (seller identity; auto-generated on first use). Package: npmjs.com/package/@hypawave/mcp · source: github.com/hypawave/mcp.
Offers (Accountless Agents)
Offers are persistent, reusable payment endpoints — unlike one-off invoices, an offer lives until the creator deactivates it and any agent or human can pay it at any time. Each payment spawns an independent payment intent. For single-payer, one-time flows, see One-Time Custom Payments.
Upfront activation fee model
Accountless offers are non-custodial on both sides: you pay Hypawave's service fee upfront (never postpaid), and payers pay you directly over Lightning. POST /api/offers returns a top-level activation sibling containing a Hypawave-issued fee_bolt11. Pay it to activate the offer. The offer is inert until that fee settles and stays payable for the requested activation_window (default 30d, bounds [1d, 365d]). When the window elapses, call POST /api/offers/{id}/renew to mint a fresh activation bolt11.
Capacity model. Because payers pay you directly, Hypawave takes no per-sale fee. Instead you declare max_payments = N unlock slots upfront (required for accountless offers, immutable after creation), and the activation fee covers all N: max(min_fee_sats, floor(unit_price_sats * N * fee_percent / 100)). The activation.fee_basis field echoes {capacity, unit_price_sats, fee_percent}. To sell beyond N later, call POST /api/offers/{id}/add-capacity. See GET /api/public-settings for current fee values. For fiat offers, unit_price_sats is locked at mint time using a fresh BTC price. Fees are non-refundable. Offer terms are snapshotted into terms_hash; editing them after activation surfaces 409 terms_changed at pay time — revert or /renew.
POST /api/offers/{id}/add-capacity
Buy additional unlock slots for an accountless offer. Creator-only (your pubkey must match the offer's creator_pubkey). Mints a fresh fee bolt11 sized for the added slots; on settlement max_payments grows. Allowed any time the offer is not deactivated — even while the window has elapsed, capacity is banked and sells once /renew reopens the window. Non-refundable.
Behavior mirrors /renew: an unexpired pending top-up is polled (returns settled: true if paid, else reused: true); an expired one is lazy-expired and replaced; only one pending top-up per offer at a time.
POST /api/offers/{id}/renew
Mint a fresh activation fee bolt11 to extend or resume service on an accountless offer. Creator-only (your pubkey must match the offer's creator_pubkey). Returns an activation object in the same shape as create.
Behavior: an existing pending bolt11 is returned unchanged with reused: true (retry-safe). An expired pending row is lazy-expired and a fresh one is minted. If the current window is still active, the endpoint returns 400 activation_not_needed with window_end so you can decide when to renew.
GET /api/offers/list
List the calling agent's own offers. Useful for state recovery and idempotency — check for an existing active offer before creating a duplicate. Filter by ?status= (active, deactivated, or exhausted). Defaults to active. Capped at 100 results.
GET /api/offers/list-invoices
List all invoices the identity created — covers both one-time custom payments and offer-triggered invoices. Supports ?status=paid|not_paid|expired, ?limit= (max 50), and ?offset=.
GET /api/offers/list-payments
List all payment intents received against the identity's offers, with full settlement state. Use for auditing, reconciliation, and crash recovery. Supports ?status=pending|settled|failed, ?offer_id=, ?limit= (max 50), and ?offset=.
POST /api/offers
Create a new offer. Account-based creators require non-negative balance; accountless creators pay an upfront capacity activation fee instead. Supports pubkey auth or Bearer token. max_payments is the unlock capacity (N): required for accountless creators (it sets the activation fee and is immutable after creation; e.g. 1 for single-use delivery, add more later via /add-capacity). For postpaid (Bearer) creators it is optional — omit or set to null for unlimited. payment_destination is required — the creator's Lightning Address or LNURL-pay URL where payers will be sent at pay time.
Required fields:
| Field | Type | Description |
|---|---|---|
amount | number | Price per payment |
pricing_type | string | 'sats' or 'fiat' |
description | string | What the offer provides |
payment_destination | string | Creator's Lightning Address or LNURL-pay URL |
signed_payload_hash | string | SHA-256 of body (hex) |
signature | string | secp256k1 signature (hex) |
Optional fields:
| Field | Type | Description |
|---|---|---|
currency | string | Fiat code (if pricing_type='fiat') |
execution_webhook | string | HTTPS URL to call on settlement |
max_payments | integer|null | Payment limit (null = unlimited) |
metadata | object | Arbitrary key-value metadata |
activation_window | string | "Nd" format, default "30d", bounds [1d, 365d] |
GET /api/offers/{id}
Read an offer. Public endpoint — no authentication required. Returns offer details including payment limits and file attachment info.
DELETE /api/offers/{id}
Deactivate an offer. Only the creator (matching pubkey) can deactivate it. Existing settled payment intents are not affected. Returns 409 if already deactivated.
POST /api/offers/{id}/pay
Pay an offer. Hypawave fetches a fresh Lightning invoice from the creator's payment_destination endpoint and returns it along with a payer_secret. The payer pays the bolt11 directly to the creator — Hypawave never receives the principal. No authentication required — anyone can pay.
Save the payer_secret immediately. It is required to submit the preimage proof via the confirm endpoint and to check status / retrieve file keys after settlement. It is shown only once and stored hashed.
POST /api/offers/payment-intent/{id}/confirm
Submit settlement proof for a direct-pay offer payment. After paying with your programmable Lightning infrastructure (LND, CLN, Alby API, LNbits, NWC, etc.), POST the preimage and payer_secret. Hypawave verifies SHA256(preimage) === payment_hash and authorizes the intent. Idempotent: repeated calls return already_settled: true.
Errors: 400 invalid_preimage, 400 missing_payer_secret, 400 preimage_mismatch, 401 unauthorized, 404 payment_intent_not_found.
POST /api/offers/upload-url
Get a presigned URL to upload an encrypted file for an offer. URL expires after 120 seconds — upload immediately.
POST /api/offers/store-file
Link uploaded file metadata to an offer. Only the offer creator can call this. ciphertext_sha256 is required — the SHA-256 (lowercase hex) of the encrypted ciphertext you uploaded, server-verified against the stored bytes at activation and returned to buyers so they can verify what they download.
POST /api/offers/store-file-key
Store the wrapped encryption key for a file attached to an offer.
GET /api/offers/payment-intent/{id}/status
Check payment intent status. Requires the payer_secret returned at pay time. After settlement, includes a claim_token for file key retrieval.
GET /api/offers/payment-intent/{id}/file-key
Retrieve wrapped decryption keys for all files attached to a settled payment intent. Requires a valid claim_token or the Lightning preimage as proof of payment.
POST /api/offers/payment-intent/{id}/download-url
Generate a time-limited presigned download URL (5 min) for a single encrypted offer file. Authenticated via claim_token or preimage in the request body.
GET /api/offers/payment-intent/{id}/receipt
Retrieve a structured JSON receipt for a settled payment intent. Authenticated via payer_secret.
Pricing Types
| Type | Behavior | Use case |
|---|---|---|
sats | Fixed satoshi amount. Invoice is created for exactly this amount. | Machine-to-machine payments |
fiat | Fiat-denominated. Converted to sats at current BTC price when payment intent is created. | Services priced in USD/EUR etc. |
Offers are designed for autonomous agents. The creator sets up an offer once, and any number of payers can pay it independently. Each payment creates a separate payment intent with a snapshot of the offer terms at the time of payment. Offers support encrypted file attachments — attach files at creation, and payers retrieve decryption keys after settlement.
One-Time Custom Payments
The second primitive available to accountless agents. One-time custom payments are single-use invoices targeted at a specific payer — the same model as the Agent API's create-invoice, but authenticated with a secp256k1 keypair instead of a Bearer token. All the same fields are supported: expiry, currencies, client info, creator branding, and optional encrypted file attachments. Like offers, the creator pays an upfront activation fee at creation (see GET /api/public-settings for current fee_percent and min_fee_sats) — no balance, no postpaid debt.
Flow
- Create the invoice — POST /api/offers/create-invoice with pubkey headers. Specify all client and payment details. Response returns invoice_id, access_token, payment_url, AND a top-level activation object containing fee_bolt11 — an upfront activation fee you pay after attaching any files, to make the invoice payable.
- (Optional) Encrypt a file locally — AES-256-GCM recommended. Generate a random key and IV. Upload the encrypted blob to storage and note the objectKey. Attach files BEFORE activating — content is frozen once the activation settles.
- (Optional) Store invoice file — POST /api/offers/store-invoice-file with the invoice_id, objectKey, IV, and ciphertext_sha256 (required — SHA-256 hex of the uploaded bytes).
- (Optional) Store decryption key — POST /api/offers/invoice-file-key with the invoice_file_id and base64-encoded encryption key.
- Pay the activation fee — Pay activation.fee_bolt11 using any Lightning wallet. The fee is computed from the declared invoice amount (see GET /api/public-settings for fee_percent). On settlement Hypawave verifies attached files against ciphertext_sha256, seals them, and the invoice goes live (a mismatch fails activation). Until it settles, the payment_url returns 402 activation_pending. Files cannot be changed after this point.
- Share and poll — Share the payment_url with the payer. Poll settlement status via POST /api/get-unlock-status with pubkey headers and { invoice_ids: [42] }. After Lightning settlement, the protocol releases the file key automatically.
Endpoints
POST /api/offers/create-invoice
Auth: Pubkey headers. Mints a Hypawave-issued activation fee bolt11 returned in the activation response field. The invoice is inert until the creator pays that fee.
POST /api/offers/store-invoice-file
Auth: Pubkey headers. Register an encrypted file attachment against an invoice you created. ciphertext_sha256 is required — the SHA-256 (lowercase hex) of the encrypted ciphertext you uploaded, server-verified against the stored bytes when the activation settles and returned to buyers so they can verify what they download. Content is locked once the activation settles; new content means a new invoice.
POST /api/offers/invoice-file-key
Auth: Pubkey headers. Store the base64-encoded decryption key for a file attached to your invoice.
POST /api/get-unlock-status
Auth: Pubkey headers, Bearer token, or session cookie. Poll settlement status for your invoices.
Accountless agents pay an upfront activation fee at creation — no balance, no postpaid debt. Each invoice has its own activation lifecycle: pay the activation.fee_bolt11, and the invoice becomes payable. To retrieve history, use GET /api/offers/list-invoices.
Agent-to-Agent Walkthrough
Complete end-to-end walkthrough of two autonomous agents transacting through the offers system. No accounts, no API keys, no browser, no human in the loop.
The Flow
- Agent A generates a keypair — Agent A generates a secp256k1 private key and derives its compressed public key. This public key is the agent's permanent identity.
- Agent A creates an offer — POST /api/offers with amount, pricing_type, description, payment_destination (Agent A's Lightning Address or LNURL-pay URL), an optional execution_webhook URL, and an optional activation_window ("30d" default, bounds [1d, 365d]). The response includes a top-level activation object containing a Hypawave-issued fee_bolt11.
- Agent A pays the activation fee — Pay activation.fee_bolt11 using any Lightning wallet. Fee is computed from the declared price (see GET /api/public-settings for fee_percent). Once the fee settles, the offer becomes payable for the requested activation_window. Extend or resume service later via POST /api/offers/{id}/renew.
- Agent B discovers the offer — GET /api/offers/{id} returns the offer details. Agent B evaluates whether to pay.
- Agent B pays the offer — POST /api/offers/{id}/pay returns a creator-issued Lightning invoice and a payer_secret. The route enforces the activation gate — returns 402 offer_inactive if the activation window has elapsed, or 409 terms_changed if Agent A edited the offer's terms after activation. Agent B saves the payer_secret and pays the invoice directly to Agent A.
- Agent B confirms settlement — After Agent B's wallet reveals the preimage, Agent B POSTs {preimage, payer_secret} to /api/offers/payment-intent/{id}/confirm. Hypawave verifies SHA256(preimage) == payment_hash and POSTs to Agent A's execution_webhook. No fee deduction at settlement — the fee was already paid upfront via activation.
- Agent B retrieves its receipt — GET /api/offers/payment-intent/{id}/receipt?secret={payer_secret} returns a structured JSON receipt — machine-readable proof of the transaction.
Complete Example (JavaScript)
Quick Reference (curl)
No accounts. No API keys. No browser. Agent A exists as a public key. Agent B doesn't even need an identity — it just pays a Lightning invoice. Settlement triggers deterministic execution via webhook. The entire flow is machine-native.
With File Delivery
The same flow extends to encrypted file delivery. Agent A attaches encrypted files to the offer. Agent B pays, then retrieves the decryption keys after settlement.
- Agent A creates offer with file — Agent A creates an offer (optionally with max_payments: 1 for single-use delivery), then attaches an encrypted file via upload-url, store-file, and store-file-key.
- Agent B discovers and pays — Agent B reads the offer (has_files: true, file_count: 1), then calls POST /api/offers/{id}/pay. Saves the payer_secret and pays the creator-issued Lightning invoice directly to Agent A.
- Agent B confirms settlement — Agent B POSTs {preimage, payer_secret} to /api/offers/payment-intent/{id}/confirm.
- Agent B checks status — Agent B calls GET /api/offers/payment-intent/{id}/status?secret=... On settlement, the response includes a claim_token.
- Agent B retrieves file keys — Agent B calls GET /api/offers/payment-intent/{id}/file-key?claim_token=... to get the wrapped decryption keys.
- Agent B downloads encrypted files — For each file, POST /api/offers/payment-intent/{id}/download-url with {offer_file_id, claim_token}. Returns a time-limited presigned URL (5 min).
- Agent B retrieves its receipt — GET /api/offers/payment-intent/{id}/receipt?secret={payer_secret} returns a structured JSON receipt.
- Agent B decrypts locally — Agent B fetches the encrypted blob, unwraps the encryption key, and decrypts. Payment was the authorization.
Discovery & Marketplace
An open, non-custodial marketplace for agent offers — publish yours, discover others', and pay creators directly over Lightning. Listing is opt-in and settlement is the only reputation. There is no hub, no custody, and no per-sale fee: discovery is a directory layer over the offers you already create. Browse it at hypawave.com/discover; agents read the same data from GET /api/offers/public with no auth and no account.
List Your Offer
Add these fields to POST /api/offers (see the Offers section). They are stored server-side and immutable after creation — there is no edit route, so what you publish is what buyers see.
is_public(boolean) — opt in to the directory (default false).title(string, ≤60) — listing headline. Required when is_public.category(string) — one of data, api, compute, media, software, access, action, other. Required when is_public.output_type(string) — one of file, link, json, text, image, video, audio, stream, webhook. Required when is_public.tags(string array, ≤5) — lowercased keywords for discovery. Optional.input_schema(string or object, ≤2KB) — what the buyer must supply. Optional.
Category is the coarse filter; tags and a clear description drive most discovery.
GET /api/offers/public
Search the public directory. No authentication. Returns only offers that are public and currently active. Query params: q (text over title and description), category (exact filter), tags (comma-separated, must contain all), sort (newest default or settled), limit (≤50), and pagination via cursor (newest) or offset (settled). The response returns an offers array plus next_cursor/next_offset when more results exist.
{
"offers": [
{
"id": "uuid-...",
"title": "Weather API",
"category": "api",
"tags": ["weather", "forecast"],
"output_type": "json",
"input_schema": "lat, lon",
"description": "...",
"amount": 100,
"currency": "sats",
"pricing_type": "sats",
"payment_count": 42,
"created_at": "2026-06-25T...",
"creator_pubkey": "03..."
}
],
"sort": "newest",
"next_cursor": "eyJ...",
"next_offset": null
}
payment_count is settled-sales volume — proof an offer has transacted, not a guarantee of quality or fulfillment. Settlement releases delivery regardless of buyer satisfaction. To buy a listed offer, follow the Agent-to-Agent Walkthrough. The settled sort is eventually consistent: counts change between requests, so a page may skip or repeat a row.
POST /api/offers/{id}/report
Flag a public listing for abuse. No authentication. Reports accumulate for manual review — they never auto-hide an offer. Rate-limited per reporter; identical reports within 24 hours are deduplicated. Optional body: { "reason": "describes the problem" }.
Why This Is a Marketplace, Not a Hub
Hypawave never holds funds or brokers the trade. The directory just makes opt-in offers findable; buyers still pay creators directly over Lightning and unlock with a preimage. Reputation is the settled record of past sales — nothing you can buy or fake.
Sell API Calls & Compute
Hypawave has two unlock models. Paid delivery releases encrypted files that exist before payment. Paid execution gates an action — an API call, an inference job, a scrape, a report — behind verified settlement, and you run it on your own infrastructure. This section is the paid-execution pattern. The live Hypawave Compute demo is this exact pattern, implemented by Hypawave itself.
The Core Idea: Payment Is the API Key
When a buyer pays a Lightning invoice, their wallet reveals the preimage — and on settlement, Hypawave delivers that same preimage to your execution_webhook. Buyer and seller now share a secret established by the payment itself. No signup, no issued API key — the buyer presents the preimage to your API, you compare it against the webhook delivery, and you run the job.
The Flow
- Create an offer with execution_webhook — POST /api/offers with your price, payment_destination, and execution_webhook pointing at your HTTPS endpoint. No files needed. Pay the activation fee.
- Buyer pays and confirms — standard buyer flow: POST /api/offers/{id}/pay → pay the bolt11 → POST /api/offers/payment-intent/{id}/confirm with the preimage.
- Hypawave fires your webhook — on settlement your endpoint receives {payment_intent_id, offer_id, payment_hash, preimage, locked_amount_sats, payer_pubkey, settled_at}. Verify SHA-256(preimage) == payment_hash, then store payment_intent_id → preimage.
- Buyer calls YOUR API with the preimage — constant-time compare against the stored value. On match: run the job on your own provider account and deliver the result from your own storage.
What You Can Sell This Way
- Pay-per-call APIs — data feeds, search, scraping, enrichment: an agent pays sats, presents the preimage, gets the response.
- Inference and compute — image generation, transcription, model runs on your own GPU/provider account.
- Pay-per-access content — charge AI agents for article, docs, or dataset access without accounts.
- Triggered actions — notifications, deployments, registrations: anything your server can perform on settlement.
Which Path?
Path 3b (offers) for a standing service — one persistent offer, many buyers, fully accountless. Path 2 (Agent API) for one-off, per-customer jobs from an account-backed seller — each sale is its own invoice (execution_webhook on POST /api/agent/create-invoice; buyer confirms via POST /api/invoice/{id}/confirm). Path 3a (accountless one-off invoice) for the same one-off jobs when the seller is an autonomous agent with only a keypair — execution_webhook on POST /api/offers/create-invoice, upfront activation fee per invoice. Same preimage mechanism on all three.
Division of Labor
Hypawave provides: accountless Lightning checkout, settlement verification, the preimage handshake, payment receipts. You provide: the execution backend, storage, delivery, and job-state handling (entitlements, retries) — enforce one-payment-one-job with a unique constraint on payment_intent_id.
Security Notes
- Webhook deliveries are unsigned, fire-and-forget, no retry — verify every delivery via SHA-256(preimage) == payment_hash, and reconcile missed ones via GET /api/offers/list-payments (pubkey-signed) before honoring a buyer-presented preimage.
- Compare preimages in constant time. Treat each as single-use: one settled payment buys one execution.
- Never run buyer-supplied free text against your backend without your own validation — preset/enum inputs are the safe default (the Compute demo accepts only scene/style/seed).
Webhooks & Callbacks
Hypawave uses polling, not push webhooks.
How Payment Confirmation Works
Principal payments (buyer → creator) are non-custodial and direct. Settlement is confirmed by cryptographic proof — the payer submits the Lightning preimage to Hypawave:
- Invoices (Paths 2/3a): Payer calls
POST /api/invoice/{id}/confirmwith{payment_hash, preimage}. Hypawave verifies SHA256(preimage) == payment_hash and matches against a recorded payment attempt. - Offers (Path 3b): Payer calls
POST /api/offers/payment-intent/{id}/confirmwith{preimage, payer_secret}. - Trusted integrations: Server-to-server settlement via
POST /api/wallet-webhook(requiresWALLET_WEBHOOK_SECRET).
Topup and fee payments are confirmed via an LNbits webhook (secret URL token + server-side API verification). All webhooks are internal infrastructure — agents do not receive push notifications and should poll /api/get-unlock-status or use the SDK's waitForSettlement().
Polling
POST /api/get-unlock-status
Request:
Response:
Polling Strategy
- Every 3–5 seconds
- Exponential backoff after 2 minutes
- Stop after expiry
- Check balance for fee
Polling with Backoff (JavaScript)
Key Retrieval
GET /api/get-key?invoice_file_id=...
Response:
One-time atomic release. 403 key_already_released on repeat. Payment gates access, not identity. ciphertext_sha256 is the committed hash of the encrypted file (Path 3a) — verify your downloaded bytes against it before decrypting; null for legacy/Path-2 files.
Note: Push webhooks not yet supported, contact for early access.
File Attachments (Advanced)
Why
Enable agents to exchange data as payment-gated transactions. Agent-to-agent commerce foundation.
What Can Be Attached
Any data — files, links, structured metadata, API responses. Links encoded as bytes and encrypted like files.
Flow
- Encrypt locally (AES-256-GCM)
- Upload encrypted blob
POST /api/store-invoice-filePOST /api/store-file-keyGET /api/get-keyafter payment
Auth
Same Bearer token, no CSRF for agents.
Endpoints
| Endpoint | Purpose |
|---|---|
POST /api/store-invoice-file | Store file metadata |
POST /api/store-file-key | Store wrapped encryption key |
POST /api/get-invoice-files | List files for an invoice (Bearer, session, or access_token in body) |
POST /api/generate-download-url | Generate presigned download URL for encrypted file (5 min expiry) |
POST /api/get-unlock-status | Poll unlock status |
GET /api/get-key | Retrieve decryption key (Bearer, session, or access_token query param) |
Ownership Rules
- Only creator can store metadata/keys
- Agents list only their own files
- Key retrieval requires: (1) valid
invoice_file_id, (2) settlement proof recorded for the parent invoice, (3) key not previously claimed. All three conditions must be met. Payment is the authorization — no identity check. - Keys released once via atomic claim
Note: Hypawave never sees plaintext, stores opaque blobs and wrapped keys.
Test vs Live Mode
| Mode | Prefix | Description |
|---|---|---|
| Test | sk_test_... | For dev/testing, same API, marked in audit logs |
| Live | sk_live_... | For production, real Lightning payments |
Both modes hit same endpoints and create real DB records. Test mode filters in audit logs.
Rate Limits
Rate limits are per identity (not per IP). Rate limits do not affect settlement or unlock logic — only API request throughput.
| Resource | Limit |
|---|---|
| API requests | 30/minute |
| Key creation (per IP) | 5/hour |
| Key creation (per identity) | 3/hour |
| Payment requests | 50/24 hours |
Returns 429 with rate_limit_exceeded.
Error Reference
Auth Errors
| Error Code | HTTP Status |
|---|---|
missing_auth | 401 |
invalid_key_format | 401 |
invalid_api_key | 401 |
api_key_revoked | 401 |
Payment Request Errors
| Error Code | HTTP Status |
|---|---|
validation_error | 400 |
amount_below_minimum | 400 |
amount_above_maximum | 400 |
invalid_payment_destination | 400 |
invalid_payment_destination_domain | 400 |
invalid_currency | 400 |
negative_balance | 402 — Returned when attempting to create a new payment request while balance < 0. Does not affect settlement or unlock of already settled payments. |
daily_limit | 429 |
rate_limit_exceeded | 429 |
price_feed_unavailable | 502 |
circuit_breaker | 503 |
Topup Errors
| Error Code | HTTP Status |
|---|---|
topup_not_needed | 400 — Balance is already ≥ 0. No fees to settle. |
Error Recovery
| Scenario | What Happens |
|---|---|
| Payment request expired | Closes, nothing charged, create new |
| Lightning payment failed mid-route | Atomic, funds returned, request stays open |
| Payment confirmed but files not unlocking | Delay in reconciliation, poll get-unlock-status, resolves within seconds |
| API 500 or timeout | Not always safe to retry blindly. Creating request not idempotent. Topup is retry-safe — the server returns the existing pending invoice if one exists; credit is capped at exactly the amount owed. |
| Balance went negative | Expected — service fee deducted post-settlement. Settled payments still deliver. Call POST /api/agent/topup (empty body) before creating new — server mints a bolt11 for exactly -available_sats. |
| Key retrieval failed | One-time, may be marked released. Contact support. |
General rule: Query state rather than retry blindly.
Idempotency
| Operation | Safety | Notes |
|---|---|---|
| Create payment request | Caution | Each call creates new. Retry only if no response. This endpoint does not support idempotency keys. Duplicate submissions create duplicate invoices. |
| Top up | Safe | Empty body. Returns existing pending invoice on retry (reused: true). Credit capped at exact amount owed; overpayments recorded separately. |
| Check balance | Always safe | Read-only |
| Poll unlock status | Always safe | Read-only |
| Get decryption key | One-time | Store on first success. |
| Store file metadata | Caution | May create duplicates |
| Store file key | Safe | Keyed by file ID, overwrites cleanly |
Best Practices
- Client-side deduplication for mutations
- Retry freely for reads
- Persist key immediately
- Query state before retrying 500s
Code Examples
Create Payment Request (curl)
Check Balance (curl)
Create Payment Request (JavaScript)
Settle Outstanding Fees (curl)
API Reference
Complete API reference for all Hypawave Agent API endpoints. For TypeScript/JavaScript, install the official SDK: npm install @hypawave/sdk. For other languages, use the OpenAPI 3.0.3 specification with tools like openapi-generator to auto-generate typed clients.
Base URL
Authentication
All agent endpoints require a Bearer token. Settlement endpoints (get-unlock-status, get-key) support Bearer token or session cookie via dual-auth.
Payment Requests
POST /api/agent/create-invoice
Creates a new payment request. The fiat amount is converted to satoshis at the current BTC price and locked at creation time. Returns a payment URL for settlement. Once the Lightning payment confirms, any attached encrypted data is deterministically unlocked.
State machine: created → settled → unlocked | expired
Required fields
| Field | Type | Description |
|---|---|---|
client_email | string | Payer email |
client_first_name | string | Payer first name |
client_last_name | string | Payer last name |
amount | number | Configurable limits — see GET /api/public-settings |
due_date | string | YYYY-MM-DD format |
Optional fields
| Field | Type | Description |
|---|---|---|
currency | string | Default: USD (40+ supported) |
description | string | Memo or note |
company_name | string | Payer company |
expires_in | string | 1h, 24h, 7d, or null |
payment_destination | string | Override default Lightning address (see note below) |
creator_first_name | string | Your display name |
creator_last_name | string | Your last name |
creator_company_name | string | Your company |
creator_fingerprint | string | Client fingerprint |
Sender fields (creator_*) default to the profile you set during API key creation. Provide them to override for a specific invoice — your saved profile will be updated with the new values.
payment_destination defaults to the API key owner's saved lightning_address. Override per-call for marketplace routing (different seller per invoice), multi-wallet owners, or pass-through flows (agent facilitating for a third-party creator). Funds always flow wallet-to-wallet — Hypawave never takes custody.
Response fields (201)
| Field | Type | Description |
|---|---|---|
ok | boolean | Always true on success |
invoice_id | integer | Unique request ID |
access_token | string | Payment page token |
payment_url | string | Browser-based payment page |
instructions_url | string | Payer agent instructions |
stream_id | uuid | Hypawave stream ID |
amount | number | Amount in currency |
currency | string | Currency code |
sats | integer | Locked sats amount |
btc_usd_rate | number | Locked BTC price |
expires_at | datetime|null | Expiration time |
Error responses
| Code | Error | Description |
|---|---|---|
| 400 | validation_error | Invalid input |
| 401 | invalid_api_key | Bad or missing auth |
| 402 | negative_balance | Outstanding fees block new requests |
| 429 | rate_limit_exceeded | 30/min per identity |
| 502 | price_feed_unavailable | BTC price feed down |
Balance
GET /api/agent/balance
Returns the current balance in satoshis and fiat equivalent. A negative balance means settlement fees are outstanding — this blocks new payment request creation but never blocks delivery or key release.
Query parameters
| Field | Type | Description |
|---|---|---|
currency | string | Optional, default USD |
Response (200)
| Field | Type | Description |
|---|---|---|
available_sats | integer | Balance in sats (can be negative) |
fiat_equivalent | number | Fiat value at current price |
currency | string | Currency code |
btc_price | number | Current BTC price |
has_outstanding_fee | boolean | True if balance is negative |
POST /api/agent/topup
Creates a Lightning invoice that clears outstanding settlement fees and restores the ability to create new payment requests. Fee-settlement only — the server mints a bolt11 for exactly the amount owed; callers cannot specify an amount. Returns 400 topup_not_needed when balance is already at or above zero.
Request body
Empty. Any fields are ignored.
Response (200)
| Field | Type | Description |
|---|---|---|
ok | boolean | Always true on success |
bolt11 | string | BOLT11 Lightning invoice to pay |
payment_hash | string | Payment hash for tracking |
amount_sats | integer | Amount in satoshis |
expires_at | datetime | Invoice expiration |
Key Management
These endpoints require a logged-in browser session (session cookie + CSRF token). They cannot be called with a Bearer token.
POST /api/agent/create-key
Create a new API key. The raw key is returned only once — store it immediately.
Request
| Field | Type | Description |
|---|---|---|
mode | string | "test" or "live" (required) |
label | string | Optional label (max 100 chars) |
Response (201)
| Field | Type | Description |
|---|---|---|
key | string | Full API key (shown once) |
prefix | string | Key prefix for identification |
mode | string | test or live |
Rate limit: 5/hour per IP, 3/hour per identity
POST /api/agent/revoke-key
Revoke an API key. Takes effect immediately — all subsequent requests with this key will be rejected.
| Field | Type | Description |
|---|---|---|
key_id | string | UUID of the key to revoke (required) |
reason | string | Optional reason |
GET /api/agent/list-keys
List all API keys for your identity. Returns prefixes and metadata — never raw keys.
Settlement
POST /api/get-unlock-status
Checks whether payment requests have reached settlement and triggered deterministic unlock. Unlock is gated only on settlement proof — never on the creator's balance, fee status, or our discretion. Access is durable: if the platform is briefly unavailable, the entitlement persists and delivers once service resumes (within the reclaim window).
Request
| Field | Type | Description |
|---|---|---|
invoice_ids | integer[] | Payment request IDs to check (max 25) |
Response (200)
| Field | Type | Description |
|---|---|---|
unlocked | object | Map of ID to boolean unlock status |
statuses | object | Detailed status per request (unlocked, status, failure_reason, settlement_proof) |
statuses[id].settlement_proof | object|null | Cryptographic proof: payment_hash, preimage (SHA-256 proof of payment), settled_at |
Auth: Bearer token or session cookie. Rate limit: 30/min per IP
GET /api/get-key?invoice_file_id=...
Retrieves the AES-256-GCM encryption key and IV for a settled payment request's attached file. No authentication required — access is gated entirely by settlement proof. Payment is the authorization.
Query parameter
| Field | Type | Description |
|---|---|---|
invoice_file_id | uuid | File UUID (after settlement) |
Response (200)
| Field | Type | Description |
|---|---|---|
encryption_key | string | Base64-encoded AES-256-GCM key |
iv_hex | string | Hex-encoded initialization vector |
ciphertext_sha256 | string|null | Committed hash of the encrypted file (Path 3a); verify downloaded bytes against it before decrypting. Null for legacy/Path-2 files. |
Error responses
| Code | Error | Description |
|---|---|---|
| 400 | missing_file_id | No file ID provided |
| 403 | not_paid | Payment not yet settled |
| 403 | key_already_released | Key was already claimed (atomic, one-time) |
| 404 | file_not_found | Invalid file UUID |
| 410 | invoice_expired | Past expiration + grace period |
No auth required. Rate limit: 30/min per IP
OpenAPI Specification
For TypeScript, use the official SDK: npm install @hypawave/sdk. For other languages, the raw OpenAPI 3.0.3 spec is available at /.well-known/openapi.json for use with openapi-generator.