# AI CRM Nepal API documentation

Verified against the implementation: 2026-10-11. Public documentation: https://www.aicrmnepal.com/api-docs

OpenAPI 3.1: https://www.aicrmnepal.com/openapi.json

## Authentication & setup

Sign in to the CRM and open Automation with a profile that has automation permission. Generate a workspace Bearer token, copy it to your server's secret storage and enable API lead intake. Send Authorization: Bearer YOUR_WORKSPACE_TOKEN and Content-Type: application/json. All six integration endpoints use POST with a JSON body, including reads. Tokens are workspace-scoped; do not send a workspace_id to switch tenants. Revoking or regenerating invalidates the old token. Intake, lead-details and task-create require intake to be enabled. The three update endpoints validate an active token but currently do not require that toggle to be on; revoke the token to stop every integration.

## Choose one lead identifier

For lead-details, lead-note, lead-pipeline and lead-assignee, at least one of crm_id, supabase_id, accounting_id or phone is compulsory. The same references optionally link task-create to a lead. Send only one identifier per request. If multiple are supplied, every provided value is validated, then lookup priority is CRM ID > Supabase ID > Accounting ID > phone. An ID that is not found never falls back to the phone. IDs are generated by the CRM and cannot be changed through these APIs. Always use IDs returned by your own workspace.

## Response objects

Lead details return id, crm_id, supabase_id, accounting_id, name, phone, email, business_name, pan_vat_number, lead_date, next_follow_up_at, expected_budget, earned_amount, source, status, pipeline_stage, pipeline_option_id, pipeline_label, interested_option_id, interested_in, city_option_id, city_district, assignee_ids, assignee_labels, assignee, creator, latest_note, created_at and updated_at. Other lead-write endpoints return the lead snapshot with pipeline_display_label, interested_label, city_label and notes names rather than the details endpoint's display aliases. Nullable fields may be null. Notes contain id, content, created_at and author (id, full_name, email, role); author may be null.

## Rate limits & errors

Request JSON is limited to 64 KiB (65,536 UTF-8 bytes), including chunked uploads. Oversized bodies return 413. Each workspace has a separate 60-second window per endpoint: intake 60 requests, each other integration endpoint 120. Read X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix seconds) and X-RateLimit-Policy when present; some early validation errors omit them. 429 includes Retry-After in seconds. Errors are JSON with error and sometimes fields, message or retryAfterSeconds. 400: invalid payload/options/member; 401: missing, invalid, revoked token or disabled required intake; 402: intake lead-plan limit; 403: intake workspace suspended; 404: lead not found in this workspace; 409: duplicate intake phone; 429: rate limit; 500: server failure. Retry 429 after Retry-After and transient server failures with bounded backoff. After an ambiguous write/network timeout, reconcile before retrying: note/task writes are not idempotent and can duplicate.

## Calling agents & accounting sync

Before a call, use lead-details with include_notes:true and drain every note page using its two-part cursor. Use include_notes:false for a faster current-field read when history is unnecessary. After the call, add the outcome through lead-note and create a follow-up task. Keep CRM, Supabase and Accounting IDs in your integration's mapping table. accounting_id is our internal ACC identifier; mapping to an external accounting customer ID is your integration's responsibility. Do not claim an accounting provider is already connected. Only the six documented operations are supported with workspace Bearer tokens: there is no external lead-list, arbitrary-field edit, delete, task-list or project API yet.

## Webhooks: events & delivery

In Automation, configure separate publicly reachable HTTPS URLs and enable the events you need: lead.created, lead.pipeline_changed, lead.assignee_changed and lead.follow_up_due. Standard event payloads have event, triggered_at, profile_id, workspace_id and lead. Stage-change adds previous_pipeline_stage and pipeline_stage. Assignee-change adds previous_assignees and assignees, and is skipped for default-only assignment. Follow-up-due adds event_id and scheduled_for. Standard lead webhook snapshots omit status/status_option_id/status_display_label; due-event snapshots currently include the stored lead fields. Creation, stage and assignment events attempt delivery up to three times with a 5-second timeout and 800/1600ms delays for retryable failures. Due events use a worker with up to five attempts and scheduled backoff; delivery timing depends on that worker. A successful API write is not confirmation that its webhook was delivered. Return 2xx promptly, process work asynchronously, and deduplicate due events using event_id.

## Verify webhook signatures

