External API Overview

The public REST API used by CRM sync, forms, automations, and partner integrations, with what is live in V2 today.

IntermediateownermanagerdeveloperUpdated 2026-09-24

External API Overview

Current V2 status (2026-09-22): /api/v1 is 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-key POST /api/v1/estimates is merged but pending production; it will create an empty draft only. Until that release, live requests to it still receive 405 write_not_supported. API keys are managed in Settings > Integrations > External API keys. Outbound webhook endpoints are managed in Settings or through /api/v1/webhooks with 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.json as 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

CapabilityV2 today
GET /api/v1/{leads,clients,estimates,jobs,invoices} and GET .../{id}Live
POST /api/v1/leads and POST /api/v1/clientsLive
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 recordsLive: test keys read and write sandbox leads, clients, and estimates
/api/v1/openapi.jsonLive
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 statusNot 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}/pauseLive; changes apply only to existing workflows
MCP automation tools at POST /api/mcpLive; stateless Streamable HTTP with the same live-key access rules
GET /api/v1/workflows, workflow schema discovery, query and mutation operations, and durable mutation receiptsAvailable 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.

RequestPurposeRequired workflow scope
GET /api/v1/workflowsDiscover operations visible to the key, including each operation's name, kind, and required scopeworkflows:read
GET /api/v1/workflows?operation={operation-name}Read one operation's input JSON Schema and input_schema_statusworkflows:read
GET /api/v1/workflows/{operation}?input={URL-encoded-JSON}Run a query operationworkflows:read
POST /api/v1/workflows/{operation} with JSON inputRun a query operation; no idempotency key or mutation receiptworkflows:read
POST /api/v1/workflows/{operation} with JSON input and Idempotency-KeyRun a mutation operationworkflows:write
GET /api/v1/workflows/requests/{requestId}Read the durable receipt for a mutationworkflows: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, and zip, because every V2 client owns a property.
  • A lead's source must name one of the workspace's active lead sources.
  • A lead for an existing_client_id may omit service_address; it lands on that client's primary saved property. Sending notes with existing_client_id is refused (update the client instead).
  • A lead without assigned_to goes 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 returns 400 invalid_json.
  • connector_key hands the lead to a lead connector: its aliases, source label, assigned rep, and notes prefix apply, an incomplete payload answers 202 with an import_id and waits in Settings > Integrations > Lead Connectors > Review Queue, and a key from another workspace or an inactive connector answers 422 on connector_key.
  • Idempotency-Key must be 1 to 255 printable characters; anything else returns 422 invalid_idempotency_key, and a missing header returns 422 missing_idempotency_key.
  • Unexpected failures return 500 internal_error with a fixed message and an X-Request-ID you 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_... or Authorization: Bearer ce_test_...
  • Writes: POST and PATCH require Idempotency-Key, including PATCH /api/v1/estimates/{id}
  • Correlation: every response includes X-Request-ID
  • Rate limits: every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-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_json
  • 401 invalid_api_key
  • 403 insufficient_scope
  • 403 unsupported_in_test_mode
  • 404 not_found
  • 405 write_not_supported (V2 only: the write exists in V1 but is not available yet)
  • 409 idempotency_conflict
  • 409 idempotency_in_progress
  • 409 invalid_state
  • 413 body_too_large
  • 422 validation_error
  • 422 missing_idempotency_key
  • 422 invalid_idempotency_key
  • 422 invalid_cursor and 422 invalid_sort
  • 429 rate_limited
  • 500 internal_error
  • 503 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

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.

Was this article helpful?

Still need help? Contact support