Base URL
http://localhost:3000 in development. Production base URLs are whatever your deployment sets. The API is currently un-versioned; a /v1/ prefix is on the roadmap but not yet in the code.
Authentication
Three headers, three actors. The registry decides which one to validate from the route, not from the caller — there is no negotiation.
| Actor | Header | Format | Example |
|---|---|---|---|
| Buyer | x-user-id | any string | user-1 |
| Vendor | x-api-key | pak_<uuid> | pak_a1b2c3d4… |
| Tier-2 access | x-session-token | st_<uuid> | st_abc123def4… |
Endpoints
User
/api/intentsPublish a new intent.
{
"category": "plumbing_fixtures",
"description": "Pink undermount kitchen sink, porcelain, 30\"",
"attributes": { "material": "porcelain", "color": "pink", "size_inches": 30 },
"constraints": [{ "type": "material_exclude", "value": "stainless_steel" }],
"budget": { "min": 200, "max": 400, "currency": "USD" },
"urgency": "ready_to_buy",
"location": { "metro": "NYC", "zip": "10013" },
"tags": ["kitchen", "renovation"],
"autoApproveBelow": 300
}{ "id": "int_7f...", "status": "active", "createdAt": "2025-11-22T18:04:11Z" }- ·401 missing x-user-id
- ·422 schema validation failed
/api/intentsList the caller's intents.
{ "intents": [{ "id": "int_7f...", "status": "active", "offerCount": 4 }] }/api/intents/:idGet an intent with its offer list.
{ "intent": { ... }, "offers": [...] }- ·404 not owned by caller
/api/intents/:idUpdate an intent (cancel, extend, revise).
{ "status": "cancelled" }Vendor
/api/vendorsRegister a vendor. Returns the API key ONCE.
{ "name": "Premium Sink Co", "email": "ops@premiumsink.co", "categories": ["plumbing_fixtures"] }{ "vendor": { "id": "ven_...", "rating": null }, "apiKey": "pak_a1b2c3..." }/api/vendors/meGet the authenticated vendor's profile.
Offer
/api/offersSubmit an offer. Server scores it; may auto-accept (returns session token) or auto-reject (422).
{
"intentId": "int_7f...",
"price": 280,
"currency": "USD",
"deliveryDays": 2,
"inStock": true,
"attributes": { "material": "porcelain", "color": "pink", "size_inches": 30 },
"description": "Pink undermount porcelain sink, 30 inches.",
"matchPercentage": 95
}{ "offer": { "id": "off_...", "status": "accepted", "score": 82 }, "sessionToken": "st_abc123..." }- ·401 missing x-api-key
- ·403 vendor not registered for this category
- ·422 auto-rejected: reason
/api/offers/:id/acceptBuyer accepts an offer. Issues a session token to the vendor.
{ "offer": { "status": "accepted" }, "sessionToken": "st_..." }/api/offers/:id/rejectBuyer rejects an offer.
/api/offers/:id/counterBuyer counters an offer with a message.
{ "counterMessage": "Can you do 260 for same-day?" }Registry
/api/registry/intentsBrowse active intents. Returns Tier 1 data only. Filter by category, metro, urgency, budget.
{ "intents": [{ "id": "int_...", "category": "...", "budget": {...}, "urgency": "...", "metro": "...", "tags": [...] }] }/api/registry/intents/:id/detailsTier 2 data for a specific intent. Requires a matching session token.
- ·401 missing token
- ·403 token expired or mismatched
Events
/api/eventsServer-Sent Events stream. Emits intent_created, intent_updated, offer_created, offer_status_changed.
Info
/api/healthLiveness probe.
{ "status": "ok" }SSE stream format
GET /api/events returns a text/event-stream response. Each event is a JSON payload with a fixed shape. The client reconnects automatically on drop — the EventSource API handles it.
SSE frames# Example stream (whitespace inserted for readability)
event: intent_created
data: {"id":"int_7f3a1b2c","category":"plumbing_fixtures","urgency":"ready_to_buy"}
event: offer_created
data: {"id":"off_9a2b4c8d","intentId":"int_7f3a1b2c","score":82,"status":"accepted"}
event: offer_status_changed
data: {"id":"off_3c5d7e9f","status":"rejected"}cURL cookbook
Four copy-paste scripts for the whole happy path.
create-intent.shcurl -X POST http://localhost:3000/api/intents \
-H "content-type: application/json" \
-H "x-user-id: user-1" \
-d '{
"category": "plumbing_fixtures",
"description": "Pink undermount kitchen sink, porcelain, 30\"",
"attributes": { "material": "porcelain", "color": "pink", "size_inches": 30 },
"budget": { "min": 200, "max": 400, "currency": "USD" },
"urgency": "ready_to_buy",
"location": { "metro": "NYC", "zip": "10013" },
"autoApproveBelow": 300
}'