# AGENTS.md — Fictix, for coding agents

Fictix generates a synthetic company (accounting, banking, CRM, payroll,
tasks, native-shaped connector records) so you can test a product against
believable, reconciled data — with known issues planted on request.

This file is a brief for agentic coding tools (Claude Code, Cursor, Codex,
etc.) working in a repo that integrates Fictix. For full detail, read
`https://fictix-docs.vercel.app/llms-full.txt` (every published doc page, concatenated)
or fetch a single page as Markdown by requesting its docs URL with `.md`
appended, e.g. `https://fictix-docs.vercel.app/api-reference/demo-jobs.md`.

## The one thing to know

A customer starts in the Fictix Console (`console.fictix.ai`), not the API:
sign up, generate or select a company, then copy the project API key and
runtime base URL from **Connect to your builder**. Do not try to construct a
company or a key by calling an API directly — there is no self-service
browser-key flow.

Staging also supports one organization API key across all current and future
companies in an organization. Admins create it in Organization settings →
Organization API keys. Read `/get-started/organization-api-keys.md` for this
flow. Organization keys are not yet available in production.

```bash
export FICTIX_API_ORIGIN="https://api.fictix.ai"       # or api-staging.fictix.ai
export FICTIX_PROJECT_SLUG="<from Console Connect panel>"
export FICTIX_PROJECT_API_KEY="<from Console > Company settings > Company API keys>"
```

## Auth layers — use the narrowest one

| Header | Scope | Where it comes from |
| --- | --- | --- |
| `X-API-Key` | One generated company's runtime routes (`/api/v1/orgs/{slug}/...`) | Console → Company settings |
| `X-API-Key` (organization key, staging only) | All companies in one organization; `/api/v1/organizations/{org_id}/companies` lists IDs and slugs | Organization settings → Organization API keys |
| `Authorization: Bearer` | Signed-in Console and direct org-admin flows | Authenticated WorkOS org-user session managed by the Console; never copy it |
| `X-Admin-Key` | Fictix-approved external server-to-server management (`/api/v1/demo-jobs/...`) | `FICTIX_ADMIN_API_KEY` supplied by Fictix |

Never put any of these in browser JavaScript, a public env var, or a repo.

### Credential env vars — the complete list

The three exports above support the company-key flow. The staging organization
flow instead uses `FICTIX_API_ORIGIN`, `FICTIX_ORGANIZATION_ID`, and
`FICTIX_ORGANIZATION_API_KEY`. These are Console self-service values.
One more exists, **for Fictix-approved
server-to-server integrations only** — a normal Console customer does not
have it:

- `FICTIX_ADMIN_API_KEY` — sent as `X-Admin-Key`

That's the whole list. Do not invent other variable names (there is no
`FICTIX_CONTROL_PLANE_BEARER`, `FICTIX_ADMIN_KEY`, or `FICTIX_ACCESS_TOKEN`),
and never ask a user to extract a bearer token from their Console session —
the approved admin key is supplied to the integration server-side, not a
copyable browser secret. The signed-in Console manages its own WorkOS bearer
session for Console management actions; it is not one of these customer
environment variables and must not be forwarded. One caveat: the `fictix_mcp` sidecar reads its own names
(`FICTIX_BASE_URL`, `FICTIX_DEFAULT_SLUG`) for the same values — see
`https://fictix-docs.vercel.app/for-agents/mcp.md` before writing MCP config.

## Read data for a company you already have

```bash
curl -sS "$FICTIX_API_ORIGIN/api/v1/orgs/$FICTIX_PROJECT_SLUG/data/customers?limit=100&offset=0" \
  -H "X-API-Key: $FICTIX_PROJECT_API_KEY"
```

Canonical entities: `accounts`, `bank_accounts`, `bank_transactions`, `bills`,
`customers`, `customer_payments`, `credit_memos`, `deals`, `employees`,
`invoices`, `items`, `journal_entries`, `payroll_runs`, `tasks`,
`vendor_payments`, `vendors`.
(`payments` aliases `customer_payments`; `bill_payments` aliases
`vendor_payments` — use canonical names in new code.)

