Files
0pt/docs/04-api.md
T
adminandClaude Opus 4.8 22e09d984d feat: rebrand MONO->0pt (hero, header, layout) + add project docs/contract
Hero is now a data-native 0pt artifact (no photos, keeps grain/reveal/float); header is the 0pt wordmark with Swedish nav; layout is sv + loads JetBrains Mono + 0pt metadata; globals wires the loaded fonts. Adds CLAUDE.md + docs/01-09 as the build contract. next build green (5 routes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 17:38:07 +02:00

98 lines
4.5 KiB
Markdown

# 04 · API contract (FastAPI)
Canonical REST contract. Reconcile the existing 25+ endpoints in `src/orchestrator/main.py` toward this. JSON in/out, `snake_case`. All amounts in **öre**. Auth: Next.js → FastAPI over a shared internal token (`X-Internal-Token`); customer identity passed as `org_id`/`user_id` resolved from the Auth.js session server-side.
## Conventions
- Errors: `{ "error": { "code", "message" } }`, proper HTTP status. Interface-voice messages (Swedish) are produced in the frontend, not here.
- Idempotency: accept `Idempotency-Key` on POSTs that create orders/payments.
- Pagination: `?limit=&cursor=`.
## Catalog
```
GET /catalog -> [{id,title,markets,entity_type,count,updated,price_ore,confidence}]
GET /catalog/{id} -> full dataset (overview, coverage, schema, quality summary)
GET /catalog/{id}/sample?n=10 -> sample rows WITH per-field provenance
```
## Estimate (configurator → price/time/confidence)
```
POST /estimates
body: { flow, markets[], entity_type, fields[], enrichment[], volume, frequency, confidence_target, formats[] }
-> { total_ore, deposit_ore, balance_ore, est_days, est_confidence, breakdown[] }
```
## AI-assist (NL → config)
```
POST /ai/parse
body: { text } -- "5000 svenska SaaS-bolag med e-post och omsättning"
-> { config: <estimate body>, rationale } -- prefilled configurator; uses pgvector match to catalog/fields
```
## Orders (lifecycle)
```
POST /orders body: { flow, config } -> { order_id, status:'draft'|'quoted' }
GET /orders -> [orders for org]
GET /orders/{id} -> order + current job + delivery (if any)
POST /orders/{id}/scope (custom flow) body:{ notes } -> status:'quoted' (manual quote step)
POST /orders/{id}/accept customer approves delivery -> triggers balance release; status:'accepted'
POST /orders/{id}/revise body:{ notes } -> status:'revision'; escrow untouched
```
## Payments (50/50 escrow)
```
POST /payments/{order_id}/deposit -> { checkout_url } (Stripe Checkout for 50%; on success → IN_PRODUCTION)
POST /payments/{order_id}/release -> captures/charges the held balance (called on accept)
POST /webhooks/stripe (Stripe → here) verify signature; update payments + order status
```
> Implement balance as either a manual capture on a held PaymentIntent, or a second Checkout/invoice keyed to `order_id`. Never charge balance before `accept`.
## Jobs / live status
```
GET /orders/{id}/status -> { stage, pct, per_market[], confidence, eta, rows }
GET /orders/{id}/events -> Server-Sent Events stream (preferred for the production tracker)
```
## Uploads (R2 presigned)
```
POST /uploads body:{ order_id, name, mime, bytes } -> { file_id, put_url } (client PUTs to R2)
GET /orders/{id}/files -> [files]
```
## Customer DB access (read-only grant)
```
POST /connections/db-grant
body: { order_id, conn_string, scope, expires_at } -- stored ENCRYPTED; validated read-only
-> { grant_id, status:'pending'|'verified' }
DELETE /connections/db-grant/{id} -> revoke
```
## Deliveries
```
GET /orders/{id}/delivery -> { formats, destinations, record_count, avg_confidence, quality_report, files[], provenance_export_url }
POST /orders/{id}/delivery/destinations body:{ destinations[] } -> updates targets (CSV/Parquet/JSON/API/NocoDB/Metabase/FiveCRM/Sheets/webhook)
```
## Sources (the transparency moat)
```
GET /sources -> [{source_id,name,market,access,licence,cadence,confidence}]
GET /sources/{market} -> sources + freshness for a market
```
## Subscriptions / feeds
```
POST /subscriptions body:{ order_id, cadence, webhook_url } -> { sub_id }
GET /subscriptions -> [subs]
POST /subscriptions/{id}/pause | /resume
```
## Webhooks out (to customers)
- On delivery / feed update: POST to `subscriptions.webhook_url` with `{ order_id, delta_url, summary }`.
## Health
```
GET /health -> { ok, db, workers, queue }
```
## Existing-code reconciliation
Map current endpoints (orders, estimates, ai-assistent, catalog, webhooks, health) onto the names above; rename for consistency, keep behavior. Add: `/orders/{id}/events` (SSE), `/payments/*` escrow split, `/connections/db-grant`, `/sources`, `/subscriptions`. Remove any endpoint that drives a bypass/stealth fetch path.