Read X-AI-CRM-Timestamp, X-AI-CRM-Signature, X-AI-CRM-Event, X-AI-CRM-Workspace, X-AI-CRM-Delivery-Attempt and X-AI-CRM-Delivery-ID. The signature is sha256= followed by HMAC-SHA256 using the workspace's current automation token over timestamp + '.' + the exact raw JSON body. Do not parse/re-serialize the body before verification. Use a timing-safe comparison, reject missing/invalid signatures, verify expected workspace/event and reject stale timestamps (for example a five-minute tolerance). Standard events may have an empty delivery ID; do not treat it as a universal deduplication key. Update the verification secret when rotating the token.

## Browser and internal routes

Call integration endpoints from your backend or automation tool; no browser CORS support is promised. Never embed the Bearer token in frontend code, public URLs or AI prompts. /api/automation/settings (GET/PATCH) and /api/automation/token (POST: revoke/regenerate) are authenticated CRM-session management routes with automation permission and same-origin protection for writes. /api/automation/follow-up-dispatch (POST) is an internal worker route with a separate server secret. The application's /api/leads, /api/tasks, /api/projects, /api/analytics, /api/admin and account/settings routes are session/admin APIs, not workspace-token integration endpoints. Use the CRM UI to manage these features; do not substitute a Bearer token for a CRM session.

## POST /api/automation/intake — Create a lead

Create a new lead with generated CRM, Supabase and Accounting identifiers. Existing phone numbers return 409; this endpoint does not upsert or update existing leads.

Success: 201 { lead: Lead, identifiers: { crm_id, supabase_id, accounting_id } }

- name (string; required): Lead name, 2–200 characters after trimming.
- phone (string; required): Required mobile number, 5–32 input characters and at least 7 digits; normalized before duplicate checking.
- email (string; optional): Valid email address; empty string is accepted and stored as null.
- business_name (string; optional): Business name. Default: empty string.
- pan_vat_number (string; optional): PAN/VAT number. Default: null.
- lead_date (date; optional): Valid YYYY-MM-DD. Omitted or empty: today's Nepal date.
- earned_amount (number; optional): NPR amount, 0–1,000,000,000,000. Default: 0. Numeric strings are also coerced.
- expected_budget (number; optional): NPR amount, 0–999,999,999,999.99. Default: 0. Numeric strings are also coerced.
- source (string; optional): Lead source. Default: Automation API.
- assignee_email (string; optional): Email of an active member in this workspace. Alias: assigneeEmail.
- pipeline_stage (string; optional): Configured stage label or value; omit for the default stage.
- pipeline_option_id (string; optional): Configured stage option ID. If both ID and stage are sent, the server searches for either match; send one for clarity.
- interested_in (string; optional): Configured interest label.
- interested_option_id (string; optional): Configured interest option ID; omit both interest fields for no selection.
- city_district (string; optional): Configured city/district label. Alias: city.
- city_option_id (string; optional): Configured city option ID; omit both city fields for no selection.
- next_follow_up_at (date-time; optional): Valid date/time. Prefer ISO 8601 with +05:45 or Z. Omitted/empty: null. Dates without an offset are interpreted in Asia/Kathmandu.
- notes (string; optional): Initial note. Default: empty string.

Get the workspace's configured stage, interest, city and member values from its CRM settings; there is no Bearer-token options-discovery endpoint.

Without an assignee email, the configured default assignment is used. Invalid option/member values return 400.

Lead-plan capacity returns 402; a suspended workspace returns 403. Intake note history is processed asynchronously; do not assume the initial note is immediately in the paginated activity history.

```sh
curl --request POST 'https://www.aicrmnepal.com/api/automation/intake' \
  --header "Authorization: Bearer $CRM_AUTOMATION_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Example Customer",
  "phone": "+9779800000000",
  "source": "Calling agent",
  "notes": "Requested a product walkthrough."
}'
```

## POST /api/automation/lead-details — Read a lead and its notes

Look up one lead in the token's workspace using any one of the four reference types. Read current fields quickly or page through conversation history.

Required: at least one lead reference.

Success: 200 { lead: Lead, notes: Note[], notes_pagination: { included, limit, has_more, next_cursor }, form_submissions?: { submissions, has_more, next_cursor } }

