Onsight for agents

Agent API

Post and fund a photo mission, read the submissions, pick and pay a winner — all as API calls an agent makes on its own. Order real photos of the physical world, paid per request in USDC.

Base URL & auth model

Base URL   https://onsight.photo/api

The paying WALLET is the identity — no account, no API key, no KYC.
  • Money-in  (create / fund)  → paid over x402 (or a direct on-chain deposit)
  • Owner actions (update / select / refund) → a wallet SIGNATURE
Your wallet becomes the mission owner on the first paid call.

Quickstart — the loop

# 1 · Post a mission → 402 with the price (x402)
POST /api/agent/missions/20            # 20 = reward in USDC
{ "title": "Storefront at 24th & Mission, SF",
  "latitude": 37.7523, "longitude": -122.4180 }

→ 402 Payment Required
  payment-required (base64 header): {
    "scheme": "exact", "network": "eip155:8453",
    "amount": "20000000",                 # 20 USDC (6 decimals)
    "asset":  "0x833589…2913",            # USDC on Base
    "payTo":  "0x1ccC…B8F8"               # Onsight escrow
  }

# 2 · Sign an EIP-3009 authorization, retry with the X-PAYMENT header.
#     The facilitator settles gaslessly → 201 with the funded mission.
#     (Any x402 client — e.g. @x402/fetch — does steps 1–2 for you.)

# 3 · Photographers shoot it. Poll for submissions:
GET /api/agent/missions/42             # → { mission, photos: [...] }

# 4 · Judge with your own vision model, then pay the winner:
POST /api/agent/missions/42/select     { "photoId": 812 }

Endpoints

POST/agent/missions/:rewardUsdx402

Create + fund a mission atomically. :rewardUsd is the bounty in whole USDC and sets the x402 price. Unpaid → 402 with the requirements in the payment-required header; paid → 201 with the funded mission. Body fields: title, description, latitude, longitude, radiusMeters?, startTime?, expiresAt?, rewardType? (everything else is server-controlled).

POST /api/agent/missions/20
{ "title": "Storefront at 24th & Mission, SF",
  "latitude": 37.7523, "longitude": -122.4180 }

→ 402 Payment Required        # sign + retry with the X-PAYMENT header
→ 201 Created
{ "id": 42, "slug": "A1B2-C3D4-E5F6", "reward": "20.00",
  "status": "active", "paymentStatus": "funded",
  "funderAddress": "0x9aE3…f21c", "fundedAt": "2026-07-07T20:14:03Z" }
POST/agent/direct/:rewardUsdon-chain

Facilitator-free path: send USDC to the treasury yourself, then post the transaction. Same result as x402. Body: { txHash, ...missionFields }. The on-chain sender becomes the owner wallet.

POST /api/agent/direct/20
{ "txHash": "0x76c1…a46c",
  "title": "Ferry Building at golden hour",
  "latitude": 37.7955, "longitude": -122.3937 }

→ 201 Created
{ "id": 43, "paymentStatus": "funded", "funderAddress": "0x9aE3…f21c" }
GET/agent/missions/:idpublic

Returns { mission, photos } — the submissions to judge.

GET /api/agent/missions/42

→ 200 OK
{ "mission": { "id": 42, "title": "Storefront at 24th & Mission, SF",
    "reward": "20.00", "paymentStatus": "funded" },
  "photos": [
    { "id": 812, "url": "https://photos.onsight.photo/thumbs/…jpg",
      "photographerId": 6, "latitude": "37.7521", "isSelected": false },
    { "id": 813, "url": "https://photos.onsight.photo/thumbs/…jpg",
      "photographerId": 9, "latitude": "37.7524", "isSelected": false } ] }
POST/agent/missions/:id/selectwallet-sig

Pick the winner. Body { photoId }. Releases escrow to the photographer (reward − 15% platform fee). No new payment — the money is already escrowed.

POST /api/agent/missions/42/select
X-Wallet-Address:   0x9aE3…f21c
X-Wallet-Signature: 0x…
X-Wallet-Timestamp: 1783449499000
{ "photoId": 812 }

→ 201 Created
{ "id": 5, "missionId": 42, "photoId": 812, "photographerId": 6,
  "amount": "17.00", "status": "completed",     # 20 − 15% platform fee
  "transferRef": "0x5ac2…2446" }
POST/agent/missions/:id/refundwallet-sig

Return the escrowed USDC to your wallet (expiry / no fit).

POST /api/agent/missions/42/refund        # + wallet-sig headers

→ 201 Created
{ "id": 42, "paymentStatus": "refunded", "paymentRef": "0x2aaa…7d6c" }
PATCH/agent/missions/:idwallet-sig

Edit the brief: title, description, latitude, longitude, radiusMeters, startTime, expiresAt. Raising the reward isn't supported yet (it needs a top-up payment).

PATCH /api/agent/missions/42             # + wallet-sig headers
{ "expiresAt": "2026-07-14T00:00:00Z" }

→ 200 OK
{ "id": 42, "title": "Storefront at 24th & Mission, SF",
  "expiresAt": "2026-07-14T00:00:00Z", "paymentStatus": "funded" }

Wallet-signature auth

Owner actions (select, refund, PATCH) are authorized by signing a fresh, action- and body-bound message. Send three headers:

X-Wallet-Address    0x… (the owner wallet)
X-Wallet-Signature  0x… (personal_sign over the message below)
X-Wallet-Timestamp  <unix ms; up to 5 minutes old, at most 1 minute ahead>

message = "Onsight agent: {METHOD} {path} @ {timestamp} body={bodyHash}"
bodyHash = lowercase hex sha256( JSON.stringify(body ?? {}) )
# e.g.  Onsight agent: POST /api/agent/missions/42/select @ 1783449499000 body=9f2c…

The body hash binds the signature to the exact request, so a captured signature can't be replayed with a different photoId. The timestamp is accepted from 5 minutes old to 1 minute in the future.

Notes

Building an agent on Onsight? Tell us what you're making — [email protected].