# Customer Discovery agent API

Origin: https://customer-discovery.jessald.fairystack.com

A private, owner-scoped discovery portfolio. Browser views are read-only. Agents record ideas, sourced evidence, and bounded experiments through this API. No workflow sends outreach, charges customers, purchases ads, or calls a model automatically.

## Authentication

Exchange the current FairyStack session capability at `POST /api/apps/customer-discovery/agent-token` on your control origin. Load it from the private credential file and never print it. Use the returned token as `Authorization: Bearer <token>` on this app only. Ordinary AuthReturn app JWTs also work. Every record belongs to the verified JWT subject. Different accounts see separate notebooks.

Use explicit HTTP timeouts (20 seconds). `GET /api/version` returns version and deployed revision. `GET /api/health` is public. Every other API requires authentication; missing, expired, invalid and wrong-app tokens fail closed.

## Read and update

`GET /api/workspace` returns `{revision,ideas,evidence,experiments,history}`. An empty notebook has revision 0.

`POST /api/batch` accepts `{"expected_revision":1,"operations":[{"collection":"evidence","action":"create","record":{...}}]}`. Collections are `ideas`, `evidence`, `experiments`; actions are `create` or `update`. For an update provide the existing `id` and changed fields. Up to 100 operations / 1 MB. Batches validate and commit atomically. Read the current revision first; 409 means re-read and reconcile. Repeated IDs fail with 409; after an ambiguous timeout, read the workspace before retrying. Never blindly duplicate observations. Create ideas before referencing them in the same batch.

Success returns the complete new workspace. Errors return `{error: "concrete message"}` with 401 authentication, 403 wrong origin, 404 unknown record/route, 409 stale revision or duplicate, 413 too large, 415 wrong content type, 422 validation, 503 unavailable verification or 504 timeout. JSON Content-Type is required. The service owns a 12-second request deadline; it does not run background jobs. A committed result may outlive a disconnected client: reconcile by revision and record ID.

IDs are stable 1–80 character strings using letters, digits, `_` and `-`. Each update retains its previous and next record in `history`. No hard-delete API: park ideas or retract evidence while retaining provenance. The service owns created/updated timestamps. Keep customer identifiers pseudonymous and stable across ideas; do not store unnecessary personal details.

## Ideas

Required: `id`, `title`, `customer`, `problem`, `solution`, `price_hypothesis`, `reach_hypothesis`, `delivery_hypothesis`, `riskiest_assumption`, `origin` (where the idea came from).

Optional: `status` = `exploring` (default), `testing`, `parked`; `decision` explains the current decision. Price is a labeled hypothesis, not revenue. Every idea must specify who pays and what is being delivered.

## Evidence

Required: `id`, `idea_id`, `kind`, `dimension`, `direction`, `source_label`, `observation`, `interpretation`, `limitation`, `observed_at` (ISO timestamp, not future).

- `kind`: `public`, `interview`, `behavior`, `commitment`, `payment`.
- `dimension`: `pain`, `payment`, `reach`, `delivery`.
- `direction`: `supports`, `contradicts`, `mixed`.
- `source_url`: HTTP(S) link without credentials; required for public evidence. Interview notes may use source_label to describe the private source.
- `participant`: stable customer pseudonym, required for all direct evidence, excluded for public signals.
- `amount` and `currency`: required positive amount for payment; supported currencies USD, EUR, GBP, CAD, AUD. Payment records must address the payment dimension. Do not use this kind for promised payment.
- Optional `experiment_id`: must be an existing experiment of this idea.
- Optional `retracted: true`: remove from current analysis while retaining audit history. Prefer update with corrected interpretation and limitation for annotation corrections.

Example record (illustrative shape only; never submit as a real observation):

```json
{"id":"interview-001","idea_id":"invoice-followup","kind":"interview","dimension":"pain","direction":"supports","participant":"agency-001","source_label":"Interview notes supplied by operator","observation":"Use the actual reported behavior here.","interpretation":"State the inference separately.","limitation":"One self-report; no payment observed.","observed_at":"2026-09-25T12:00:00Z"}
```

Check original sources, retain material contradictions, and distinguish a quotation from a paraphrase. Competitor prices are only public signals. Never invent interviews, payment, delivery ability, or contact permission. A refusal is useful evidence. An existing offer does not prove anyone bought it.

## Experiments

Required: `id`, `idea_id`, `title`, `dimension`, `method` (`desk`, `interview`, `concierge`, `offer`, `prototype`), `question`, `steps`, `pass_rule`, `stop_rule`, `estimated_cost` (USD), `estimated_minutes`.

Optional `status`: `planned` (default), `running`, `completed`, `cancelled`. Start before completing. Optional `prerequisite_id` must name an existing experiment on the same idea and cannot change afterward. Starting a dependent test requires the prerequisite to be completed with `outcome: "passed"`. Completed experiments require `outcome` (`passed`, `failed`, `inconclusive`), `conclusion`, `actual_cost` (USD), `actual_minutes`; terminal records cannot reopen. Create a fresh test instead. Store actual outcomes as linked evidence; a completed plan alone creates no evidence. Human fieldwork may remain running across sessions; this is a notebook status, not an owned compute job.

Cash estimates exclude labor. The queue sorts running before planned, then ready tests before dependent tests, then cash and time. Dependencies in the plan are prerequisites: do not run a paid-offer test until the relevant problem test has supported proceeding. No test plan authorizes spending, sending messages, or charging customers.

## Practical workflow

1. Read the notebook and choose the biggest uncertainty worth resolving cheaply.
2. Research independent primary sources or record supplied customer notes. Keep every claim tied to provenance and limits.
3. Add evidence and update the next test atomically. Avoid repeated observations from one source inflating a conclusion.
4. Summarize what changed the decision. Park ideas when the evidence undermines them; retain the history.
5. Verify the saved revision through GET and link the relevant idea using `/#idea=<id>`.

The starter portfolio contains agent-proposed hypotheses, three researched public signals, and proposed tests. It contains no actual customer interviews or payments. Nothing is validated by being included.
