REST API · v1

Kanvo API Reference

Integrate Kanvo with your own systems. Create and update records, manage tasks, and subscribe to real-time events via webhooks.

Base URL: https://kanvocrm.com/api/v1Auth: Bearer token

Overview

The Kanvo API is a REST API that allows external systems to read and write data in your Kanvo workspace. All requests must be authenticated with an API key generated in Settings → Advanced → API Keys.

All endpoints return JSON. The base URL for all API requests is:

text
https://kanvocrm.com/api/v1

The API follows conventional REST patterns — GET to read, POST to create, PATCH to update, and DELETE to remove.


Authentication

All API requests must include your API key in the Authorization header as a Bearer token. Create and manage API keys at Settings → Advanced → API Keys inside your dashboard.

Each key has an assigned scope that controls what it can do:

NameTypeDescription
readscopeFetch records, tasks, and schema. Cannot create, update, or delete.
writescopeAll read permissions, plus create, update, and delete access for records and tasks.
adminscopeAll write permissions, plus webhook management.
bash
curl https://kanvocrm.com/api/v1/records \
  -H "Authorization: Bearer kv_live_your_api_key_here"
🔒 Keep your API keys secret. Never expose them in client-side code or public repositories. Rotate compromised keys immediately from the dashboard.

Errors & Status Codes

All error responses use standard HTTP status codes and return a consistent JSON body.

NameTypeDescription
200OKRequest succeeded.
400Bad RequestMissing or invalid parameters.
401UnauthorizedMissing or invalid API key.
403ForbiddenAPI key lacks the required scope for this operation.
404Not FoundResource doesn't exist or belongs to a different workspace.
500Server ErrorUnexpected error. Contact support if it persists.
json
{
  "success": false,
  "error": "Object type 'lead' not found"
}

Pagination

List endpoints are paginated. Use page and per_page query parameters.

NameTypeDescription
pageintegerPage number, starting at 1. Defaults to 1.
per_pageintegerResults per page. Defaults to 50, max 100.
json
{
  "success": true,
  "data": [...],
  "meta": {
    "total": 237,
    "page": 2,
    "per_page": 50
  }
}

Records

Records are the central data object in Kanvo — leads, jobs, estimates, clients, and any custom object types you create. Each record belongs to an object type identified by its slug, and optionally sits in a pipeline stage.

List records

GEThttps://kanvocrm.com/api/v1/records
NameTypeDescription
typestringFilter by object type slug (e.g. lead, job, estimate).
searchstringCase-insensitive title search.
assignee_iduuidFilter by assigned team member UUID.
pageintegerPage number. Defaults to 1.
per_pageintegerResults per page. Defaults to 50.
bash
curl "https://kanvocrm.com/api/v1/records?type=lead&per_page=10" \
  -H "Authorization: Bearer kv_live_..."
json
{
  "success": true,
  "data": [
    {
      "id": "b3e1a2f4-...",
      "title": "Johnson Property - Lawn Care",
      "object_type_id": "a1b2c3d4-...",
      "stage_id": "f5e6d7c8-...",
      "assignee_id": null,
      "data": { "phone": "555-123-4567" },
      "created_at": "2026-03-14T18:30:00.000Z",
      "updated_at": "2026-03-14T18:30:00.000Z",
      "object_types": { "name": "Lead", "slug": "lead", "icon": "👤" }
    }
  ],
  "meta": { "total": 84, "page": 1, "per_page": 10 }
}

Get a record

GEThttps://kanvocrm.com/api/v1/records/:id
bash
curl "https://kanvocrm.com/api/v1/records/b3e1a2f4-..." \
  -H "Authorization: Bearer kv_live_..."

Create a record

POSThttps://kanvocrm.com/api/v1/records
NameTypeDescription
typerequiredstringObject type slug. Must match a type in your workspace (e.g. lead, job).
titlestringDisplay name of the record. Defaults to 'Untitled'.
dataobjectFree-form JSONB data for any custom fields.
assignee_iduuidUUID of the team member to assign this record to.
stage_iduuidDirect stage UUID. Use this or pipeline + stage, not both.
pipelinestringPipeline name, slug, or UUID. Places the record in the first stage unless stage is also specified.
stagestringStage name, slug, or UUID within the specified pipeline.
bash
curl -X POST https://kanvocrm.com/api/v1/records \
  -H "Authorization: Bearer kv_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "lead",
    "title": "Smith Residence - Spring Cleanup",
    "pipeline": "main-sales",
    "stage": "new",
    "data": {
      "phone": "555-999-0001",
      "address": "42 Elm Street, Hartford CT"
    }
  }'
Fires the record.created webhook event. If a pipeline stage is specified, also fires pipeline.stage_changed.

Update a record

PATCHhttps://kanvocrm.com/api/v1/records/:id

Only include fields you want to change. Omitted fields are left untouched.

NameTypeDescription
titlestringNew display name.
dataobjectReplaces the entire data object. Fetch first if you need to merge.
assignee_iduuidReassign the record. Pass null to unassign.
stage_iduuidMove to a new pipeline stage.
bash
curl -X PATCH https://kanvocrm.com/api/v1/records/b3e1a2f4-... \
  -H "Authorization: Bearer kv_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "stage_id": "c9d0e1f2-..." }'
Fires record.updated. If stage_id changed, also fires pipeline.stage_changed.

Delete a record

DELETEhttps://kanvocrm.com/api/v1/records/:id

Soft-deletes the record by setting deleted_at. Excluded from all future list queries.

bash
curl -X DELETE https://kanvocrm.com/api/v1/records/b3e1a2f4-... \
  -H "Authorization: Bearer kv_live_..."
