> ## Documentation Index
> Fetch the complete documentation index at: https://help.reevo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API Conventions

> Action routes, request hygiene, idempotency, field discovery, and client tooling for Public API v2.

<Warning>
  **Restricted access.** Public API v2 is currently available only to allowlisted
  organizations. Requests from workspaces that have not been enabled are rejected.
  Contact your Reevo representative to have your organization added to the allowlist.
</Warning>

# API Conventions

Public API v2 follows a small set of conventions across every record type. Learn them once and they apply everywhere, including custom objects.

## Action routes

Alongside standard REST verbs, v2 exposes three underscore-prefixed action routes. The underscore prefix keeps these action names from colliding with record IDs and custom object names.

| Route                                  | Method | Purpose                                                                                                                                                                                      |
| :------------------------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/api/v2/public/<record_type>/_query`  | `POST` | Filter, sort, and paginate records. See [Query Records for Sync](/Public-API-v2/Guides/Query-Records-for-Sync).                                                                              |
| `/api/v2/public/<record_type>/_upsert` | `POST` | Create or update a record by a unique match field. Available for `contact`, `account`, and custom objects. See [Create and Update Records](/Public-API-v2/Guides/Create-and-Update-Records). |
| `/api/v2/public/_schema/<record_type>` | `GET`  | Inspect a record type's fields, relationships, and capabilities.                                                                                                                             |

Canonical CRUD uses plain REST: `POST /api/v2/public/<record_type>` to create, `GET /api/v2/public/<record_type>/{id}` to read, `PATCH /api/v2/public/<record_type>/{id}` to update, and `DELETE /api/v2/public/<record_type>/{id}` to archive.

## Request hygiene

Write requests must be well-formed JSON. The surface enforces these rules before any business logic runs:

| Rule           | Requirement                                                                                                                   | Failure                      |
| :------------- | :---------------------------------------------------------------------------------------------------------------------------- | :--------------------------- |
| Content type   | `POST`, `PUT`, and `PATCH` bodies must be sent with `Content-Type: application/json` (a `; charset=utf-8` suffix is allowed). | `415 unsupported_media_type` |
| Accept         | If you send an `Accept` header, it must allow `application/json` (`application/json` or `*/*`).                               | `406 not_acceptable`         |
| Body size      | Request bodies are capped at 1 MiB (1,048,576 bytes).                                                                         | `413 payload_too_large`      |
| Trailing slash | Canonical paths have no trailing slash. A trailing slash is redirected to the canonical form with a `307`.                    | None (redirected)            |

## Idempotency

Public API v2 does not use an `Idempotency-Key` header. Plan retries around the semantics of each operation instead:

* `GET`, `PATCH`, and `DELETE` are naturally idempotent. Repeating the same request lands the record in the same state. Note that a second `DELETE` on an already-archived (or absent) record returns `404 record_not_found`, not a `2xx`: the record state is unchanged, but a client retrying a `DELETE` must treat the `404` as an acceptable "already archived" outcome.
* A plain `POST` create is **not** deduplicated. Retrying a create after a network timeout can produce a second record.
* For a safe, repeatable create-or-update, use [`_upsert`](/Public-API-v2/Guides/Create-and-Update-Records) on `contact`, `account`, or a custom object. The first call returns `201` with `meta.action: "created"`, and later calls return `200` with `meta.action: "updated"`. On `contact` the match field is `primary_email` (or `contact_emails.email`), so re-running the same call converges on a single record. On `account` the match field is `domains.domain_name`, which is **not** unique: if more than one account in the workspace shares that domain, the call returns `400 ambiguous_match` instead of converging.

## Discover field rules with `_schema`

Field-level rules are workspace-specific and are not hardcoded into these guides. Use `GET /api/v2/public/_schema/{record_type}` as the source of truth for:

* Which fields exist, and their value types.
* Whether a field is creatable, updatable, required, or system-managed.
* Whether a field is filterable and sortable.
* Which fields are unique (and therefore usable as an `_upsert` or `related_record_match` key).
* The available options for select and stage fields.

Building a generic client? Call `_schema` before writing values rather than assuming a fixed field set. See [Errors and Validation](/Public-API-v2/Errors-and-Validation) for the validation codes a write can return.

## Client libraries

There are no official Reevo SDKs or a published Postman collection for Public API v2 yet. The API is fully described by the OpenAPI specification checked in at `/api-reference/api/v2/public/openapi.json`, so you can generate a typed client or a Postman collection from it today. See the [Overview](/Public-API-v2/Overview) for where the spec lives.
