Skip to content

Commit dcb9f74

Browse files
ktamas77claude
andcommitted
Onsight API: open-source docs + x402 agent example
Ground-truth photo API for AI agents and humans. Documents the x402 agent channel (pay USDC per photo order on Base), the wallet-signature owner-action auth, and the human web flow. Includes a runnable x402-fetch agent order example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 parents  commit dcb9f74

8 files changed

Lines changed: 314 additions & 0 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules/
2+
.env
3+
.env.*
4+
*.log
5+
.DS_Store

CONTRIBUTING.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Contributing to Onsight API
2+
3+
Thanks for taking the time. This repo is the **public documentation and examples**
4+
for the Onsight API — the service itself lives at [onsight.photo](https://onsight.photo).
5+
Contributions here are about making the API easier to use.
6+
7+
## What to open an issue about
8+
9+
- **Docs that are wrong or unclear** — an endpoint, header, or payment step that
10+
doesn't match what the API actually does. Include the request you sent and the
11+
response you got (redact wallet keys and signatures).
12+
- **Broken examples** — if [`examples/`](examples/) doesn't run, tell us your Node
13+
version, the command you ran, and the full error.
14+
- **API bugs** — unexpected status codes, wrong prices in a `402`, settlement or
15+
payout problems. Include the mission id and, if payment-related, the on-chain
16+
`txHash` (public info, safe to share).
17+
- **Questions about integrating** — how to call it from your agent framework,
18+
language, or wallet setup. No such thing as a dumb one.
19+
20+
## Requesting an API feature
21+
22+
Open an issue titled `[feature] ...` and cover:
23+
24+
- **The job to be done** — what your agent or app is trying to accomplish.
25+
- **Why the current API can't** — the missing endpoint, field, filter, or payment mode.
26+
- **A sketch of the shape** — the request/response you'd want, if you have one in mind.
27+
28+
Concrete use cases move fastest. "My agent needs to filter open missions by radius"
29+
beats "please add filtering".
30+
31+
## Pull requests
32+
33+
For docs and examples in this repo, PRs are welcome:
34+
35+
1. Fork and branch.
36+
2. Keep changes focused — one fix or example per PR.
37+
3. If you touch [`examples/`](examples/), make sure it still runs
38+
(`cd examples && npm install && node <file>`).
39+
4. Open the PR with a short description of what and why.
40+
41+
## Security
42+
43+
Found a vulnerability — in the payment flow, escrow, or wallet-signature auth?
44+
**Don't open a public issue.** See [SECURITY.md](SECURITY.md).
45+
46+
## Code of conduct
47+
48+
Be decent. Assume good faith, keep it about the work, and help newcomers.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 squidcode
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Onsight API
2+
3+
**Photo infrastructure for AI agents and humans.** Onsight lets you commission a
4+
real, verified, geotagged photo of a specific place at a specific time — and pay
5+
for it per request. An AI agent can't walk outside and photograph a storefront,
6+
a parking lot, or a shelf. Onsight is the API that can.
7+
8+
Live at **[onsight.photo](https://onsight.photo)**.
9+
10+
---
11+
12+
## What Onsight is
13+
14+
Onsight is a crowdsourced ground-truth photography marketplace:
15+
16+
- A **requester** posts a *mission* — "photograph the queue outside this address,
17+
today, from the street" — and funds a reward in USDC.
18+
- Local **photographers** nearby fulfill it and submit photos.
19+
- The requester picks a winner; the escrowed reward pays out on-chain.
20+
21+
There are **two front doors onto the same rail**:
22+
23+
| Requester | How they order | How they pay |
24+
|---|---|---|
25+
| **Human** | web UI at [onsight.photo](https://onsight.photo) | direct USDC deposit (card on-ramp available) |
26+
| **AI agent** | `POST /agent/missions` | **[x402](https://x402.org)** — pays USDC per call, no account, no key |
27+
28+
Same escrow, same photographer supply, same payout. Only how the order is placed
29+
and paid differs.
30+
31+
## Why agents need it
32+
33+
Agents are good at reasoning over data they're given and terrible at the physical
34+
world. They can't verify a place is real, open, busy, or gone. Onsight closes that
35+
gap: one paid API call returns a fresh, geotagged photograph taken by a real person
36+
on the ground. It's a ground-truth sensor for the physical world, priced per photo.
37+
38+
## How agent payment works (x402)
39+
40+
[x402](https://x402.org) is the "HTTP 402 Payment Required" standard — the server
41+
answers a paid request with a `402` and a price, the client pays inline and retries.
42+
No signup, no API key: **the agent's wallet _is_ the account.**
43+
44+
```
45+
1. Agent → POST /agent/missions?rewardUsd=20 (mission body, no payment)
46+
2. Onsight → 402 Payment Required { price: $20 USDC, payTo: treasury, network: Base }
47+
3. Agent → signs an EIP-3009 authorization, retries with an X-PAYMENT header
48+
4. Onsight → verifies + settles USDC on-chain → mission created & funded (escrow)
49+
returns the mission + the settlement txHash
50+
```
51+
52+
Settlement runs through a standard x402 **facilitator** (x402.org on testnet,
53+
Coinbase CDP on mainnet) — Onsight runs no extra chain infrastructure. Payment is
54+
on **[Base](https://base.org)** in **USDC**.
55+
56+
> **x402 gates money _in_. A wallet signature gates every owner action.**
57+
58+
Once a mission is funded, the agent proves ownership of subsequent actions (edit the
59+
brief, pick a winner, refund) by signing a request with the same wallet — no more
60+
payments, since the money is already escrowed.
61+
62+
## API surface
63+
64+
Base URL: `https://onsight.photo`
65+
66+
| Agent action | Endpoint | Auth |
67+
|---|---|---|
68+
| Post + fund a mission (place a photo order) | `POST /agent/missions?rewardUsd=N` | **x402** (payment = escrow funding) |
69+
| Read a mission + submitted photos | `GET /agent/missions/:id` | public |
70+
| Update brief / extend dates | `PATCH /agent/missions/:id` | wallet signature |
71+
| Pick + pay a winner | `POST /agent/missions/:id/select` `{ photoId }` | wallet signature |
72+
| Refund / cancel | `POST /agent/missions/:id/refund` | wallet signature |
73+
74+
**Wallet-signature auth** (owner actions): send `X-Wallet-Address`,
75+
`X-Wallet-Signature`, and `X-Wallet-Timestamp`, signing the message
76+
77+
```
78+
Onsight agent: {METHOD} {path} @ {timestamp} body={sha256(body)}
79+
```
80+
81+
The signature is action-, time-, and body-bound (5-minute window), so a captured
82+
`select` signature can't be replayed with a swapped `photoId`.
83+
84+
## Quick start
85+
86+
Get a `402` quote for a $20 photo mission — no wallet required to see the price:
87+
88+
```bash
89+
curl -i -X POST "https://onsight.photo/agent/missions?rewardUsd=20" \
90+
-H "Content-Type: application/json" \
91+
-d '{
92+
"title": "Storefront at 123 Market St",
93+
"description": "Street-level photo of the entrance, taken today in daylight.",
94+
"lat": 37.7897,
95+
"lng": -122.3972,
96+
"radiusMeters": 150
97+
}'
98+
# → HTTP/1.1 402 Payment Required
99+
# → body describes price, payTo (treasury), asset (USDC), and network (Base)
100+
```
101+
102+
To actually place and fund the order, an agent signs the payment and retries with an
103+
`X-PAYMENT` header. The full runnable flow — using [`x402-fetch`](https://www.npmjs.com/package/x402-fetch)
104+
so payment is handled automatically — is in
105+
**[`examples/x402-agent-order.js`](examples/x402-agent-order.js)**.
106+
107+
Buying as a human? See **[`examples/human-order.md`](examples/human-order.md)**.
108+
109+
## Examples
110+
111+
- [`examples/x402-agent-order.js`](examples/x402-agent-order.js) — an agent places and
112+
funds a photo order via x402, then reads it back.
113+
- [`examples/human-order.md`](examples/human-order.md) — walkthrough for human buyers.
114+
115+
## Status
116+
117+
The USDC escrow rail is live on Base mainnet; the x402 agent channel is rolling out.
118+
Endpoints and payloads here track the public API — if something drifts,
119+
[open an issue](../../issues).
120+
121+
## License
122+
123+
[MIT](LICENSE) © squidcode

SECURITY.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Security Policy
2+
3+
Onsight moves real money (USDC escrow on Base) and authenticates owner actions with
4+
wallet signatures. If you find a vulnerability in the payment flow, escrow, refund,
5+
or signature-auth logic, we want to hear from you.
6+
7+
## Reporting
8+
9+
**Do not open a public issue for security vulnerabilities.**
10+
11+
- Email **security@onsight.photo**, or
12+
- Use GitHub's [private vulnerability reporting](../../security/advisories/new).
13+
14+
Please include enough to reproduce: the request, the response, and (for
15+
payment/settlement issues) the on-chain `txHash` — which is public and safe to share.
16+
Do **not** include private keys or signatures from a real funded wallet.
17+
18+
We'll acknowledge within a few business days and keep you posted on the fix. Please
19+
give us a reasonable window to patch before any public disclosure.

examples/human-order.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Ordering a photo as a human
2+
3+
You don't need a crypto wallet, an agent, or the API to buy a photo on Onsight.
4+
The web app wraps the same escrow rail the agent API uses.
5+
6+
## Steps
7+
8+
1. **Go to [onsight.photo](https://onsight.photo)** and start a new mission.
9+
2. **Describe what you need.** A good brief is specific:
10+
- *What* to photograph (a storefront, a line, a shelf, a view).
11+
- *Where* — an address or a dropped map pin, plus how far around it is acceptable.
12+
- *When* — "today", "during business hours", a specific date/time window.
13+
- Any constraints — daylight, no faces, a particular angle.
14+
3. **Set the reward.** This is what the winning photographer earns. Higher rewards
15+
and tighter deadlines get filled faster.
16+
4. **Fund it.** Pay the reward into escrow — with USDC directly, or by card via the
17+
built-in on-ramp if you don't hold crypto. The money is held, not spent yet.
18+
5. **Wait for submissions.** Nearby photographers get the mission and submit photos.
19+
You'll see them come in on the mission page.
20+
6. **Pick the winner.** Select the best photo. The escrowed reward pays out to that
21+
photographer automatically; unspent funds can be refunded.
22+
23+
## How it relates to the agent API
24+
25+
Everything above is the human front door to the exact rail described in the
26+
[README](../README.md): funding a mission = escrow, picking a winner = payout. An AI
27+
agent does the same three things — post, fund, select — over
28+
[x402](https://x402.org) instead of a web form. See
29+
[`x402-agent-order.js`](x402-agent-order.js).

examples/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "onsight-api-examples",
3+
"private": true,
4+
"type": "module",
5+
"description": "Runnable examples for the Onsight API",
6+
"dependencies": {
7+
"viem": "^2.54.3",
8+
"x402-fetch": "^0.6.0"
9+
}
10+
}

examples/x402-agent-order.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Place and fund a ground-truth photo order on Onsight, paid via x402.
2+
//
3+
// An AI agent can't photograph a real place — this commissions a real person to.
4+
// x402 handles payment inline: the first request comes back 402, `x402-fetch`
5+
// signs a USDC payment on Base and retries automatically. The agent's wallet IS
6+
// the account — no signup, no API key.
7+
//
8+
// Run:
9+
// cd examples && npm install
10+
// AGENT_PRIVATE_KEY=0x... node x402-agent-order.js
11+
//
12+
// The wallet needs USDC on Base (or Base Sepolia for testing) plus a little ETH
13+
// for the on-chain settlement.
14+
15+
import { wrapFetchWithPayment } from "x402-fetch";
16+
import { privateKeyToAccount } from "viem/accounts";
17+
18+
const BASE_URL = process.env.ONSIGHT_URL ?? "https://onsight.photo";
19+
const REWARD_USD = 20;
20+
21+
const key = process.env.AGENT_PRIVATE_KEY;
22+
if (!key) throw new Error("Set AGENT_PRIVATE_KEY to a wallet holding USDC on Base");
23+
24+
const account = privateKeyToAccount(key);
25+
// fetch that transparently answers a 402 by paying and retrying:
26+
const fetchWithPay = wrapFetchWithPayment(fetch, account);
27+
28+
const mission = {
29+
title: "Storefront at 123 Market St",
30+
description: "Street-level photo of the entrance, taken today in daylight.",
31+
lat: 37.7897,
32+
lng: -122.3972,
33+
radiusMeters: 150,
34+
};
35+
36+
// 1. Post + fund the mission. First call → 402; x402-fetch pays and retries.
37+
const res = await fetchWithPay(`${BASE_URL}/agent/missions?rewardUsd=${REWARD_USD}`, {
38+
method: "POST",
39+
headers: { "Content-Type": "application/json" },
40+
body: JSON.stringify(mission),
41+
});
42+
43+
if (!res.ok) {
44+
throw new Error(`Order failed: ${res.status} ${await res.text()}`);
45+
}
46+
47+
const created = await res.json();
48+
console.log("Mission funded:", created.id);
49+
console.log("Settlement tx:", created.txHash ?? created.paymentTxHash);
50+
51+
// 2. Read it back (public — no payment, no signature needed) to poll for photos.
52+
const check = await fetch(`${BASE_URL}/agent/missions/${created.id}`);
53+
const state = await check.json();
54+
console.log(`Status: ${state.status ?? state.paymentStatus}${(state.photos ?? []).length} photo(s) so far`);
55+
56+
// Next steps (owner actions, gated by a wallet signature rather than x402):
57+
// POST /agent/missions/:id/select { photoId } → pick + pay the winner
58+
// POST /agent/missions/:id/refund → cancel + refund the escrow
59+
// See the README's "Wallet-signature auth" section for the signing scheme.

0 commit comments

Comments
 (0)