Quantom API

A full read and write REST API for your CRM. Every request carries a bearer key, and every key is held to the permissions of the person who made it.

Base URLhttps://crm-api.curepay.dev
Start here

Getting started

That hostname serves the API and nothing else. It answers /api/..., returns 404 for everything else, and has no sign-in page because there is no session to have.

Create a key in Quantom under Integrations, then Developer REST API. It is shown once. Send it on every request:

curl https://crm-api.curepay.dev/api/deals \
  -H 'Authorization: Bearer cpk_your_key'

Authentication, and what a key can do

A key inherits the permissions of whoever created it.

An owner's key can do everything an owner can, including delete, from anywhere, with no second factor. Scope it when you make it: the form offers every permission you hold, and a key for a website form needs one of them, not all of them.

A key can also be given a lifetime. A key with no expiry never expires, which is the right choice for a sync you own and the wrong one for a contractor.

Keys cannot manage keys. A leaked key cannot mint itself a replacement, so revoking it in Quantom stops it immediately and permanently.

Errors, and how to read a 403

Errors are JSON with an error field. A 403 from a scoped key also names the permission it wanted, so you can go and tick that one rather than guessing:

{ "error": "That API key doesn't grant this.", "perm": "deals.view" }

401 means the key is wrong, expired or missing. 403 means the key is good and the permission is not. 404 means the path is not one this API serves.

Reference

Endpoints

The permission beside each route is the one it checks. Two names joined by + means it wants both: a section gate, and a second check inside it.

The pipeline

GET/api/deals

Requiresdeals.view

Every deal, paged. ?limit= and ?cursor=. Each carries cpid, the CurePay id of the client it became, and did, its Deal ID (DID-2025-0012) once it is on that client's Deals tab; both are empty until then.

GET/api/deals/{id}

Requiresdeals.view

One deal, whole, with its did and cpid. {id} is the deal's id or any Deal ID; a DID that is not a pipeline deal (a register deal, a Service Program, a marketing contract) answers with its Client IQ row.

POST/api/deals

Requiresdeals.edit

Create one. { name*, company, email, phone, value, stage, source, address }. A new deal has no did until it is on a client's Deals tab.

GET/api/contacts

Requirescontacts.view

Contacts, paged.

POST/api/contacts

Requirescontacts.edit

Create one. { name*, email, phone, company }

GET/api/tasks

Requirescalendar.view

Open tasks.

POST/api/tasks

Requirescalendar.edit

Create one. { title*, due, related }

Customer reports

GET/api/clienttasks/report?client=&period=month

Requiresclienttasks.view + reports.view

THE CUSTOMER REPORT. A month or a quarter of everything for one client, next to the period before it. client= is the name, the id or the CPID (CPID-2025-0007), or send cpid= instead. period=month|quarter. Takes both rights: the section gate and the money on the page.

POST/api/reports/run

Requiresreports.view

Run any report the builder can build. { entity, groupBy, measures, dateField, from, to, filters }

GET/api/clienttasks/projection?client=

Requiresclientiq.view + commerce.view

Seven years of projected revenue for one client.

GET/api/goals

Requiresreports.view

Goal attainment and the weighted pipeline forecast.

GET/api/clienttasks/deals?did=

Requiresclientiq.view

One deal by its DID (DID-2025-0013), with the client it is on, whoever's it is. Leave did= off for every Client IQ deal in the book, 500 a page, with ?cursor= for the next. Only deals on a client's Deals tab: canvassing leads are not deals and are not here.

GET/api/clienttasks/deals?client=

Requiresclientiq.view

Every deal on one client, one row each, as the Deals tab lists them: the register's processing deal and its Service Program are two deals, each marketing contract and one-off is one, and so is each pipeline deal on a line. Each has its did (DID-2025-0012). client= is the name or the CPID, or send cpid=.

GET/api/clienttasks/intel?client=

Requiresclientiq.view

One client’s intelligence payload: onboarding, revenue, work, documents. client= is the name or the CPID; the CPID picks the exact client where two share a name.

GET/api/clienttasks/spine?mid=

Requiresclientiq.view

One merchant from the deal that sold it to the last residual it earned.