- crm_id (string; optional): Stable CRM ID: CRM- followed by 12 digits. Alias: crmId.
- supabase_id (UUID; optional): Lead UUID returned by the CRM. Aliases: supabaseId, lead_id, leadId.
- accounting_id (string; optional): Stable internal Accounting ID: ACC- followed by 12 digits. Alias: accountingId. This is not an external accounting vendor's customer ID.
- phone (string; optional): Mobile number. Aliases: lead_number, leadNumber. Nepal 10-digit numbers starting with 9 normalize to +977; formatted numbers normalize to digits with a + prefix. At least 7 digits.
- include_whatsapp_enquiries (boolean; optional): Default false. Include private WordPress WhatsApp enquiry page/title/time with independent pagination; normal Bearer and lead authorization required.
- whatsapp_enquiries_cursor (string; optional): Opaque whatsapp_enquiries.next_cursor, independent of notes/form pagination.
- whatsapp_enquiries_limit (integer; optional): Page size 1–50, default20.
- include_form_submissions (boolean; optional): Default false. Include private form inquiry answers as form_submissions with independent pagination; lead access and normal Bearer authentication required.
- form_submissions_limit (integer; optional): Form submissions per page:1–50, default20. Independent from notes_limit.
- form_submissions_cursor (string; optional): Opaque form_submissions.next_cursor from the same actor/workspace/lead. Follow until form_submissions.has_more is false; do not use note cursors.
- include_notes (boolean; optional): Default: true. false skips note-history fetching; notes is empty and has_more is false, but lead.latest_note remains available.
- notes_limit (integer; optional): 1–100, default 50. Numeric strings are coerced. This is a page size, not the total note count.
- notes_before (date-time; optional): Optional ISO timestamp with offset from the previous next_cursor.created_at. Example: 2026-10-11T04:00:00Z.
- notes_before_id (UUID; optional): Use next_cursor.id with notes_before for stable pagination when timestamps are equal. On its own it does not filter notes.

History contains note activities only, not every audit or stage-change activity. Order: newest created_at first, then descending note UUID.

To read all notes, keep requesting with BOTH returned cursor fields until has_more is false. include_notes:true alone returns only the first page.

Successful responses are private, no-store. The documentation's sample IDs/numbers are illustrative and are not live customer records.

```sh
curl --request POST 'https://www.aicrmnepal.com/api/automation/lead-details' \
  --header "Authorization: Bearer $CRM_AUTOMATION_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "phone": "+9779800000000",
  "include_notes": true,
  "notes_limit": 100
}'
```

## POST /api/automation/lead-note — Add a lead note

Append a note activity to the lead's history and replace the lead's latest-note summary.

Required: at least one lead reference.

Success: 200 { lead: Lead }

- crm_id (string; optional): Stable CRM ID: CRM- followed by 12 digits. Alias: crmId.
- supabase_id (UUID; optional): Lead UUID returned by the CRM. Aliases: supabaseId, lead_id, leadId.
- accounting_id (string; optional): Stable internal Accounting ID: ACC- followed by 12 digits. Alias: accountingId. This is not an external accounting vendor's customer ID.
- phone (string; optional): Mobile number. Aliases: lead_number, leadNumber. Nepal 10-digit numbers starting with 9 normalize to +977; formatted numbers normalize to digits with a + prefix. At least 7 digits.
- note (string; required): Non-empty after trimming. Alias: notes. No explicit maximum is enforced by this route; keep notes concise.

A successful response waits for note-history creation. Repeating the same request appends another activity; there is no idempotency key or automatic duplicate suppression.

```sh
curl --request POST 'https://www.aicrmnepal.com/api/automation/lead-note' \
  --header "Authorization: Bearer $CRM_AUTOMATION_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "crm_id": "CRM-000000000001",
  "note": "Customer requested a callback tomorrow."
}'
```

## POST /api/automation/lead-pipeline — Update the lead stage

Set a configured stage and derive the lead status from that stage. This existing API works with lead stages; it does not require a separate pipeline-board feature.

Required: at least one lead reference.

Success: 200 { lead: Lead, changeActivities?: Activity[], unchanged?: true }

- crm_id (string; optional): Stable CRM ID: CRM- followed by 12 digits. Alias: crmId.
- supabase_id (UUID; optional): Lead UUID returned by the CRM. Aliases: supabaseId, lead_id, leadId.
- accounting_id (string; optional): Stable internal Accounting ID: ACC- followed by 12 digits. Alias: accountingId. This is not an external accounting vendor's customer ID.
- phone (string; optional): Mobile number. Aliases: lead_number, leadNumber. Nepal 10-digit numbers starting with 9 normalize to +977; formatted numbers normalize to digits with a + prefix. At least 7 digits.
- pipeline_option_id (string; optional): One stage selector is required. Configured stage option ID. Alias: pipelineOptionId.
- pipeline_stage (string; optional): Configured stage ID, label or value. Alias: pipelineStage.
- pipeline_label (string; optional): Configured stage display label. Alias: pipelineLabel.