json
{ "success": true, "data": { "deleted": true, "id": "b3e1a2f4-..." } }

Tasks

Tasks can be standalone or linked to a specific record via record_id.

List tasks

GEThttps://kanvocrm.com/api/v1/records/tasks
NameTypeDescription
record_iduuidFilter to tasks attached to a specific record.
assignee_iduuidFilter by assigned team member.
completedbooleantrue returns completed tasks only; false returns open tasks only.
pageintegerPage number.
per_pageintegerResults per page.
bash
curl "https://kanvocrm.com/api/v1/records/tasks?record_id=b3e1a2f4-...&completed=false" \
  -H "Authorization: Bearer kv_live_..."

Get a task

GEThttps://kanvocrm.com/api/v1/records/tasks/:id

Create a task

POSThttps://kanvocrm.com/api/v1/records/tasks
NameTypeDescription
titlerequiredstringTask title.
record_iduuidLink to a record.
assignee_iduuidAssign to a team member.
due_dateISO 8601Due date, e.g. 2026-06-30.
notesstringOptional notes or description.
bash
curl -X POST https://kanvocrm.com/api/v1/records/tasks \
  -H "Authorization: Bearer kv_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Follow up on estimate",
    "record_id": "b3e1a2f4-...",
    "due_date": "2026-07-01"
  }'

Update a task

PATCHhttps://kanvocrm.com/api/v1/records/tasks/:id
NameTypeDescription
titlestringNew title.
completedbooleantrue to mark complete, false to reopen.
assignee_iduuidReassign.
due_dateISO 8601Update due date.
notesstringUpdate notes.

Delete a task

DELETEhttps://kanvocrm.com/api/v1/records/tasks/:id

Webhooks

Webhooks let Kanvo push real-time event notifications to your server. Register an HTTPS endpoint and subscribe to specific events. Webhook management requires the admin scope.

List webhooks

GEThttps://kanvocrm.com/api/v1/webhooks
json
{
  "success": true,
  "data": [
    {
      "id": "wh_abc123",
      "url": "https://your-app.com/hooks/kanvo",
      "events": ["record.created", "pipeline.stage_changed"],
      "is_active": true,
      "last_triggered_at": "2026-06-17T14:20:00Z",
      "last_status": 200,
      "failure_count": 0,
      "created_at": "2026-03-01T10:00:00Z"
    }
  ]
}

Register a webhook

POSThttps://kanvocrm.com/api/v1/webhooks
NameTypeDescription
urlrequiredstringHTTPS endpoint URL to receive event payloads.
eventsrequiredstring[]Array of event names to subscribe to.
bash
curl -X POST https://kanvocrm.com/api/v1/webhooks \
  -H "Authorization: Bearer kv_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/hooks/kanvo",
    "events": ["record.created", "record.updated", "pipeline.stage_changed"]
  }'
The signing secret is only returned once — in the response to this creation request. Store it securely to verify future payloads.

Delete a webhook

DELETEhttps://kanvocrm.com/api/v1/webhooks?id=:id
bash
curl -X DELETE "https://kanvocrm.com/api/v1/webhooks?id=wh_abc123" \
  -H "Authorization: Bearer kv_live_..."

Event reference

All subscribable event names:

record.createdrecord.updatedrecord.deletedtask.createdtask.updatedtask.deletedtask.completedpipeline.stage_changedcontract.createdcontract.signedform.submittedcontact.createdcontact.updated

Payload signing

Every delivery includes a X-Kanvo-Signature header — an HMAC-SHA256 signature of the raw request body using your endpoint's signing secret. Verify it to confirm the request originated from Kanvo.

javascript
import { createHmac } from "crypto";

function verifyKanvoWebhook(rawBody, signature, secret) {
  const expected = createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return `sha256=${expected}` === signature;
}

// In your request handler:
const rawBody = await request.text();
const sig = request.headers.get("x-kanvo-signature");

if (!verifyKanvoWebhook(rawBody, sig, process.env.KANVO_WEBHOOK_SECRET)) {
  return new Response("Forbidden", { status: 403 });
}

const event = JSON.parse(rawBody);
console.log(event.event, event.data);

Payload shape for all events:

json
{
  "event": "record.created",
  "workspace_id": "ws_abc123",
  "timestamp": "2026-06-17T14:20:00.000Z",
  "data": {
    "id": "b3e1a2f4-...",
    "title": "Smith Residence",
    "object_type_id": "...",
    "stage_id": "...",
    "assignee_id": null,
    "data": {},
    "created_at": "2026-06-17T14:20:00.000Z"
  }
}

Schema

Fetch your workspace's object types and pipeline structure. Useful when building integrations that need to know which types and stages exist before creating records.

GEThttps://kanvocrm.com/api/v1/schema
bash
curl https://kanvocrm.com/api/v1/schema \
  -H "Authorization: Bearer kv_live_..."
json
{
  "success": true,
  "data": {
    "object_types": [
      { "id": "a1b2...", "name": "Lead", "slug": "lead", "icon": "👤" },
      { "id": "c3d4...", "name": "Job", "slug": "job", "icon": "🔧" },
      { "id": "e5f6...", "name": "Estimate", "slug": "estimate", "icon": "📋" }
    ],
    "pipelines": [
      {
        "id": "p1q2...",
        "name": "Main Sales",
        "slug": "main-sales",
        "stages": [
          { "id": "s1t2...", "name": "New", "slug": "new", "position": 0 },
          { "id": "s3t4...", "name": "Contacted", "slug": "contacted", "position": 1 },
          { "id": "s5t6...", "name": "Won", "slug": "won", "position": 2 }
        ]
      }
    ]
  }
}