ASC (ambulatory surgery center) companies add `operating_rooms`,
`surgical_cases`, `clinical_incidents`, and `dictation_scripts`. Create that
synthetic clinical pack with `company.industry: "asc_surgical"`, not a clinical
`company.archetype`. It contains no real patient data; `dictation_scripts.labels`
is a synthetic extraction answer key for offline evaluation only. See
`https://fictix-docs.vercel.app/concepts/clinical-asc.md`.

## Create/control a company programmatically (approved server-to-server only)

```http
POST /api/v1/demo-jobs
Idempotency-Key: <stable-per-request-key>
X-Admin-Key: $FICTIX_ADMIN_API_KEY
```

The admin key is held only by approved partners. If the user isn't one, don't
solicit a credential — route them to the Console flow instead. This is the
normalized control-plane surface — not the first integration path for a
normal Console customer; the signed-in Console uses its own managed WorkOS
bearer session. See
`https://fictix-docs.vercel.app/api-reference/demo-jobs.md`.

## Discovery (no credential required)

```bash
curl -sS "$FICTIX_API_ORIGIN/api/v1/catalog/entities"
curl -sS "$FICTIX_API_ORIGIN/api/v1/catalog/connector-capabilities"
```

## Connect a provider client

Read `/guides/connect-your-software.md`, `/api-reference/provider-first-requests.md`,
and `/api-reference/provider-workflows.md` before constructing a provider URL.
The public `/provider-first-requests.json` file contains all reviewed requests.
Public catalog snapshots observed October 28, 2026 report 60 entries in staging
and production: 59 marked available/selectable and one FCI execute preview that
is not selectable. All 60 report approximate fidelity. These are catalog
reports, not provider-request tests or a strict upstream parity claim. The
published first-request templates were tested in staging only. Query the chosen
environment's catalog before choosing a provider.

Copy the provider URL and first request from the staging company's **API** page.
Use `/api/v1/orgs/{slug}/native/{provider}/{provider_path}` for native calls;
preserve API versions, content types, and POST bodies. Native reads need `read`,
native writes need `write` and a nonempty idempotency key. Send `Idempotency-Key`
unless the provider workflow documents another header or body field for that route.
GraphQL, XML, and form POSTs can be reads.

External Brex, Chase, and Mercury payouts on staging also require the company's
posting-account choice in **Settings → Company → Bank payout posting account**.
An owner/admin must save it and confirm it survives reload. If the control is
absent, customer setup is unavailable in that environment; never substitute an
operator key or copied Console token. Choose an active, non-bank/non-AR/non-AP
GL account in the payout bank's currency; currency is checked when posting.
Missing configuration returns HTTP 400 in the provider's error envelope: Brex
uses `CONFIGURATION_REQUIRED`, Chase `invalid_parameter` with context, and
Mercury `errors.general`. Verify the
provider operation, bank balance, and balanced canonical posting after payment
and retry. Staging checks do not qualify production payout accounting.

FCI uses `/api/v1/orgs/{slug}/execute` with `read` and `execute` scopes. The
body's `org_id` is the company project ID, not the workspace organization ID.
Inspect execute `status`, GraphQL `errors`, Sage operation statuses, and
Expensify `responseCode` even on HTTP 200. Relay Financial has no implemented
direct API contract. Supported workflows do not imply full vendor parity.

## Conventions worth encoding into generated code

- Page canonical data with `limit`/`offset`; continue while
  `offset + data.length < count`. Native APIs use their provider's pagination
  contract from the workflow reference.
- The organization company directory uses a different envelope: `companies`,
  page `count`, and overall `total`; continue while `offset + count < total`.
- Handle `413` on `/demo-jobs/{id}/bundle` by paging entities or exporting
  instead — don't parse the record-count cap out of the error string.
- Retry `POST /api/v1/demo-jobs` only with the *same* `Idempotency-Key` and
  *same* body; a different body with a reused key returns `409`.
- Most error `detail` values may be a string or a `{ code, message }` object;
  demo-job credit errors instead use `{ error, message }`. Handle both
  envelopes.
- `contract_version` is a date-based string (e.g. `"2026-07-17"`) — never
  coerce it to a number.

## Full reference

- Getting started: `/get-started/*`
- Concepts (demo jobs, blueprints, entities/lineage, simulation): `/concepts/*`
- End-to-end guides: `/guides/*`
- Endpoint reference: `/api-reference/*`
- Limits, versioning, changelog: `/resources/*`
- Machine-readable index: `/llms.txt`, full content: `/llms-full.txt`