Provide at least one stage selector. A matching option ID takes priority; if absent/invalid the server tries the stage, then label when stage is omitted. Use one valid selector to avoid ambiguity.

The same selection returns unchanged:true. Other selections may trigger the configured stage-change webhook.

```sh
curl --request POST 'https://www.aicrmnepal.com/api/automation/lead-pipeline' \
  --header "Authorization: Bearer $CRM_AUTOMATION_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "accounting_id": "ACC-000000000001",
  "pipeline_stage": "contacted"
}'
```

## POST /api/automation/lead-assignee — Change the lead assignee

Assign one active team member by email, or reset to the configured default assignment.

Required: at least one lead reference.

Success: 200 { lead: Lead, changeActivities?: Activity[], unchanged?: true }

- crm_id (string; optional): Stable CRM ID: CRM- followed by 12 digits. Alias: crmId.
- supabase_id (UUID; optional): Lead UUID returned by the CRM. Aliases: supabaseId, lead_id, leadId.
- accounting_id (string; optional): Stable internal Accounting ID: ACC- followed by 12 digits. Alias: accountingId. This is not an external accounting vendor's customer ID.
- phone (string; optional): Mobile number. Aliases: lead_number, leadNumber. Nepal 10-digit numbers starting with 9 normalize to +977; formatted numbers normalize to digits with a + prefix. At least 7 digits.
- assignee_email (string; optional): Optional active member email. Alias: assigneeEmail. Omitted or empty resets the lead to its configured default assignment; it does not preserve the current assignee.

An unknown or inactive member returns 400. Same assignment returns unchanged:true. The endpoint selects one member; it is not a multi-assignee write API.

```sh
curl --request POST 'https://www.aicrmnepal.com/api/automation/lead-assignee' \
  --header "Authorization: Bearer $CRM_AUTOMATION_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "supabase_id": "00000000-0000-4000-8000-000000000001",
  "assignee_email": "member@example.com"
}'
```

## POST /api/automation/task-create — Create a task

Create a task, optionally linked to a lead by phone or any of its three identifiers.

Success: 201 { task: Task, lead_reference: { crm_id, supabase_id, accounting_id } | null }

- title (string; required): Task title, 1–200 characters after trimming.
- description (string; optional): Task details. Default: empty string.
- assignee_email (string; optional): Optional valid active member email. Alias: assigneeEmail. Omitted: token owner's profile ID. Empty string is invalid.
- priority (enum; optional): low, medium or high. Default: medium.
- due_at (date-time; optional): Optional valid date/timestamp. Alias: deadline. Omitted/empty: no deadline. Prefer an explicit offset; offset-free values use Asia/Kathmandu.
- crm_id (string; optional): Stable CRM ID: CRM- followed by 12 digits. Alias: crmId.
- supabase_id (UUID; optional): Lead UUID returned by the CRM. Aliases: supabaseId, lead_id, leadId.
- accounting_id (string; optional): Stable internal Accounting ID: ACC- followed by 12 digits. Alias: accountingId. This is not an external accounting vendor's customer ID.
- phone (string; optional): Mobile number. Aliases: lead_number, leadNumber. Nepal 10-digit numbers starting with 9 normalize to +977; formatted numbers normalize to digits with a + prefix. At least 7 digits. Task inputs allow up to 64 characters.

Lead reference fields are all optional here. If one is supplied, it must resolve in the workspace or the request fails; omitted: unlinked task.

Task CRM IDs must already be uppercase. Accounting IDs are normalized to uppercase. Supabase/lead ID aliases must be UUIDs.

Task response includes the generated task ID, workspace_id, assigned_to, created_by, title, description, status, priority, due_at, lead_id and timestamps. Default new status: open. This external API does not update task status.

```sh
curl --request POST 'https://www.aicrmnepal.com/api/automation/task-create' \
  --header "Authorization: Bearer $CRM_AUTOMATION_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "title": "Call customer back",
  "priority": "high",
  "due_at": "2026-10-11T11:00:00+05:45",
  "phone": "+9779800000000"
}'
```