Skip to content
All guides

REST API

Read and write your CRM data from your own systems. Create a key in Settings, then call the JSON API over HTTPS.

  • Create keys in Settings under API keys. Choose read-only or read-and-write. The token (csk_…) is shown once and stored hashed; revoke a key at any time and it stops working immediately.
  • Authenticate every request with a header: Authorization: Bearer csk_…
  • Resources: /api/v1/companies, /api/v1/contacts, /api/v1/leads and /api/v1/deals. Each supports GET (list), POST (create), and GET or PATCH on /api/v1/<resource>/<id>.
  • Product usage: POST to /api/v1/usage with a read-and-write key to feed the customer health score shown on each company. Send one object or an array of up to 500, each {"company_id": "…", "metric": "activity", "count": 1, "occurred_at": "…"}. Only company_id is required: metric defaults to activity, count to 1, and occurred_at to the time of the call. A 202 comes back with accepted and a rejected list naming any company id the workspace does not hold, so a partial batch tells you which rows landed.
  • Workspaces with the Contracts module also get /api/v1/agreements and /api/v1/obligations. These are read-only: GET a list or GET one by id. A POST or PATCH returns 405, and a workspace without the module gets 403 saying so. The register is evidence about your contracts, so it is not somewhere an integration should be able to write.
  • The API returns the facts about the paper and keeps the contract text and citation quotes in the app. Fetch a document from the app when you need the paper itself.
  • On an obligation, owed_by (ours, theirs, mutual, unsure) and survives_termination (yes, no, unsure) and extraction_confidence (high, medium, low) can all be null, and null means NOTHING HAS ANSWERED: either the row was read before that field existed, or the reading judged the row is not a duty anyone performs. Null is not the same as no. Treating it as a negative is the exact mistake those fields exist to prevent, so branch on the value explicitly.
  • Lists return newest first with cursor pagination: pass ?limit=50 and follow next_cursor until it is null.
  • A cursor is opaque, server-sealed and short-lived: read it as a token to hand straight back, not as a value to parse, store or build. A 422 Malformed cursor means that one is no longer usable, so start the collection again from the first page.
  • Bodies are JSON. Field names are snake_case in responses; creates and updates accept the same fields you see in the app, including custom for your custom fields. Deal amounts are major units ("amount": "12500"); responses carry amount_minor.
  • Every write made with a key is recorded on the workspace ledger under that key's identity, so API activity audits exactly like a person's.
  • Errors are JSON too: {"error":{"message":"…"}} with conventional status codes (401 bad key, 403 read-only key writing or a module you do not have, 404 not found, 405 writing to a read-only resource, 422 validation).
  • Prefer no-code? The web-to-lead capture endpoint accepts form submissions without a key, and CSV import and export cover bulk moves.