# AI.md — Guide for AI Code CLIs

**You are an AI code CLI tasked with building a new functionality that integrates with the Contabeleza API.**

This document is your **single source of truth** for understanding the platform. It tells you exactly where to look, what to read, and in what order. Follow it step by step and you will have everything you need to write correct, working code.

**Important**: This document is served at `/ai` on the deployed docs site and at `/ai` (or `/ai.md`) on the local dev server. Read it first, then follow the links below.

### 0.1 Environment Variables

Before fetching the docs site, set these environment variables:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `API_CONTABELEZA_CLIENT_ID` | Yes | — | Cloudflare Access Client ID |
| `API_CONTABELEZA_CLIENT_SECRET` | Yes | — | Cloudflare Access Client Secret |
| `API_CONTABELEZA_URL` | No | `api-docs.contabeleza.com.br` | Base URL for the API docs site |

These are **Cloudflare Access Service Tokens** used to bypass ZeroTrust authentication. All `curl` examples below include the required headers.

---

## 0. The docs site is your primary source of truth

This repository (`api-docs-contabeleza`) is a **static documentation site** for the Contabeleza API. It contains:

- An **OpenAPI 3.0 spec** with every documented endpoint, request/response shape, and example payload
- A **Models reference** explaining every JSON:API type, its attributes, and its relationships
- A **Tech Guides** section with deep technical docs for developers
- A **General Guides** section (in Portuguese) for non-technical users
- A **Swagger UI** at `/docs` for interactive exploration
- An **Endpoint browser** at `/` with filter/search and collapsible groups

Before you touch any code outside this repo, **fully read the docs site**. Specifically:

| Section | URL | What it tells you |
|---|---|---|
| Endpoints browser | `/` | Every operation, grouped by tag, with descriptions and use-cases. Collapsible groups, search, tag filters. |
| Swagger UI | `/docs` | Interactive reference — try requests, see schemas |
| Models | `/models` | Every JSON:API type — attributes, types, examples, relationships |
| Tech guides catalog | `/guides/tech` | All developer guides (auth, JSON:API, environments, invoice emission, etc.) |
| General guides catalog | `/guides/geral` | Portuguese guides for non-technical context (with type/status translations) |
| OpenAPI spec (raw) | `/openapi.json` or `/openapi.yaml` | The full spec as a single document — for programmatic access |
| Changelog | `/changelog` | Recent changes to the API |
| This document | `/ai` (rendered) and `/ai.md` (raw) | The bootstrap doc you are reading |

## 1. Read the docs in this order

Do these in order. Don't skip steps.

### Step 1.0 — Read `/AI_INDEX.md` (compact reference, ~270 lines)

This is a **machine-generated index** of every endpoint, model, and error code. It is designed specifically for AI agents — compact, scannable, and directly renderable.

Fetch it first to understand the full surface area of the API:

```bash
curl -s \
  -H "CF-Access-Client-Id: $API_CONTABELEZA_CLIENT_ID" \
  -H "CF-Access-Client-Secret: $API_CONTABELEZA_CLIENT_SECRET" \
  https://${API_CONTABELEZA_URL:-api-docs.contabeleza.com.br}/AI_INDEX.md
```

It contains:
- **Tag tree** — all endpoint groups with counts
- **Endpoint table** — method, path, tag, response model, request model, error statuses
- **Model table** — every JSON:API type with attribute and relationship counts
- **Error code index** — unique error codes grouped by HTTP status

**Start here.** If the index covers your use case, you will know exactly which endpoints to fetch from the full spec.

### Step 1.1 — Read `/openapi.json` (or fetch the raw spec)

This is the **machine-readable source of truth**. Fetch it:

```bash
curl -s \
  -H "CF-Access-Client-Id: $API_CONTABELEZA_CLIENT_ID" \
  -H "CF-Access-Client-Secret: $API_CONTABELEZA_CLIENT_SECRET" \
  https://${API_CONTABELEZA_URL:-api-docs.contabeleza.com.br}/openapi.json | jq '.paths, .components.schemas'
```

For each path you'll see:
- `summary` and `description` — what the endpoint does
- `tags` — which resource it belongs to
- `parameters` — what you send (path, query, header)
- `requestBody` — the request schema
- `responses[200]` — the success response with an `example` payload

For each schema in `components.schemas` you'll see the type, attributes, and relationships.

**Start here.** If the spec covers your use case, you have everything you need.

### Step 1.2 — Read the Models reference at `/models`

The Models page renders the OpenAPI schemas with descriptions, types, and observed examples from captured traffic. It's the human-friendly version of `components.schemas`.

Use it to understand:
- What attributes a resource has
- What types they are (string, integer, etc.)
- What relationships exist between resources
- What real-world example values look like

### Step 1.3 — Read the tech guide that matches your task

