# VertexCRM > Multi-tenant CRM API (India). Org-scoped REST at /api/v1. Auth: Bearer vcr_… (Setup → API Keys). Lists paginate at 20 rows. Do not invent shop prices or undocumented endpoints. Base: https://www.vertexcrm.in API: https://www.vertexcrm.in/api/v1 ## Docs (fetch these first) - [Public API (markdown)](https://www.vertexcrm.in/developers.md): integrator contract - [AI tools / MCP copy](https://www.vertexcrm.in/developers/ai.md): Cursor, Claude Code, Codex, ChatGPT - [Paste-into-chat prompt](https://www.vertexcrm.in/developers/prompt.md): single system prompt - [Agent skill](https://www.vertexcrm.in/developers/skill.md): short skill for coding agents - [OpenAPI 3 JSON](https://www.vertexcrm.in/openapi.json): machine spec - [Full dump](https://www.vertexcrm.in/llms-full.txt): concatenated docs - [Swagger / Redoc](https://www.vertexcrm.in/docs): human explorer - [MCP (docs, HTTP)](https://www.vertexcrm.in/mcp): Model Context Protocol, public docs only ## API objects (v1 only) Accounts, contacts, leads, opportunities, cases. Inbox, gallery, products, campaigns, users are not on v1. Lead status: Open - Not Contacted | Working - Contacted | Closed - Converted | Closed - Not Converted Lead rating: Hot | Warm | Cold Opportunity stage: Prospecting | Qualification | Needs Analysis | Value Proposition | Negotiation | Closed Won | Closed Lost Case status: New | Working | Escalated | Closed | On Hold Case priority: High | Medium | Low ## Partner webhooks (not vcr_ keys) POST /webhooks/inbound-leads — X-Inbound-Secret or Bearer INBOUND_LEAD_SECRET; optional X-Org-Slug POST /api/booking-forms/whatsapp — Bearer BOOKING_FORMS_WHATSAPP_TOKEN; body {to, message, name, template} ## Rules for agents 1. Read /developers.md before writing client code. 2. Prefer API keys over scraping HTML. 3. per_page is fixed at 20; walk page=. 4. PUT is read-modify-write. DELETE returns {ok:true} with HTTP 200. 5. Never log or embed vcr_ keys in browser JS. 6. Do not claim Inbox or WhatsApp send on /api/v1. --- # VertexCRM — paste this into Claude, Cursor, Codex, or ChatGPT Copy everything below the line into the chat (or AGENTS.md / CLAUDE.md) before asking the model to integrate VertexCRM. --- You are integrating **VertexCRM**, a multi-tenant CRM at https://www.vertexcrm.in. ## Fetch first (do this, do not guess) 1. https://www.vertexcrm.in/llms.txt 2. https://www.vertexcrm.in/developers.md 3. https://www.vertexcrm.in/openapi.json If those fail, use this contract. ## Auth - Preferred: `Authorization: Bearer vcr_…` (org API key from Setup → API Keys). Shown once; hashed at rest. - Optional: session cookie or login JWT. - Keys are **organization-scoped**. Never cross tenants. ## Base `https://www.vertexcrm.in/api/v1` Self-hosted: `{origin}/api/v1` ## Resources (only these on v1) | Resource | Path | List extras | |----------|------|-------------| | Accounts | /accounts, /accounts/{id} | sort, dir | | Contacts | /contacts, /contacts/{id} | sort, dir | | Leads | /leads, /leads/{id} | status, rating, sort, dir | | Opportunities | /opportunities, /opportunities/{id} | stage, sort, dir | | Cases | /cases, /cases/{id} | status | Methods: GET list/get, POST create (201), PUT update, DELETE → `{ "ok": true }` HTTP 200. Lists: `{ "data": [], "page": 1, "per_page": 20 }`. Page size is **fixed at 20**. `page` is 1-based. ## Picklists (use these strings) - Lead status: `Open - Not Contacted`, `Working - Contacted`, `Closed - Converted`, `Closed - Not Converted` - Lead rating: `Hot`, `Warm`, `Cold` - Opportunity stage: `Prospecting`, `Qualification`, `Needs Analysis`, `Value Proposition`, `Negotiation`, `Closed Won`, `Closed Lost` - Case status: `New`, `Working`, `Escalated`, `Closed`, `On Hold` - Case priority: `High`, `Medium`, `Low` ## Not on v1 Inbox, WhatsApp send, gallery files, products, campaigns, users, automation. Do not invent those routes. ## Partner endpoints (different secrets) - `POST /webhooks/inbound-leads` — `X-Inbound-Secret` or Bearer `INBOUND_LEAD_SECRET`; optional `X-Org-Slug` - `POST /api/booking-forms/whatsapp` — Bearer `BOOKING_FORMS_WHATSAPP_TOKEN`; `{to, message, name, template}` ## Safety - Do not put `vcr_` keys in frontend code or commit them. - Creates are not idempotent — dedupe on email/source/day. - Do not invent Healthy-O-Me / shop prices. - Prefer curl or a small server client. After writing code, mention `/docs` (Swagger) for humans. ## Example ```bash curl -sS -X POST \ -H "Authorization: Bearer vcr_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"first_name":"Ananya","last_name":"Shah","email":"ananya@example.com","status":"Open - Not Contacted","source":"Website"}' \ "https://www.vertexcrm.in/api/v1/leads" ``` --- # VertexCRM public API — integrator guide > How a customer system reads and writes CRM objects in **their** organization. Live: [https://www.vertexcrm.in/developers](https://www.vertexcrm.in/developers) · Raw markdown: [https://www.vertexcrm.in/developers.md](https://www.vertexcrm.in/developers.md) · LLM index: [https://www.vertexcrm.in/llms.txt](https://www.vertexcrm.in/llms.txt) · MCP: [https://www.vertexcrm.in/mcp](https://www.vertexcrm.in/mcp) · Explorer: [https://www.vertexcrm.in/docs](https://www.vertexcrm.in/docs) · OpenAPI: [https://www.vertexcrm.in/openapi.json](https://www.vertexcrm.in/openapi.json) Last updated: 2026-08-23. This document matches the handlers in `internal/handler/api.go` and the routes in `internal/server/router.go`. If the code and this page disagree, the code wins — then update this file. --- ## 1. Base URL and version ``` https://www.vertexcrm.in/api/v1 ``` Self-hosted: `{origin}/api/v1`. There is one version (`v1`). All resources are **organization-scoped**. A key or session never sees another tenant’s rows. Machine-readable spec: `GET /docs/openapi.json` (no auth). Interactive explorer: [`/docs`](https://www.vertexcrm.in/docs) (Swagger UI + Redoc). --- ## 2. Authentication Pick one. Do not send more than you need. | Method | How | Typical use | |--------|-----|-------------| | **Organization API key** | `Authorization: Bearer vcr_…` | Server-to-server. **Preferred.** | | **Session cookie** | Browser login cookie `octavertex_session` | Same-origin UI / scripts | | **JWT Bearer** | `Authorization: Bearer ` | Mobile / custom clients after login | ### 2.1 Create an API key 1. Sign in as an org admin. 2. **Setup → API Keys** (`/admin/api-keys`). 3. Name the key (e.g. `shop-sync-prod`) and create it. 4. Copy the plaintext **once**. VertexCRM stores only a hash. The key is bound to the **current organization**. If the creating user is missing, the API still authenticates as `api_key:{prefix}` with that org in context. Revoke immediately if leaked. Rotate by creating a new key, switching the client, then deleting the old one. ### 2.2 Organization context | Client | Org resolution | |--------|----------------| | API key `vcr_…` | Org is the key’s organization. Optional `?org=slug` is ignored for tenancy. | | Session / JWT | Use `?org={slug}` when the user belongs to more than one org (same as the HTML app). | ### 2.3 Permissions `/api/v1` uses the same RBAC as the UI: `accounts|contacts|leads|opportunities|cases` × `list|read|create|update|delete`. If the key’s user has no profile grants, calls return **403**. Grant a dedicated “API integration” profile with only the objects the integrator needs. --- ## 3. Conventions ### 3.1 Content type - Request body: `Content-Type: application/json` - Responses: JSON. Errors: `{ "error": "…" }` - Dates: RFC 3339 timestamps. Display in the product is Asia/Kolkata; the API does not convert. ### 3.2 List pagination Every list returns: ```json { "data": [ /* objects */ ], "page": 1, "per_page": 20 } ``` - `page` — 1-based. Default `1`. Values < 1 become `1`. - `per_page` — **fixed at 20**. There is no `per_page` query parameter today. - Walk pages until `data` is shorter than 20 or empty. Common query params: | Resource | Extra filters | Default sort | |----------|---------------|--------------| | Accounts | `sort`, `dir` | `name` asc | | Contacts | `sort`, `dir` | `last_name` asc | | Leads | `status`, `rating`, `sort`, `dir` | `created_at` desc | | Opportunities | `stage`, `sort`, `dir` | `created_at` desc | | Cases | `status` | (repo default) | `dir` is `asc` or `desc`. ### 3.3 Identifiers Integer `id` values. Always send `id` from a previous response. `organization_id` is set by the server; clients should not rely on writing it. ### 3.4 Updates `PUT /{resource}/{id}` replaces the writable fields from the JSON body. Owner and created-by are preserved from the existing row. Send the full object you intend to keep (read-modify-write). ### 3.5 Deletes `DELETE` returns `{ "ok": true }` with HTTP 200 (not 204). ### 3.6 Status codes | Code | Meaning | |------|---------| | 200 / 201 | Success (create is 201) | | 400 | Invalid JSON | | 401 | Missing/invalid session, JWT, or key | | 403 | Authenticated but profile lacks the action | | 404 | Wrong id or wrong org | | 500 | Server / database | --- ## 4. Resources Picklists below are the values the UI seeds. The API accepts the string you send; stay on these values so reports and filters work. ### 4.1 Accounts — `/api/v1/accounts` | Method | Path | Permission | |--------|------|------------| | GET | `/accounts` | list | | GET | `/accounts/{id}` | read | | POST | `/accounts` | create | | PUT | `/accounts/{id}` | update | | DELETE | `/accounts/{id}` | delete | Writable fields: `name`, `website`, `phone`, `industry`, `annual_revenue`, `employees`, `address`, `city`, `state`, `postal_code`, `country`, `description`. ### 4.2 Contacts — `/api/v1/contacts` Writable: `account_id`, `first_name`, `last_name`, `email`, `phone`, `title`, `department`, `timezone`, `linkedin_url`, `instagram_handle`, `facebook_url`, `description`. `timezone` is IANA (e.g. `Asia/Kolkata`). ### 4.3 Leads — `/api/v1/leads` Writable: `first_name`, `last_name`, `company`, `email`, `phone`, `status`, `rating`, `source`, `lead_score`, `timezone`, social URLs, `description`. **Status:** `Open - Not Contacted` · `Working - Contacted` · `Closed - Converted` · `Closed - Not Converted` **Rating:** `Hot` · `Warm` · `Cold` **Source (UI list):** Website, WhatsApp, Phone, Email, LinkedIn, Instagram, Facebook, Referral, Meta Lead Ads, Other. Creating a lead via the API does **not** auto-convert. Conversion is a product action (Convert button or AI `track_conversion`). ### 4.4 Opportunities — `/api/v1/opportunities` Writable: `account_id`, `name`, `amount`, `stage`, `close_date`, `probability`, `description`. **Stage:** Prospecting, Qualification, Needs Analysis, Value Proposition, Negotiation, Closed Won, Closed Lost. `close_date` is a timestamp or null. ### 4.5 Cases — `/api/v1/cases` Writable: `subject`, `status`, `priority`, `account_id`, `contact_id`, `queue_id`, `description`. **Status:** New, Working, Escalated, Closed, On Hold. **Priority:** High, Medium, Low. --- ## 5. Worked examples Replace `YOUR_KEY` and host. ### 5.1 Health: list accounts ```bash curl -sS -H "Authorization: Bearer YOUR_KEY" \ "https://www.vertexcrm.in/api/v1/accounts?page=1" ``` ### 5.2 Create a lead from your website / POS ```bash curl -sS -X POST \ -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "first_name": "Ananya", "last_name": "Shah", "company": "Northwind Agency", "email": "ananya@example.com", "phone": "+919876543210", "status": "Open - Not Contacted", "rating": "Warm", "source": "Website", "description": "Requested Growth plan demo" }' \ "https://www.vertexcrm.in/api/v1/leads" ``` ### 5.3 Create an account, then a contact ```bash curl -sS -X POST -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Northwind Agency","city":"Pune","country":"India"}' \ "https://www.vertexcrm.in/api/v1/accounts" # use returned id curl -sS -X POST -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"account_id":123,"first_name":"Ananya","last_name":"Shah","email":"ananya@example.com","timezone":"Asia/Kolkata"}' \ "https://www.vertexcrm.in/api/v1/contacts" ``` ### 5.4 Open a deal ```bash curl -sS -X POST -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": 123, "name": "VertexCRM Growth — FY26", "amount": 249000, "stage": "Qualification", "probability": 40 }' \ "https://www.vertexcrm.in/api/v1/opportunities" ``` ### 5.5 JavaScript (Node 18+) ```js const BASE = "https://www.vertexcrm.in/api/v1"; const KEY = process.env.VERTEXCRM_API_KEY; async function createLead(body) { const res = await fetch(`${BASE}/leads`, { method: "POST", headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json", }, body: JSON.stringify(body), }); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); return res.json(); } ``` --- ## 6. Partner and webhook APIs (not `/api/v1`) These are **separate** contracts. They do not use `vcr_` keys unless noted. ### 6.1 Inbound leads — `POST /webhooks/inbound-leads` For ads, newsletters, Zapier, or a form tool that should only create leads. | Header | Required | Value | |--------|----------|--------| | `X-Inbound-Secret` or `Authorization: Bearer …` | Yes | Platform `INBOUND_LEAD_SECRET` | | `X-Org-Slug` | Recommended | Target org slug. If omitted, the first org is used. | ```json { "first_name": "Ravi", "last_name": "Mehta", "email": "ravi@example.com", "company": "Mehta & Co", "phone": "+919811112222", "source": "Google Ads", "campaign_name": "Brand search", "description": "Downloaded pricing PDF" } ``` At least one of `first_name`, `last_name`, or `email` is required. Returns **501** if the secret is not configured on the instance. ### 6.2 Booking-forms WhatsApp — `POST /api/booking-forms/whatsapp` Used by Cafe Orelo (and similar portals) to send a confirmation on the org’s existing AiSensy/Meta sender. Auth: `Authorization: Bearer ` (instance env, not `vcr_`). ```json { "to": "+9198XXXXXXXX", "message": "Your table is confirmed.", "name": "Guest", "template": "booking_confirm" } ``` `to` and `message` are required. ### 6.3 Commerce payment (Healthy-O-Me pattern) `POST /webhooks/healthyome-payment` with `X-HealthyOme-CRM-Key`. Marks the matching lead Closed-Converted and opens a Closed Won opportunity. Customer-specific; do not reuse without a written integration. ### 6.4 Channel webhooks (Meta / AiSensy / Instagram) Configured per org under Setup → Integrations. You do not call these from your app; Meta/AiSensy call VertexCRM. --- ## 7. Rate limits, idempotency, and safety - There is **no published rate-limit header** today. Treat 60 requests/minute/key as a polite ceiling; back off on 5xx. - Creates are **not idempotent**. Deduplicate on your side (email + source + day) before POST. - Never log full `vcr_` keys. Never embed keys in browser JavaScript on a public site. - Do not use the API to scrape another org. Keys cannot cross tenants. - Webhook secrets (`INBOUND_LEAD_SECRET`, booking token) are **platform** secrets — request them in the integration questionnaire; they are not self-serve in the UI. --- ## 8. What is not in v1 Inbox messages, gallery files, products, campaigns, reports, users, and automation are **not** on `/api/v1` yet. Use the UI, or ask for a scoped partner endpoint (booking-forms pattern). --- ## 9. Support - In-app: Setup → API Keys · OpenAPI link - Human: [vertexcrm.in/contact](https://www.vertexcrm.in/contact) — attach the integration questionnaire (`marketing/gtm/QUESTIONNAIRES.md` § API) - Security: same form, subject “Security” --- # VertexCRM — AI tools (Cursor, Claude Code, Codex, ChatGPT) Use these blocks as-is. Replace `vcr_YOUR_KEY` with a key from **Setup → API Keys**. Never commit the key. Human UI: https://www.vertexcrm.in/developers Markdown: https://www.vertexcrm.in/developers.md LLM index: https://www.vertexcrm.in/llms.txt OpenAPI: https://www.vertexcrm.in/openapi.json MCP (public docs): https://www.vertexcrm.in/mcp --- ## 1. Copy markdown (any chat) In Cursor / Claude / ChatGPT / Codex, paste: ``` Read https://www.vertexcrm.in/llms.txt and https://www.vertexcrm.in/developers.md then https://www.vertexcrm.in/openapi.json. Integrate VertexCRM using Authorization: Bearer vcr_YOUR_KEY against https://www.vertexcrm.in/api/v1. Follow picklists and pagination (per_page=20) exactly. Do not invent Inbox or WhatsApp routes. ``` Or paste the full prompt: https://www.vertexcrm.in/developers/prompt.md --- ## 2. Cursor ### 2.1 @-mention docs (no MCP) 1. Settings → Indexing / Docs → add `https://www.vertexcrm.in/developers.md` and `https://www.vertexcrm.in/llms.txt`. 2. In chat: `@VertexCRM` or paste the prompt above. ### 2.2 Project rule Save as `.cursor/rules/vertexcrm.mdc` (or paste into Cursor Rules): ```markdown --- description: VertexCRM public API alwaysApply: false --- When integrating VertexCRM, fetch https://www.vertexcrm.in/developers.md and https://www.vertexcrm.in/openapi.json first. Auth: Bearer vcr_… Base: /api/v1. Objects: accounts, contacts, leads, opportunities, cases only. Lists: page, per_page=20. Lead statuses use the long Salesforce-style strings. ``` ### 2.3 MCP — live CRM (stdio) Install the binary from this repo (`go install ./cmd/vertexcrm-mcp`) or `go run`. `~/.cursor/mcp.json` or project `.cursor/mcp.json`: ```json { "mcpServers": { "vertexcrm": { "command": "vertexcrm-mcp", "args": [], "env": { "VERTEXCRM_BASE_URL": "https://www.vertexcrm.in", "VERTEXCRM_API_KEY": "vcr_YOUR_KEY" } } } } ``` ### 2.4 MCP — docs only (HTTP, no key) ```json { "mcpServers": { "vertexcrm-docs": { "url": "https://www.vertexcrm.in/mcp" } } } ``` --- ## 3. Claude Code ```bash # Docs MCP (no secret) claude mcp add --transport http vertexcrm-docs https://www.vertexcrm.in/mcp # Live CRM (needs a key; run from a machine that has the binary on PATH) claude mcp add vertexcrm --env VERTEXCRM_API_KEY=vcr_YOUR_KEY --env VERTEXCRM_BASE_URL=https://www.vertexcrm.in -- vertexcrm-mcp ``` Project `CLAUDE.md` snippet: ```markdown ## VertexCRM Read https://www.vertexcrm.in/llms.txt and https://www.vertexcrm.in/developers.md before writing API clients. Skill: https://www.vertexcrm.in/developers/skill.md ``` Optional: save `docs/developers/SKILL.md` into `.claude/skills/vertexcrm/SKILL.md`. --- ## 4. OpenAI Codex / ChatGPT `AGENTS.md` or custom instructions: ```markdown VertexCRM API: https://www.vertexcrm.in/developers.md LLM index: https://www.vertexcrm.in/llms.txt OpenAPI: https://www.vertexcrm.in/openapi.json Auth header: Authorization: Bearer vcr_… ``` ChatGPT: upload `developers.md` or say “fetch https://www.vertexcrm.in/llms-full.txt”. --- ## 5. Other agents (Windsurf, Cline, Continue, Aider) Point the tool’s docs / context URL at: - https://www.vertexcrm.in/llms-full.txt - https://www.vertexcrm.in/openapi.json Or run `vertexcrm-mcp` as a stdio MCP server (same env vars as Cursor). --- ## 6. Hosted MCP tools (https://www.vertexcrm.in/mcp) Public, no API key. Tools: | Tool | Purpose | |------|---------| | `get_docs` | `public-api` \| `ai-tools` \| `prompt` \| `skill` \| `llms` \| `openapi` | | `search_docs` | keyword search over the integrator docs | Live tenant reads/writes are **not** on the hosted MCP. Use `vertexcrm-mcp` + `VERTEXCRM_API_KEY`. --- ## 7. `vertexcrm-mcp` live tools When `VERTEXCRM_API_KEY` is set: - `list_accounts`, `get_account`, `create_account` - `list_contacts`, `get_contact`, `create_contact` - `list_leads`, `get_lead`, `create_lead` - `list_opportunities`, `get_opportunity`, `create_opportunity` - `list_cases`, `get_case`, `create_case` - plus the same `get_docs` / `search_docs` as hosted MCP ```bash export VERTEXCRM_BASE_URL=https://www.vertexcrm.in export VERTEXCRM_API_KEY=vcr_YOUR_KEY go run ./cmd/vertexcrm-mcp ```