Clients

GET/api/clienttasks?slim=1

Requiresclienttasks.view

The client roster. slim=1 returns id, cpid, name, status, token and setup only.

GET/api/clienttasks/client?id=

Requiresclienttasks.view

One client, whole. id= is the client id or its CPID.

POST/api/clienttasks/deliverable

Requiresclienttasks.edit

File something made for a client onto their record. { clientId*, tool*, name, ref* }

Marketing

GET/api/campaigns

Requiresmarketing.view

Campaigns and their attributed leads.

GET/api/content

Requiresmarketing.view

The Content Writer library.

GET/api/docs

Requiresmarketing.view

Shared PDFs: name, size, who uploaded it, how many times it has been opened, and the public link.

POST/api/content/outline

Requiresmarketing.edit

Plan a piece. { brief }

POST/api/content/draft

Requiresmarketing.edit

Write it from an outline. { brief, outline }

Commerce

GET/api/invoicing/invoices

Requirescommerce.view

Every saved invoice, with who and how much.

GET/api/invoicing/invoices/{number}

Requirescommerce.view

One invoice, whole.

Recipes

How to connect it

1Pull a customer report every month

The report behind a client's monthly review: this period against the one before it, with the figures the CRM recorded rather than estimated.

curl 'https://crm-api.curepay.dev/api/clienttasks/report?cpid=CPID-2025-0007&period=month' \
  -H 'Authorization: Bearer cpk_your_key'

Takes two rights: clienttasks.view to reach the section and reports.view because it puts money on the page. period is month or quarter. Ask by CPID where you have it: a name is matched too, but two clients can share one, and the CPID is the exact client.

2Put a website enquiry straight into the pipeline

The usual first integration. Your contact form posts here and the deal appears on the board with a source you can report on.

curl -X POST https://crm-api.curepay.dev/api/deals \
  -H 'Authorization: Bearer cpk_your_key' \
  -H 'content-type: application/json' \
  -d '{"name":"Jane Reyes","company":"Acme Dental","email":"jane@acme.com",
       "phone":"555-0142","value":4800,"source":"Website form"}'

Scope this key to deals.edit and nothing else. A form key that can also read payroll is a form key that reads payroll the day the site is compromised.

3Sync the client roster into a spreadsheet

The slim roster is the whole client list with six fields on it, CPID included, which is what a sheet wants. The full record is one call per client and is rarely what you mean.

curl 'https://crm-api.curepay.dev/api/clienttasks?slim=1' \
  -H 'Authorization: Bearer cpk_your_key'

Drop the ?slim=1 and every field comes back, which on 1,700 clients is about 1.5 MB. Ask for slim unless you need the rest.

4Wire it to Zapier, n8n or Make

All three speak plain HTTP, so there is no connector to install: a Webhooks step with a bearer header is the whole integration.

URL     https://crm-api.curepay.dev/api/deals
Method  POST
Headers Authorization: Bearer cpk_your_key
        content-type: application/json
Body    {"name":"{{name}}","email":"{{email}}","source":"Zapier"}

Give each tool its own key and name it after the tool. When something starts behaving oddly you revoke one key rather than guessing which of five things broke.

5Write a page for a client from your own script

The Content Writer plans first and drafts from the plan, so it is two calls. The outline comes back as JSON you can edit before you spend the second one.

curl -X POST https://crm-api.curepay.dev/api/content/outline \
  -H 'Authorization: Bearer cpk_your_key' -H 'content-type: application/json' \
  -d '{"brief":{"topic":"How much does a card terminal cost?","len":"standard"}}'

# then, with the sections it returned (edited or not):
curl -X POST https://crm-api.curepay.dev/api/content/draft \
  -H 'Authorization: Bearer cpk_your_key' -H 'content-type: application/json' \
  -d '{"brief":{...},"outline":[{"heading":"...","level":2,"words":300}]}'

Both cost a model call, so both take marketing.edit. A draft of two thousand words takes about thirty seconds and is not streamed.

Nothing on this page matches that.
Generated from the same endpoint table the application and its tests read, so it cannot describe a route that does not exist. Open Quantom