| If you need to... | Read this guide |
|---|---|
| Log in, get a token, refresh | `/guides/tech/authentication` |
| Send the `ilm-business` header | `/guides/tech/ilm-business` |
| Understand the JSON:API envelope | `/guides/tech/jsonapi` |
| Know which environment to hit | `/guides/tech/environments` |
| Set up a fiscal entity for emission | `/guides/tech/invoice-emission-setup` — three-step flow: company setup (`POST /invoices-emission`), credential storage via dedicated endpoints, and explicit emission validation (`POST /invoices-emission/validate`) |
| Configure and validate credentials (pass-gov, pass-invoices, certificate) | `/guides/tech/credential-setup` — how to store, validate, and clear each credential type. Overview of the async validation pattern and the structured error vocabulary from the portal. |
| Understand the `status_*` computed fields on a fiscal entity | `/guides/tech/invoice-emission-setup` § "emission-status state machine" — explains `status_pass_govs`, `status_pass_invoices`, `status_certificate` (incl. `expired`), `emission_status` (no longer `missing_auth`), and `emission_validation` (via `last_emission_validation` on the seller, with `statuses` audit trail) |
| Actually emit an invoice | `/guides/tech/invoice-emission` |
| Run the MEI diagnosis | `/guides/tech/mei-diagnosis` |
| Generate DAS boletos | `/guides/tech/das-emission` |
| Build an async workflow (contracts, invoice batches, terminations) | `/guides/tech/business-requests` — for contract termination, the distrato PDF can be attached either at create time (`data.pdf_url`) or at the status→closed transition (top-level `termination_pdf_url` field in the status-update payload); see the "Attaching a distrato on the closed transition" section |
| Understand contract lifecycle and statuses | `/guides/tech/contracts-lifecycle` — creation, approval, termination, and status machine |
| Manage businesses, professionals, categories | `/guides/tech/business-resources` — CRUD for businesses, professionals, week-schedules, business-categories, professional-categories, professional-services |
| List and manage professionals | `/guides/tech/professionals` — professional catalog, ownership checks, personal documents |
| Query revenue data | `/guides/tech/revenue` — revenue resumes, limits, batch list, per-entity queries |
| Understand test fixtures (CPF/CNPJ) | `/guides/tech/test-fixtures` — hub guide linking to focused CPF, CNPJ MEI, and CNPJ non-MEI fixture guides |
| CPF fixtures for individuals | `/guides/tech/test-fixtures-cpf` — standalone CPFs, CPFs linked to MEI/non-MEI CNPJs, error scenarios |
| MEI CNPJ fixtures | `/guides/tech/test-fixtures-cnpj-mei` — MEI companies with scenario-specific fixtures and test workflow |
| Non-MEI CNPJ fixtures | `/guides/tech/test-fixtures-cnpj-non-mei` — regular companies with scenario-specific fixtures and test workflow |
| Test credential error scenarios | `/guides/tech/test-credentials` — password-based error scenarios for certificate, pass-invoices, and pass-govs validation |
| Use internal accounting endpoints | `/guides/tech/internal-endpoints` — admin-only routes, direct accounting service, proxy vs direct, JSON:API types, deprecated/broken routes |

**Read the relevant guide fully before writing any code.** The guides explain the data flow, gotchas, and edge cases that the OpenAPI spec alone doesn't capture.

### Step 1.4 — Read the general guides for business context

The general guides (in Portuguese) explain the business context without code. Read them to understand *why* the API works the way it does:

- `/guides/geral/autenticacao` — How login works
- `/guides/geral/conceitos-da-plataforma` — Platform concepts (Professionals, Fiscal Entities, MEI, Invoices, Contracts)
- `/guides/geral/ambientes` — Environments
- `/guides/geral/configurando-emissao` — Configuring invoice emission
- `/guides/geral/configuracao-de-credenciais` — Credential setup lifecycle (add, update, clear, validate)
- `/guides/geral/emitindo-notas-fiscais` — Emitting invoices
- `/guides/geral/emissao-de-das` — DAS-MEI emission
- `/guides/geral/diagnostico-mei` — MEI diagnosis
- `/guides/geral/gestao-contratos` — Gestão de contratos
- `/guides/geral/business-requests` — The 4 async workflow types

The general guides use **Portuguese labels with the original English enum values in `<code>` tags** (e.g. `Novo Contrato <code>new_contract</code>`). When you see a Portuguese label in a guide, the value in backticks is the actual enum string you send in API requests.

### Step 1.5 — Check the Changelog at `/changelog`

Before you write code, check if anything related to your task has changed recently. The changelog lists recent additions, changes, and removals.

## 2. Understand the API conventions

These apply to every endpoint. Get them wrong and nothing will work.

