Developer documentation

The Root Digit CRM API

A REST API over every record in your workspace. Authenticate with a scoped key you create yourself, read and write the objects that key names, and receive signed webhooks when records change.

BASE URL https://api-crm.rootdigit.com

Authentication

Keys are created by a workspace administrator under Settings, Developer and API access. The key is shown once. Send it on every request. Integrations have no login endpoint and no OAuth flow; AI assistants sign in a different way, described below.

curl https://api-crm.rootdigit.com/api/v1/contact?limit=10 \
  -H "Authorization: ApiKey rk_live_your_key_here"

A key is not an administrator

Keys reach the record endpoints below and nothing else. Workspace administration, billing, integrations and the audit log require a signed-in session, and a request outside that surface is refused with api_key_scope whatever scopes the key holds.

Plans and trials

Keys and AI assistants work from the Growth plan up. During a workspace's 14-day free trial they are refused with 403 and reason: "trial"; during a one-day trial they keep only what the paid plan includes. Exports are refused while either trial runs: GET /api/v1/export/{object} answers 403 with reason trial or day_trial, and GET /api/v1/export still lists what there is, with the reason in paused.

Objects and scopes

Each object has a read scope and a write scope. A key is granted scopes when it is created and cannot grant itself more later.

ObjectPath segmentRead scopeWrite scope
Contactscontactcontacts:readcontacts:write
Companiescompanycompanies:readcompanies:write
Leadsleadleads:readleads:write
Dealsdealdeals:readdeals:write
Taskstasktasks:readtasks:write
Calendar eventseventevents:readevents:write
Campaignscampaigncampaigns:readcampaigns:write
Invoicesinvoiceinvoices:readinvoices:write
Credit notescreditnotecreditnotes:readcreditnotes:write
Recurring invoicesrecurringrecurring:readrecurring:write
Productsproductproducts:readproducts:write
Quotesquotequotes:readquotes:write
Support casescasecases:readcases:write
Visitsvisitvisits:readvisits:write
Inventory itemsinventoryinventories:readinventories:write
Processesprocessprocesses:readprocesses:write
Forecastsforecastforecasts:readforecasts:write
Knowledge articlesarticlearticles:readarticles:write
Price bookspricebookpricebooks:readpricebooks:write
Vendorsvendorvendors:readvendors:write
Sales orderssalesordersalesorders:readsalesorders:write
Purchase orderspurchaseorderpurchaseorders:readpurchaseorders:write

Endpoints

Replace {object} with a path segment from the table above, and {id} with a record id.

MethodPathWhat it doesScope
GET/api/v1/schemaEvery object with its fields, including custom fields.Any valid key
GET/api/v1/schema/{object}Fields for one object.Any valid key
GET/api/v1/{object}List records. Supports limit, cursor, q, field filters, and sort=newest for newest first.{object}:read
GET/api/v1/{object}/{id}Read one record.{object}:read
POST/api/v1/{object}Create a record. Honours Idempotency-Key.{object}:write
PATCH/api/v1/{object}/{id}Update a record. Send only the fields that change.{object}:write
DELETE/api/v1/{object}/{id}Move a record to the recycle bin.{object}:write
POST/api/v1/{object}/{id}/restoreRestore a record from the recycle bin.{object}:write
POST/api/v1/{object}/bulkCreate or update many records in one request.{object}:write
GET/api/v1/recycle-binRecords deleted but not yet purged.Any valid key
GET/api/v1/lead/{id}/convertWhat converting this lead would do: the company and contact it matches, and the opportunity it would open.leads:read
POST/api/v1/lead/{id}/convertConvert a lead into a company, a contact and (optionally) an opportunity, in one transaction.leads:write
GET/api/v1/duplicatesRecords this workspace already holds twice, by its own matching rules.Any valid key
GET/api/v1/{object}/merge-previewTwo records side by side: which fields differ, and what a merge would move.{object}:read
POST/api/v1/{object}/mergeMerge one record into another, choosing which value survives per field.{object}:write
GET/api/v1/exportWhat can be exported, and how many records of each object. During a trial it still answers, with paused saying why the files wait.Any valid key
GET/api/v1/export/{object}Every record of one object as CSV, including custom fields. Free, and as often as you like — except while a trial runs, when it is refused (403, reason trial or day_trial).{object}:read
GET/api/v1/openapi.jsonThis API as an OpenAPI 3.2.1 description, for generating clients. No key; ?oas=3.1 for a 3.1 copy.Any valid key
GET/api/v1/openapi/workspace.jsonThe same description for your key: only what its scopes open, with your custom fields and modules.Any valid key
GET/api/v1/public/form/{tenant}/{form}A published form's fields, for rendering it yourself. No key.Any valid key
POST/api/v1/public/form/{tenant}/{form}Submit a form. Body: values (the field keys), company (leave empty — it is the spam trap) and elapsedMs (how long the form was on screen). No key.Any valid key

