External API Overview
The public REST API used by CRM sync, forms, automations, and partner integrations, with what is live in V2 today.
External API Overview
Current V2 status (2026-09-22):
/api/v1is live in V2 for reading leads, clients, estimates, jobs, and invoices, creating leads and clients, updating clients, test-key sandbox records, and/api/v1/openapi.json. Live-keyPOST /api/v1/estimatesis merged but pending production; it will create an empty draft only. Until that release, live requests to it still receive405 write_not_supported. API keys are managed in Settings > Integrations > External API keys. Outbound webhook endpoints are managed in Settings or through/api/v1/webhookswith a live key. Estimate updates, job and invoice writes, lead updates, and job notes are still unavailable to live keys; test keys continue to write sandbox estimates. See the table below, and treat your workspace's/api/v1/openapi.jsonas the exact list of what is live. Automation workflow routes described below operate on existing workflows; they do not create or delete workflows, enroll contacts, or start a manual run.
Clean Estimate includes a public REST API at https://app.cleanestimate.pro/api/v1/ for server-to-server integrations. Use it for Zapier, Make, custom CRMs, web forms, internal middleware, and partner apps.
The V1 public API is intentionally scoped to the core workflow plus outbound webhook management:
- Leads
- Clients
- Estimates
- Jobs
- Invoices
- Outbound webhooks
- OpenAPI at
/api/v1/openapi.json
The V2 host also exposes a workflow-operation gateway for mounted application procedures and explicit adapters for mobile actions, file/media transfers, and tenant-scoped bug reports. It uses the current app permission checks for each operation and is independent of the resource-specific REST endpoints above.
Every request is isolated to the organization that owns the API key. The API never accepts a client-supplied org_id, and wrong-org records return 404.
What Is Live In V2
| Capability | V2 today |
|---|---|
GET /api/v1/{leads,clients,estimates,jobs,invoices} and GET .../{id} | Live |
POST /api/v1/leads and POST /api/v1/clients | Live |
PATCH /api/v1/clients/{id} | Live |
POST /api/v1/estimates (create an empty draft) | Pending production; currently returns 405 write_not_supported for live keys |
| Test keys with isolated sandbox records | Live: test keys read and write sandbox leads, clients, and estimates |
/api/v1/openapi.json | Live |
notes on leads (create) and clients (create and update) | Live |
PATCH /api/v1/estimates/{id}, estimate pricing or sending, job/invoice writes, and PATCH /api/v1/leads/{id} | Not available with a live key (405 write_not_supported) |
Job notes, view_url, service_interest, list filters such as status | Not yet |
GET, POST /api/v1/webhooks and GET, DELETE /api/v1/webhooks/:id (live keys) | Live |
connector_key on POST /api/v1/leads (lead connector defaults, aliases, and review queue) | Live: a complete payload answers 201, an incomplete one 202 into the review queue |
GET /api/v1/automations and GET /api/v1/automations/{id} | Live; live keys only |
PATCH /api/v1/automations/{id}, POST /api/v1/automations/{id}/publish, and POST /api/v1/automations/{id}/pause | Live; changes apply only to existing workflows |
MCP automation tools at POST /api/mcp | Live; stateless Streamable HTTP with the same live-key access rules |
GET /api/v1/workflows, workflow schema discovery, query and mutation operations, and durable mutation receipts | Available on the V2 host to eligible live keys with explicit workflows:read or workflows:write scope; see Application workflow operations |
Application workflow operations
The workflow gateway exposes application procedures and explicit HTTP adapters through one catalog, so integrations can discover the operations available to their key and the active member who created it. Procedure names use their full tRPC paths, such as jobs.list; adapter operations use their documented catalog names. The gateway applies each operation's current app permissions and location checks; an API-key scope alone does not grant access to application data or actions.
Use the live V2 host, https://cleanestimatev2.vercel.app, with a live API key. Test keys cannot use this gateway. The key must have the exact workflows:read or workflows:write scope required for the operation; the legacy global * and workflows:* scopes do not grant access. The key must cover every location in its creator's current location scope. The creator must remain an active member, and their current application permissions are checked for each call.
| Request | Purpose | Required workflow scope |
|---|---|---|
GET /api/v1/workflows | Discover operations visible to the key, including each operation's name, kind, and required scope | workflows:read |
GET /api/v1/workflows?operation={operation-name} | Read one operation's input JSON Schema and input_schema_status | workflows:read |
GET /api/v1/workflows/{operation}?input={URL-encoded-JSON} | Run a query operation | workflows:read |
POST /api/v1/workflows/{operation} with JSON input | Run a query operation; no idempotency key or mutation receipt | workflows:read |
POST /api/v1/workflows/{operation} with JSON input and Idempotency-Key | Run a mutation operation | workflows:write |
GET /api/v1/workflows/requests/{requestId} | Read the durable receipt for a mutation | workflows:read or workflows:write |
Dispatch POST by the catalog's kind: queries use workflows:read and do not require an idempotency key; mutations use workflows:write and do. Every workflow POST requires Content-Type: application/json, including when the operation has no input body. GET query invocation remains available for inputs up to 64 KiB after URL decoding. Workflow POST bodies default to 1 MiB; an operation may have a lower limit or a reviewed higher limit up to the 4 MiB absolute cap. JSON responses are capped at 4 MiB. Inline file payloads are capped at 3,000,000 bytes to leave room for base64 and JSON overhead. Vercel's non-streamed function response ceiling is 4.5 MB, so use signed upload or download flows for larger files when the operation provides them.
Schema detail includes input_schema_status: complete means the JSON Schema matches the runtime parser; partial means an unrepresentable Date/custom/union constraint is broadened and the parser may reject a schema-valid input; unsupported means no honest schema could be generated. Unsupported entries remain discoverable and runtime-validated. See Examples for how to use each status.
The operation catalog covers supported application workflows, including mounted procedures and explicit adapters for mobile-only actions and file transfers. It is not a proxy for arbitrary server routes; customer-token and portal protocols and provider callbacks remain on their dedicated interfaces. The operation list and schemas are discovered at runtime, so use the live catalog to see which operations are available to a given key. Platform-owner- only procedures are excluded. The catalog does not enumerate every API route or protocol in the application. The catalog identifies operations that may send messages, change money, or delete data. Inspect each discovered schema and its application permission before invoking one.
The mutation response includes a meta.request_id for receipt lookup. A receipt can be pending, indeterminate, or completed. Pending and indeterminate mutations are never automatically executed again. Retry only with the original idempotency key and identical input; an in-progress retry returns the receipt, while changed input with the same key returns 409. After success, an exact retry returns the saved result with X-Idempotent-Replayed: true. For operations marked as returning secrets, the first response may include the sensitive value; durable receipts and replayed responses contain only the operation's redacted projection.
See Auth and Scopes, Examples, and Idempotency for access and request patterns.
Existing automation workflows
The API lists and reads existing automation workflows, saves a revision-checked draft, publishes an explicitly selected draft revision, or pauses an existing workflow. It does not create or delete workflows, enroll contacts, or start a manual run. Test keys cannot call these routes, including the read routes.
MCP clients reach the same operations through stateless Streamable HTTP at POST /api/mcp, using protocol version 2025-11-25 and the existing live API bearer key. GET is not supported, and the endpoint does not use SSE. There is no new OAuth flow or browser-safe key format; keep the secret on your server.
Saving requires the complete workflow definition and a positive expectedRevision, even when the submitted definition is unchanged. A stale revision returns 409; read the current workflow again and review the newer version before saving. Graph updates use complete graph and trigger snapshots; the trigger configuration must match the subject type in the definition. Only legacy linear workflows can be saved without a graph snapshot, and an existing graph workflow cannot be downgraded by omitting one. Saving a draft does not publish it: publish names the exact draftRevisionNumber, while pause is a separate operation. Every write requires Idempotency-Key. Graph drafts may preserve incomplete action payloads; publish performs the canonical graph and action validation and rejects an invalid or incomplete workflow.
For the member permissions and API-key scopes required by these routes, see Auth and Scopes. The Examples page walks through the read-review-save-publish-pause sequence without rebuilding a workflow from partial fields.
V2 differs from V1 in a few places:
- Creating a client requires
address_line1,city,state, andzip, because every V2 client owns a property. - A lead's
sourcemust name one of the workspace's active lead sources. - A lead for an
existing_client_idmay omitservice_address; it lands on that client's primary saved property. Sendingnoteswithexisting_client_idis refused (update the client instead). - A lead without
assigned_togoes to the member who created the API key, or to the workspace owner once that member is deactivated. - Request bodies are limited to 1 MiB (
413 body_too_large), and a body that is not valid JSON returns400 invalid_json. connector_keyhands the lead to a lead connector: its aliases, source label, assigned rep, and notes prefix apply, an incomplete payload answers202with animport_idand waits in Settings > Integrations > Lead Connectors > Review Queue, and a key from another workspace or an inactive connector answers422onconnector_key.Idempotency-Keymust be 1 to 255 printable characters; anything else returns422 invalid_idempotency_key, and a missing header returns422 missing_idempotency_key.- Unexpected failures return
500 internal_errorwith a fixed message and anX-Request-IDyou can quote to support.
What v1 Is For
Use the external API when you need to:
- Create leads from a partner form or marketing source
- Sync clients into another system
- Write internal CRM notes onto client, lead, and job records from your own middleware or automation layer
- Generate estimates from an approved upstream workflow
- Patch existing estimate customer details, assignment, draft/sent status, or expiration without recreating the quote
- Read jobs or invoices into reporting tools
- Trigger downstream automations from outbound webhooks
For the V1 public surface, note fields are available on clients, leads, and jobs. See the V1 Examples page for copy-paste POST and PATCH requests.
When released, live-key POST /api/v1/estimates will create an empty draft from an existing client or lead and a location. It does not accept pricing, line items, totals, status, or delivery instructions, and its response does not include a customer view_url. The office must finish and send the draft through Clean Estimate. Test-key estimate writes remain isolated sandbox records and do not create live estimates.
What v1 Does Not Cover Yet
The public API still does not expose every internal CE Pro surface. Proposal-family endpoints, report snapshots, team and schedule snapshots, service catalog reads, pricing reads, customer-sign actions, and PDF/duplicate helper routes remain internal for now.
The old Phase 2 proposal/reporting docs described a broader future V1 surface that is not part of the shipped V1 contract. Within V1, use /api/v1/openapi.json as the source of truth.
Base URL And Contract
- Base URL:
https://app.cleanestimate.pro/api/v1 - Auth:
Authorization: Bearer ce_live_...orAuthorization: Bearer ce_test_... - Writes:
POSTandPATCHrequireIdempotency-Key, includingPATCH /api/v1/estimates/{id} - Correlation: every response includes
X-Request-ID - Rate limits: every response includes
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset - Browser safety: this API is for server-to-server use only. Never expose secret API keys in frontend code.
- Schema:
/api/v1/openapi.json
Shipped Resource Groups
- Core workflow:
leads,clients,estimates,jobs,invoices - Webhook management:
webhooks
Response Shape
Single-record responses use:
{
"data": {
"id": "..."
}
}List responses use:
{
"data": [],
"meta": {
"next_cursor": "opaque-cursor",
"has_more": true,
"limit": 25
}
}Errors use:
{
"error": {
"code": "validation_error",
"message": "Invalid request body",
"details": []
}
}Common error codes:
400 invalid_json401 invalid_api_key403 insufficient_scope403 unsupported_in_test_mode404 not_found405 write_not_supported(V2 only: the write exists in V1 but is not available yet)409 idempotency_conflict409 idempotency_in_progress409 invalid_state413 body_too_large422 validation_error422 missing_idempotency_key422 invalid_idempotency_key422 invalid_cursorand422 invalid_sort429 rate_limited500 internal_error503 rate_limit_unavailable
Live And Test Keys
CleanEstimatePro supports separate live and test keys:
ce_live_...keys can use the full V1 public surface.ce_test_...keys are for sandbox integrations.
In v1, test-key writes are intentionally limited to leads, clients, and estimates. Test-key writes are stored separately from live records and do not trigger normal outbound side effects.
V1 webhook management is live-key-only. Test keys cannot call:
/api/v1/webhooks
Related Inbound Channels
Not every integration starts with REST:
- Email intake: forward lead emails to the address shown on an email connector's card in Settings > Integrations > Lead Connectors (V2)
- Website forms: post to the public endpoint shown on a website form connector's card (V2)
- Booking widget:
/api/portal/[orgSlug]/book - Automation webhook intake (V1 reference; not exposed by current V2):
POST /api/automations/webhooks/inbound
- Outbound events (V1): register webhook destinations through
/api/v1/webhooks
Do not call the V1 automation intake route against current V2; no configurable automation webhook endpoint is registered. Outbound /api/v1/webhooks management, by contrast, is live in V2 with a live key (see the table above).
Start with your workspace's /api/v1/openapi.json: it lists exactly the routes that are live in V2. The companion pages in this Developers section carry the same Current V2 status note at the top.
Related articles
Was this article helpful?
Still need help? Contact support