- **All responses follow JSON:API v1.1** — `Content-Type: application/vnd.api+json`
- **Auth: `Authorization: Bearer <jwt>`** — HS256, validated server-side. Get the token from `POST /sessions` with `type: "email"`.
- **Business context: `ilm-business: <business-id>`** — required header on most endpoints. Get the business id from the login response under `data.businesses[].id`.
- **Attribute names are kebab-case** — `created-at`, `tax-number`, not `created_at` or `taxNumber`.
- **`id` is always a string** — even when numeric.
- **Type/status enums use snake_case** — `new_contract`, `profesional_invoice_emission`, `not_applicable`, `pass_only`, etc. See the general guides for Portuguese translations.
- **Tag conventions** — operations are tagged with domain groups (`businesses`, `professionals`, `professional-contracts`, etc.) plus marking tags: `Privado` (internal-use, not for general public), `Obsoleto` (deprecated — will be removed), `Admin` (restricted to admin roles). Deprecated operations also have `deprecated: true` in the spec.
- **`fiscal-entities` exposes computed status strings** for each credential: `status_pass_govs`, `status_pass_invoices`, and `status_certificate` — each can be `valid`, `invalid`, `none`, `not-validated`, or `processing-validation`. `status_certificate` additionally can be `expired` when the active cert is past its `expiration-date`. The `emission_status` field is one of `missing_setup`, `missing_validation`, `active`, `inactive` (note: `missing_auth` is no longer a value — it is now an error code returned by operations that require auth). The `last_emission_validation` field on the seller carries the latest `EmissionValidation` record, whose `statuses` array (audit trail per attempt) defines the canonical emission validation state: `none` → `validating` → `succeeded`/`failed`. Dedicated `emission-validations` endpoints (`POST`/`GET` on `/invoices-emission/validate`, `/validate-emission`, `/validation-status`) return the full `EmissionValidation` JSON:API resource with `invoice` HasOne relationship and attributes: `status`, `author`, `author_type`, `authentication_type`, `canceled_at`, `is_valid`. Derived boolean fields `has_pass_gov`, `has_pass_invoices`, and `has_certificate` are also returned: each is `false` when the corresponding status is `none` or `inactive`, `true` otherwise.
- **Query parameters for sideloading, filtering, sorting, pagination:**
  - `?include=businesses` — sideload related resources
  - `?fields[professionals]=name,email` — sparse fieldsets
  - `?filter[status]=active` — server-defined filtering
  - `?sort=-created-at` — prefix with `-` for descending
  - `?page[number]=2&page[size]=25` — pagination

## 3. If you need to test the API

The docs site has **mock endpoints** mounted at every documented path. They return the inferred example from the OpenAPI spec. Use them to:

- Validate your request shapes
- See what a response looks like
- Iterate quickly without hitting staging

You can hit the mocks locally with `npm start` (Express, port 4321) or against the deployed site directly via the Cloudflare Pages Function.

## 4. Quick reference

- **OpenAPI spec**: `public/openapi.json` (or `https://${API_CONTABELEZA_URL:-api-docs.contabeleza.com.br}/openapi.json`)
- **Swagger UI**: `/docs`
- **Models reference**: `/models`
- **Endpoint browser**: `/` (collapsible groups, search, tag filters)
- **Tech guides**: `/guides/tech` — 20 guides: authentication, ilm-business, jsonapi, environments, invoice-emission-setup, invoice-emission, credential-setup, mei-diagnosis, mei-revenue, das-emission, business-requests, test-fixtures, test-fixtures-cpf, test-fixtures-cnpj-mei, test-fixtures-cnpj-non-mei, test-credentials, contracts-lifecycle, business-resources, professionals, revenue
- **General guides**: `/guides/geral` — 12 Portuguese guides: autenticacao, emissao-notas, conceitos-da-plataforma, ambientes, configurando-emissao, configuracao-de-credenciais, emitindo-notas-fiscais, emissao-de-das, diagnostico-mei, faturamento-mei, business-requests, gestao-contratos
- **Account-level professional endpoints**: `GET /accounts/{id}/professional-invoices` and `GET /accounts/{id}/professional-contracts` — list all invoices/contracts for all professionals associated with the account via the fiscal entity owner relationship. Each item includes `professional-id` and `tenant-id` fields.
- **Changelog**: `/changelog`
- **This document**: `/ai` (rendered) and `/ai.md` (raw)

## 5. Troubleshooting

### Common Errors

| Error | Cause | Solution |
|-------|-------|----------|
| `403 Forbidden` | Missing or invalid Cloudflare Access headers | Ensure `CF-Access-Client-Id` and `CF-Access-Client-Secret` are set correctly |
| `401 Unauthorized` | Service token expired or revoked | Generate a new Service Token in Cloudflare Zero Trust dashboard |
| `Connection refused` | Wrong `API_CONTABELEZA_URL` | Check the URL, default is `api-docs.contabeleza.com.br` |
| `SSL certificate problem` | Network or proxy issue | Verify network connectivity and SSL certificates |

### Verify Your Setup

```bash
# Test authentication
curl -s -o /dev/null -w "%{http_code}" \
  -H "CF-Access-Client-Id: $API_CONTABELEZA_CLIENT_ID" \
  -H "CF-Access-Client-Secret: $API_CONTABELEZA_CLIENT_SECRET" \
  https://${API_CONTABELEZA_URL:-api-docs.contabeleza.com.br}/ai.md

# Expected output: 200
```

You have everything you need. Read carefully, test against the mocks, and ship.
