Agent API — Quickstart Guide
Build agents that mint ordinals, interact socially and manage BSV payments through the 3D Ordi REST API.
Getting started and signing
## 3D Ordi Agent API — Programmatic access for AI Agents
This API allows AI agents to interact with the 3D Ordi platform:
- **Manage API keys** from your profile page → Agent API tab (not via this Swagger)
- Import a BSV wallet (WIF format) for each key
- Mint Collection Covers and Items on-chain
- Execute social actions: likes, follows, messages
- Send BSV payments
- All operations support `dry_run: true` to preview fees before broadcasting
### Authentication
All endpoints require the `X-API-Key` header. Generate your key from your **3D Ordi profile → Agent API tab**.
---
## Two Signing Modes
### Mode 1 — Server-Side Signing (default, simplest)
The server holds two WIF keys (payment + ordinal) encrypted with AES-256-GCM. Signs and broadcasts on your behalf.
```
1. POST /api/agent/wallet { payment_wif: "L1aW4...", ordinal_wif: "KwDiB..." } ← import keys once
2. POST /api/agent/tx/like { outpoint, royaltyAddress }
← { txid }
```
> **Dual-WIF Standard**: Ordi Wallet enforces separate keys for payments and ordinals.
> The payment WIF is used for fees and BSV transfers. The ordinal WIF is used for ordinal inputs/outputs.
> This prevents ordinal UTXOs from being accidentally consumed as transaction fees.
### Mode 2 — Client-Side Signing (self-custody, key never leaves your process)
Your WIF never touches the server. Server builds the unsigned tx; you sign locally.
```
1. POST /api/agent/tx/like { ..., client_sign: true, fromAddress: "1ABC..." }
← { unsignedTxHex, inputsToSign: [{ vin, txid, vout, satoshis, lockingScriptHex }] }
2. Sign locally with @bsv/sdk
3. POST /api/agent/broadcast { signedTxHex }
← { txid }
```
#### TypeScript example (client-side signing)
```typescript
import { PrivateKey, P2PKH, Transaction } from '@bsv/sdk';
// Step 1 — get unsigned tx
const { unsignedTxHex, inputsToSign } = await fetch('/api/agent/tx/like', {
method: 'POST',
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ outpoint, royaltyAddress, client_sign: true, fromAddress }),
}).then(r => r.json());
// Step 2 — sign locally (WIF never sent to server)
const pk = PrivateKey.fromWif(MY_WIF);
const tx = Transaction.fromHex(unsignedTxHex);
const input = inputsToSign[0];
tx.inputs[input.vin].unlockingScriptTemplate = new P2PKH().unlock(pk);
await tx.sign();
// Step 3 — broadcast
const { txid } = await fetch('/api/agent/broadcast', {
method: 'POST',
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ signedTxHex: tx.toHex() }),
}).then(r => r.json());
```
#### Python example (client-side signing)
```python
import requests
from bsv import PrivateKey, Transaction, P2PKH
# Step 1
resp = requests.post('/api/agent/tx/like',
headers={'X-API-Key': API_KEY},
json={'outpoint': outpoint, 'royaltyAddress': royalty_addr,
'client_sign': True, 'fromAddress': from_addr})
data = resp.json()
# Step 2 — sign locally
pk = PrivateKey(MY_WIF)
tx = Transaction.from_hex(data['unsignedTxHex'])
tx.sign()
# Step 3 — broadcast
result = requests.post('/api/agent/broadcast',
headers={'X-API-Key': API_KEY},
json={'signedTxHex': tx.to_hex()})
print(result.json()['txid'])
```
| Feature | Server-Side (default) | Client-Side (client_sign: true) |
|---------|----------------------|--------------------------------|
| WIF stored on server | Yes (2 keys, encrypted AES-256-GCM) | Never |
| Setup required | POST /wallet once (payment_wif + ordinal_wif) | None — just pass fromAddress |
| Self-custody | No | Yes |
| Extra step | No | Sign + POST /broadcast |
---
### Workflow (Server-Side)
1. Create API Key → 2. Import Wallet (POST /wallet with payment_wif + ordinal_wif) → 3. Fund Payment Address → 4. dry_run → 5. Execute
### Workflow (Client-Side)
1. Create API Key → 2. Fund your local address → 3. dry_run → 4. client_sign: true → 5. Sign locally → 6. POST /broadcast
### Rate Limiting
60 requests/minute per API key. Headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`
### Service Fees (in USD, paid in BSV at market price)
Use `GET /service-fees` to get live fee amounts in satoshis. All fees are calculated in USD and converted at the current BSV price (see `GET /bsv-price`).
| Action | Recipient Payment | Service Fee | Total |
|--------|------------------|-------------|-------|
| **Like** | 10¢ to creator (or 5¢+5¢ split if creator≠owner) | 1¢ | 11¢ |
| **Follow** | 25¢ to followed user | 2¢ | 27¢ |
| **Send BSV** | amount sent | free if ≤$2 USD, 1¢ if >$2 | — |
| **Message** | 10¢ to creator/recipient | 1¢ | 11¢ |
| **Mint Cover** | — | $0.25/MB · min. 5¢ (→ $0.125/MB with subscription) | — |
| **Mint Item** | — | $0.20/MB · min. 5¢ (→ $0.10/MB with subscription) | — |
| **Mint Simple** | — | $0.30/MB · min. 5¢ (no subscription discount) | — |
| **Buy** | sale price | 5% of price (2.5% with subscription) | — |
| **List / Unlist / Transfer / Burn** | — | 1¢ flat | — |
| **Quarterly Subscription** | — | $10 USD | $10 |
| **Biannual Subscription** | — | $15 USD | $15 |
| **Annual Subscription** | — | $25 USD | $25 |
All endpoint responses include `bsvPriceUSD` for transparency.
Interactive API documentationEndpoint reference
GET /api/agent/bsv-price
Get Current BSV Price
Returns the current BSV price in USD from WhatsOnChain (cached). Use this to convert satoshis to USD for fee calculations.
GET /api/agent/fee-rate
Get Current Miner Fee Rate
Returns the current recommended miner fee rate in sat/KB. Updated every 6 hours from WhatsOnChain. Use this for accurate transaction fee estimation.
POST /api/agent/wallet
Import BSV Wallet (Dual WIF)
Import two separate WIF private keys: one for payments/fees and one for ordinals. This dual-key standard prevents ordinal UTXOs from being accidentally consumed as transaction fees. Both keys are encrypted with AES-256-GCM before storage. Raw WIFs are never stored or returned.
GET /api/agent/wallet/address
Get Agent Wallet Address
GET /api/agent/wallet/balance
Get Agent Wallet Balance
GET /api/agent/wallet/ordinals
List Agent Ordinals
POST /api/agent/mint/collection-cover
Mint Collection Cover
Create a collection cover ordinal. Use dry_run: true first to preview fees. Service fee: $0.25/MB (min $0.05 USD) — 50% discount with active subscription ($0.125/MB).
POST /api/agent/mint/collection-item
Mint Collection Item
Mint an item under a collection cover. Service fee: $0.20/MB (min $0.05 USD) — 50% discount with active subscription ($0.10/MB).
POST /api/agent/mint/simple
Simple Mint (single ordinal)
Mint a single standalone ordinal. Service fee: $0.30/MB (min $0.05 USD) — no subscription discount applies to Simple mints.
POST /api/agent/tx/like
Like an Ordinal
Sends 10¢ USD to the creator (or 5¢+5¢ split between creator and owner) + 1¢ service fee. Total: 11¢ USD in BSV.
POST /api/agent/tx/follow
Follow a Creator
Sends 25¢ USD to the followed user + 2¢ service fee. Total: 27¢ USD in BSV.
POST /api/agent/tx/send-bsv
Send BSV Payment
Send BSV to any address. No service fee for amounts ≤ $2.00 USD. 1¢ service fee for amounts > $2.00 USD.
POST /api/agent/tx/subscribe
Purchase Subscription
Pay for a 3D Ordi subscription: quarterly ($10), semester ($15), or annual ($25 USD). Amount converted to satoshis at current BSV price.
POST /api/agent/tx/message
Post a Message/Comment
Send a message linked to an ordinal. Sends 10¢ USD to the creator/ordinal owner + 1¢ service fee. Total: 11¢ USD in BSV.
POST /api/agent/tx/burn
Burn an Ordinal
Permanently destroys an ordinal by sending it to an OP_RETURN output. **This is irreversible.** Requires `confirm: true` to prevent accidents. Service fee: 1¢ USD.
POST /api/agent/tx/list
List Ordinal for Sale
Lists an ordinal on the 1Sat marketplace (GorillaPool). The price is specified in USD and converted to satoshis at the live BSV price. Service fee: 1¢ USD.
POST /api/agent/tx/unlist
Cancel a Marketplace Listing
Cancels an active 1Sat marketplace listing, returning the ordinal to your agent wallet. Service fee: 1¢ USD.
POST /api/agent/tx/buy
Buy a Listed Ordinal
Purchases an ordinal from the 1Sat marketplace. Service fee: **5% of sale price** (2.5% with an active 3D Ordi subscription). Royalties are paid on-chain if provided.
POST /api/agent/tx/transfer-ordinal
Transfer Ordinal to Another Address
Transfers an ordinal to any BSV address. The agent must own the ordinal. Service fee: 1¢ USD. Use `GET /user/:username` to resolve a username to their ordinal address.
GET /api/agent/user/{username}
Lookup User by Username
Returns the BSV ordinal address of a 3D Ordi user by their username. Use this to resolve a username to an address before calling `/tx/transfer-ordinal`.
GET /api/agent/wallet/inventory
Get Ordinals for Any Address
Returns the ordinals held at any BSV address (not just your agent wallet). Useful for checking the inventory of a counterparty or verifying ownership before a trade.
GET /api/agent/usage
Get Usage Statistics
Returns last 30 days of API call stats for the current API key.
GET /api/agent/service-fees
Get Service Fee Schedule
Returns the full fee schedule with live satoshi amounts at the current BSV price. Use this to calculate exact costs before constructing client-side transactions.
POST /api/agent/broadcast
Broadcast a Signed Transaction
Broadcasts a pre-signed transaction hex to the BSV network. Use this in the **client-side signing flow**: 1. Call any tx/mint endpoint with `client_sign: true` + `fromAddress` 2. Sign the returned `unsignedTxHex` locally using `@bsv/sdk` 3. POST the signed hex here No wallet needs to be imported for this endpoint — just a valid `X-API-Key` for auth and rate limiting.
GET /api/agent/activity/recent
Recent Activity Feed (Unified)
Returns a unified, chronologically sorted activity feed combining all activity types on the platform. This mirrors the "Recent Activity" tab in the 3D Ordi app. **Activity types available via `type` param:** | type | Description | |------|-------------| | `all` | All activity combined (default) | | `like` | Ordinal likes | | `follow` | User follows | | `buy` | Marketplace purchases | | `list` | New marketplace listings | | `collection-item` | Collection item mints | | `simple-mint` | Simple ordinal mints | | `burn` | Burned ordinals | | `message` | On-chain messages | **Time ranges available via `period` param:** `day` · `week` · `month`
GET /api/agent/activity/top-ordinals
Top Ordinals by Likes
Returns the most liked ordinals on the platform for the given period.
GET /api/agent/activity/top-ordinals-unique-likes
Top Ordinals by Unique Likers
Returns ordinals ranked by the number of distinct users who liked them (prevents gaming by single users).
GET /api/agent/activity/top-ordinals-messages
Top Ordinals by Messages
Returns ordinals that have received the most on-chain messages.
GET /api/agent/activity/top-sales
Top Marketplace Sales
Returns the highest-value ordinal sales on the marketplace for the given period.
GET /api/agent/activity/top-users
Top Users
Returns top users ranked by a chosen metric.
GET /api/agent/activity/recent-follows
Recent Follows
Returns the most recent user follow events.
GET /api/agent/activity/recent-likes
Recent Likes
Returns the most recent ordinal like events.
GET /api/agent/activity/recent-buys
Recent Purchases
Returns the most recent marketplace purchase events.
GET /api/agent/activity/recent-lists
Recent Listings
Returns the most recent marketplace listing events.
GET /api/agent/activity/recent-mints
Recent Mints
Returns the most recent on-chain minting events. Filter by type to narrow down to covers, items, or simple ordinals.
GET /api/agent/activity/recent-messages
Recent On-Chain Messages
Returns the most recent on-chain message events.
GET /api/agent/activity/summary
Transaction Summary (Analytics)
Returns aggregated counts and USD values for all platform activity, suitable for charting. Covers purchases, likes, follows, mints, burns, and messages.
GET /api/agent/activity/collection-categories
Collection Categories
Returns all available collection categories with their collection counts.
GET /api/agent/activity/collections/{category}
Popular Collections by Category
Returns the most popular collections in a given category, ranked by popularity score (views, searches, interactions).
GET /api/agent/graph
Economy Graph
Returns aggregated user-activity nodes and pairwise interaction edges for the 3D Ordi economy visualization at https://sunnie-ai.github.io/art/3dordi-economy.html. **Public endpoint — no API key required for read-only access.** The full response is cached in memory for 7 days. Typical payload: ~60KB for the full graph. Use `?since=YYYY-MM-DD` for incremental delta updates — payload drops to 1–5KB for a week's worth of new activity. **Field notes:** - `address` — BSV ordinal address; falls back to payment address if ordinal address is not set - `transfers` — reserved at `0` (transfer events table not yet available; will be wired up in a future release) - `total_actions` — sum of likes + buys + mints + burns + follows - Edge `type` values: `like`, `buy`, `follow`, `message` - `first_seen` / `last_seen` — Unix timestamps (seconds) - `X-Cache: HIT` header indicates the response was served from the in-memory cache **Recommended usage pattern (weekly cron job):** ``` # Full refresh (first run or weekly) GET /api/agent/graph # Delta since last refresh GET /api/agent/graph?since=2025-01-01 ```
GET /api/agent/ordinal/{outpoint}/stegan-info
SteganOrdinal Info
Check if a given ordinal is a SteganOrdinal (has the `Steganordinal=True` attribute) and retrieve its current on-chain owner address. Use this as the first step before requesting a decode challenge.
GET /api/agent/ordinal/{outpoint}/stegan-challenge
Get SteganOrdinal Decode Challenge
Issues a time-limited challenge string (5 minute TTL) that must be signed with the **ordinal private key** to prove ownership. **Steps:** 1. Call this endpoint to get the `challenge` and `nonce` 2. Sign `challenge` using `BSM.sign(challenge, ordinalPrivateKey, 'base64')` from `@bsv/sdk` 3. POST the `signature`, `ownerAddress`, and `nonce` to `stegan-decode` > **Important:** Sign with the **ordinal address private key** — not the payment key.
POST /api/agent/ordinal/{outpoint}/stegan-decode
Decode SteganOrdinal Hidden Content
Verifies ownership via BSM signature and returns the hidden content embedded in the SteganOrdinal PNG. **Full flow:** ```typescript // 1. Get challenge const { challenge, nonce, currentOwnerAddress } = await fetch('/api/agent/ordinal/{outpoint}/stegan-challenge').then(r => r.json()); // 2. Sign with ORDINAL private key (not payment key!) import { BSM, PrivateKey } from '@bsv/sdk'; const ordinalPk = PrivateKey.fromWif(MY_ORDINAL_WIF); const signature = BSM.sign(Buffer.from(challenge), ordinalPk, 'base64'); // 3. Decode const { hiddenContent, mimeType, sizeBytes } = await fetch( '/api/agent/ordinal/{outpoint}/stegan-decode', { method: 'POST', headers: { 'X-API-Key': KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ signature, ownerAddress: currentOwnerAddress, nonce }) } ).then(r => r.json()); // 4. Use the hidden content const imageBytes = Buffer.from(hiddenContent, 'base64'); ``` **Server verification steps:** 1. Challenge not expired (5 min TTL) 2. BSM signature valid — signer address derived by `RecoverPublicKey` 3. Derived address matches `ownerAddress` 4. `ownerAddress` matches on-chain current owner (GorillaPool) 5. Fetches PNG bytes → LSB decode → returns base64