OpenAPI description

The API-key side of this reference as an OpenAPI 3.2.1 document: every endpoint a key can reach, each object's fields as typed schemas, the error format and the webhook payloads. It needs no key.

Called with your key, /api/v1/openapi/workspace.json describes your workspace exactly: only what the key's scopes open, with your custom fields and your own modules. Add ?oas=3.1 to either address for an OpenAPI 3.1 copy, for tools that do not read 3.2 yet.

Typed clients come straight from it. For TypeScript, with openapi-typescript:

npx openapi-typescript https://api-crm.rootdigit.com/api/v1/openapi.json -o rootdigit-crm.d.ts

Conventions

Error formatRFC 9457 problem details, as application/json with a type, title, status and code.
IdempotencySend Idempotency-Key on POST; a repeat returns the first response with Idempotent-Replay: true.
Rate and quotaWrite requests return X-Plan-Calls-Limit and X-Plan-Calls-Remaining while a limit applies.
Webhook signaturesDeliveries carry x-rootdigit-signature: t=<unix-seconds>,v1=<hex>. The v1 value is HMAC SHA-256 of "<t>.<raw body>" keyed by the endpoint secret. Compare it in constant time and reject an old timestamp.

Errors

Failures are RFC 9457 problem documents. Branch on code rather than on the message, which is written for a person and may change.

StatusCodeMeaning
400bad_requestThe request was understood but cannot be accepted as sent.
401unauthorizedThe key is missing, malformed, expired or revoked.
403forbiddenAuthenticated, but not allowed to do this.
403api_key_scopeThis endpoint is not part of the API-key surface.
403module_not_entitledThe workspace's plan does not include this module.
404not_foundNo such record, or not visible to this key.
409conflictThe change collides with something that already exists.
422validationField-level validation failed; see the errors array.
429plan_quotaThe plan's daily API allowance is used up.
429rate_limitedToo many requests in a short time. Wait the number of seconds in the Retry-After header, then try again.

Webhooks

Add an endpoint under Settings, Developer and API access. Deliveries are retried, and every attempt is recorded where you can inspect and replay it. These are the events we send, and only these.

  • contact.created
  • contact.updated
  • company.created
  • company.updated
  • lead.created
  • lead.updated
  • deal.created
  • deal.updated
  • task.created
  • task.updated
  • event.created
  • event.updated
  • campaign.created
  • campaign.updated
  • invoice.created
  • invoice.updated
  • creditnote.created
  • creditnote.updated
  • recurring.created
  • recurring.updated
  • product.created
  • product.updated
  • quote.created
  • quote.updated
  • case.created
  • case.updated
  • visit.created
  • visit.updated
  • inventory.created
  • inventory.updated
  • process.created
  • process.updated
  • forecast.created
  • forecast.updated
  • article.created
  • article.updated
  • pricebook.created
  • pricebook.updated
  • vendor.created
  • vendor.updated
  • salesorder.created
  • salesorder.updated
  • purchaseorder.created
  • purchaseorder.updated
  • record.deleted
  • invoice.paid
  • invoice.payment_received
  • invoice.payment_removed
  • automation.fired
  • invoice.payment_link_created

AI assistants

Claude, ChatGPT and other assistants can read and update your workspace through MCP, the standard way assistants connect to other software. The address is https://api-crm.rootdigit.com/api/v1/mcp. Add the address as a connector and sign in to your workspace when asked; you choose what the assistant may read and change. A key works too, for tools that take a custom header.

  • Claude Desktop and ChatGPT: add https://api-crm.rootdigit.com/api/v1/mcp as a connector, then sign in.
  • Claude Code: claude mcp add --transport http rootdigit https://api-crm.rootdigit.com/api/v1/mcp — then sign in, or pass --header "Authorization: Bearer rk_live_…".
  • Cursor, Windsurf and any other MCP client that accepts a sign-in or a custom header.

What an assistant can do: list_objects, describe_object, list_records, get_record, create_record, update_record. It sees and changes only what the person who connected it may, within the access they gave it.

Before you connect one

Growth and above, as the REST API. Not on the free plan or during the free trial; during a one-day trial a key or an assistant keeps only what the paid plan includes. Give read access only, unless you want the assistant to change records.

Create a workspace and get a key