Skip to content

About

Code examples, Postman collection & multilingual catalogue for the RISE CRM REST API - connect RISE CRM with Zapier, Make, n8n & third-party apps. cURL, PHP, Python, JS.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

RISE CRM REST API - Examples, Postman Collection and Code Snippets

Postman OpenAPI 3.0 MCP License: MIT RISE CRM

RISE CRM REST API examples in cURL, PHP, Python and JavaScript, plus an importable Postman collection and a complete endpoint catalogue. This repository is the practical companion to REST API for RISE CRM (v2.1.0) by Themesic Interactive - the plugin that turns RISE CRM into an HTTP/JSON API you can call from anything: AI agents, n8n, Zapier, Make, spreadsheets, mobile apps or your own backend.

Every example here uses a real endpoint of the plugin, the real authtoken header, and no invented fields: every field in every payload was checked against the controller that receives it, and where a resource silently ignores a field the snippet says so instead of sending it. Copy, paste, run.


Which questions this repo answers

Does RISE CRM have a REST API? Yes. The REST API for RISE CRM plugin adds a full RESTful HTTP/JSON API to RISE CRM: 35 CRM resources - 34 of them with list, get, search, create, update and delete, plus activity-logs as a read-only audit trail - together with 27 platform endpoints for MCP, webhooks, batch, automation, reporting, custom fields and machine-readable specs, a set of small utility lookups, and the ten groups added in v2.1.0 (line items, knowledge base, checklists, files, estimate and proposal comments, team, project members, roles and templates). That is 54 endpoint groups and 322 documented endpoints in total.

How do I authenticate with the RISE CRM API? Send your token in the authtoken HTTP header on every request. There is no query-parameter fallback. See docs/authentication.md.

What is the base URL of the RISE CRM API? https://yoursite.com/index.php/api - for example https://yoursite.com/index.php/api/clients. If your install serves RISE without index.php in the URL, use https://yoursite.com/api.

Can I connect RISE CRM to ChatGPT, Claude or Cursor? Yes. The plugin ships an MCP server at POST /api/mcp speaking JSON-RPC 2.0 (protocol version 2024-11-05) with 223 generated tools over the same 35 resources. It is opt-in: switch it on from the API settings screen. See MCP server.

Can I connect RISE CRM to n8n, Zapier or Make? Yes, two ways: polling triggers under /api/automation/*, or push-style webhooks with HMAC-SHA256 signatures under /api/webhooks.

How do I create an invoice through the RISE CRM API? POST /api/invoices with invoice_client_id, invoice_bill_date and invoice_due_date. See snippets/curl/invoices.sh.

Is there a Postman collection for RISE CRM? Yes - postman/rise-rest-api.postman_collection.json in this repo, and your own install can generate one at GET /api/postman.json.

Can I run many API calls in one request? Yes. POST /api/batch runs up to 50 operations in a single HTTP call, using the same tool names as the MCP server.


Contents

Folder What is inside
postman/ Importable Postman collection and environment with {{base_url}} and {{authtoken}}
snippets/curl/ Copy-paste curl commands
snippets/php/ PHP examples (built-in cURL extension, no dependencies)
snippets/python/ Python examples (requests)
snippets/javascript/ Node / browser examples (fetch)
docs/ Authentication: creating and using a token

Each language folder carries the same twelve examples: clients, leads, invoices, projects, tasks, tickets, webhooks, mcp, batch, automation, custom_fields and list_features.


Quick start (under a minute)

  1. In RISE CRM, activate the REST API plugin and open the API settings screen.
  2. Create an API user and copy its authtoken.
  3. Call the API:
curl -sS -H "authtoken: YOUR_API_TOKEN" \
  "https://yoursite.com/index.php/api/clients"

That returns your clients as JSON. Swap clients for any resource in the catalogue below.

Create something:

curl -sS -X POST "https://yoursite.com/index.php/api/leads" \
  -H "authtoken: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"company_name":"Northwind Trading","owner_id":1,"lead_status_id":1,"lead_source_id":1}'

Use the Postman collection

  1. Postman > Import > postman/rise-rest-api.postman_collection.json.
  2. Import postman/rise-rest-api.postman_environment.json.
  3. Set base_url to https://yoursite.com/index.php/api and authtoken to your token.
  4. Pick a request and hit Send. Authentication is applied collection-wide, so nothing else to wire up.

Authentication

Item Value
Header authtoken: YOUR_API_TOKEN
Base URL https://yoursite.com/index.php/api
Base URL without index.php routing https://yoursite.com/api
Query-parameter auth Not supported - the header is the only accepted method
Request bodies on POST application/json, multipart/form-data or application/x-www-form-urlencoded
Request bodies on PUT / PATCH application/json or application/x-www-form-urlencoded. multipart/form-data is not supported on PUT or PATCH - PHP has no built-in parser for it on those verbs, so the body arrives empty
Update verbs Every writable resource accepts both PUT and PATCH, and they behave identically
curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/clients"

Tokens are issued per API user from the RISE API settings screen and are JWT values that expire, so an integration should be able to pick up a refreshed token. Full details, including what each failure message means, are in docs/authentication.md.


Endpoint catalogue (every resource and its endpoints)

34 of the 35 CRM resources follow the same six routes under the base path https://yoursite.com/index.php/api. activity-logs is the one exception: it is an audit trail and exposes the three read routes only.

GET    /api/:resource                  list
GET    /api/:resource/:id              get one
GET    /api/:resource/search/:keyword  search
POST   /api/:resource                  create
PUT    /api/:resource/:id              update  (PATCH works too)
DELETE /api/:resource/:id              delete

Two things to know before you build against list and search:

  • search is capped at 10 rows. Every resource's search query ends with LIMIT 0, 10. There is no page, offset or total-count parameter on it. Search is the "turn a name into an id" helper; use the list endpoint or the batch tools to walk a whole collection.
  • list returns the whole collection and has no limit, offset or sort parameter. 20 of the 35 resources do read a small set of named exact-match query filters - GET /api/tasks?project_id=1, GET /api/invoice-payments?invoice_id=1, GET /api/users?user_type=staff and so on. The full per-resource list is in snippets/curl/list_features.sh, which also lists the columns each search endpoint really matches.
# Resource Base path Operations
1 Leads /api/leads list, get, search, create, update, delete
2 Clients /api/clients list, get, search, create, update, delete
3 Contacts /api/contacts list, get, search, create, update, delete
4 Users /api/users list, get, search, create, update, delete
5 Projects /api/projects list, get, search, create, update, delete
6 Tasks /api/tasks list, get, search, create, update, delete
7 Milestones /api/milestones list, get, search, create, update, delete
8 Project comments /api/project-comments list, get, search, create, update, delete
9 Tickets /api/tickets list, get, search, create, update, delete
10 Ticket comments /api/ticket-comments list, get, search, create, update, delete
11 Invoices /api/invoices list, get, search, create, update, delete
12 Invoice payments /api/invoice-payments list, get, search, create, update, delete
13 Estimates /api/estimates list, get, search, create, update, delete
14 Estimate requests /api/estimate-requests list, get, search, create, update, delete
15 Proposals /api/proposals list, get, search, create, update, delete
16 Orders /api/orders list, get, search, create, update, delete
17 Contracts /api/contracts list, get, search, create, update, delete
18 Subscriptions /api/subscriptions list, get, search, create, update, delete
19 Expenses /api/expenses list, get, search, create, update, delete
20 Expense categories /api/expense-categories list, get, search, create, update, delete
21 Items /api/items list, get, search, create, update, delete
22 Item categories /api/item-categories list, get, search, create, update, delete
23 Taxes /api/taxes list, get, search, create, update, delete
24 Timesheets /api/timesheets list, get, search, create, update, delete
25 Messages /api/messages list, get, search, create, update, delete
26 Notes /api/notes list, get, search, create, update, delete
27 Events /api/events list, get, search, create, update, delete
28 Announcements /api/announcements list, get, search, create, update, delete
29 Leave applications /api/leave-applications list, get, search, create, update, delete
30 Todos /api/todos list, get, search, create, update, delete
31 Attendance /api/attendance list, get, search, create, update, delete
32 Payment methods /api/payment-methods list, get, search, create, update, delete
33 Labels /api/labels list, get, search, create, update, delete
34 Notifications /api/notifications list, get, search, create, update, delete
35 Activity logs /api/activity-logs list, get, search (read-only audit trail)

That is the complete list: 35 CRM resources, 34 with full CRUD plus search and activity-logs with the three read routes. Routes.php backs this up with 35 DELETE routes - one per writable CRM resource, plus one for webhooks.

Utility lookups

Small read-only helper endpoints that resolve the ids the create and update calls need. They are not CRM resources and have no CRUD of their own:

Endpoint Returns
GET /api/client_groups Client groups
GET /api/project_labels Project labels
GET /api/invoice_labels Invoice labels
GET /api/ticket_labels Ticket labels
GET /api/invoice_tax Invoice taxes
GET /api/contact_by_clientid/:id Contacts of one client
GET /api/ticket_type Ticket types
GET /api/staff_owner Staff members who can own a record
GET /api/project_members Project members

Platform endpoints (27)

Group Endpoints
MCP (2) POST /api/mcp, GET /api/mcp/info
Webhooks (8) GET /api/webhooks, GET /api/webhooks/events, GET /api/webhooks/:id, GET /api/webhooks/:id/logs, POST /api/webhooks, POST /api/webhooks/:id/toggle, PUT /api/webhooks/:id, DELETE /api/webhooks/:id
Reporting (5) GET /api/reports, /api/reports/summary, /api/reports/invoices, /api/reports/projects, /api/reports/timesheets
Custom fields (4) GET /api/custom-fields, GET /api/custom-fields/:id, GET /api/custom-fields/values/:relatedTo/:id, PUT /api/custom-fields/values/:relatedTo/:id
Automation (3) GET /api/automation/resources, /api/automation/sample/:resource, /api/automation/poll/:resource
Tooling (3) GET /api/postman.json, GET /api/swagger, GET /api/playground
OpenAPI (1) GET /api/openapi.json
Batch (1) POST /api/batch

New in v2.1.0

Ten more endpoint groups sit alongside the 35 CRM resources above - 54 endpoint groups and 322 documented endpoints in total. They use the same authtoken header and base URL.

Group Endpoints
Line items (on sales documents) GET / POST / PUT / PATCH /api/:parent/:id/items and DELETE /api/:parent/:id/items/:itemId, where :parent is invoices, estimates, proposals, orders, contracts or subscriptions
Knowledge base Articles: GET / POST /api/knowledge-base/articles, GET / PUT / DELETE /api/knowledge-base/articles/:id, GET /api/knowledge-base/articles/search/:keyword, and GET / POST /api/knowledge-base/articles/:id/helpful. Categories: the same CRUD + search under /api/knowledge-base/categories
Checklists items, templates and groups, each with full CRUD + search under /api/checklists/{items,templates,groups}; plus GET /api/checklists/groups/:id/templates, POST /api/checklists/items/apply-group and GET /api/checklists/tasks/:task_id/summary
Files GET / POST /api/files, GET / DELETE /api/files/:source/:id, GET /api/files/:source/:id/download, GET /api/files/search/:keyword, GET /api/files/folders, GET /api/files/categories
Estimate comments /api/estimate-comments - full CRUD + search
Proposal comments /api/proposal-comments - full CRUD + search
Team /api/teams - full CRUD + search, plus GET /api/teams/:id/members
Project members /api/project-members - full CRUD + search
Roles (read-only) GET /api/roles, GET /api/roles/:id, GET /api/roles/search/:keyword
Templates (read-only) GET /api/templates (types), GET /api/templates/:type, GET /api/templates/:type/:id, GET /api/templates/:type/search/:keyword

The machine-readable openapi/openapi.json and the Postman collection cover every group, including these.


MCP server: connect RISE CRM to AI agents

POST /api/mcp is a Model Context Protocol server over Streamable HTTP, speaking JSON-RPC 2.0 with protocol version 2024-11-05. A full-access token sees 223 tools: 207 across the 35 resources (clients_list, clients_get, clients_search, invoices_create, tasks_update, tickets_delete - activity_logs contributes read tools only), 14 lookup catalogues such as list_task_statuses and list_lead_sources, and the 2 utilities get_current_datetime and get_server_info. So Claude Desktop, ChatGPT, Cursor and the n8n AI Agent can read and write your CRM.

<resource>_search is a different implementation from the REST /search/:keyword route: it takes a limit (default 25, maximum 100) instead of the REST route's fixed cap of 10, and it matches only the resource's own table, so its column list differs from the REST one. Both are documented per resource in snippets/curl/list_features.sh.

The MCP server is opt-in and disabled by default. Turn it on from the API settings screen (setting api_mcp_enabled); while it is off, the endpoint answers 403 with a JSON-RPC error.

Supported methods: initialize, ping, tools/list (a single page, no cursor pagination) and tools/call. A payload made only of notifications/* messages returns 202 with an empty body.

# 1. Handshake
curl -sS -X POST "https://yoursite.com/index.php/api/mcp" \
  -H "authtoken: YOUR_API_TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'

# 2. Discover every tool
curl -sS -X POST "https://yoursite.com/index.php/api/mcp" \
  -H "authtoken: YOUR_API_TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

# 3. Call one
curl -sS -X POST "https://yoursite.com/index.php/api/mcp" \
  -H "authtoken: YOUR_API_TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"clients_search","arguments":{"q":"Acme","limit":5}}}'

A tool failure comes back as a normal result with isError: true rather than a protocol error, so the agent can read the message and react. Full examples: snippets/curl/mcp.sh · snippets/php/mcp.php · snippets/python/mcp.py · snippets/javascript/mcp.js


Webhooks: push RISE CRM events anywhere

Webhooks are managed over REST and delivered asynchronously.

  • GET /api/webhooks/events is the authoritative event catalogue, derived from the resources that really exist on your install. Every writable resource contributes <resource>.created, <resource>.updated and <resource>.deleted.
  • Three subscription shapes: the exact name (invoices.created), a resource wildcard (invoices.*) and the global wildcard (*).
  • Every delivery carries X-Rise-Signature: t=<unix>,v1=<hex hmac_sha256 of "{t}.{raw body}">, keyed with the signing secret. Verify it by recomputing the HMAC over the exact bytes you received, comparing in constant time, and rejecting a t outside your tolerance window.
  • The signing secret is returned once, when the webhook is created or when you rotate it with rotate_secret. No endpoint can show it again.
  • Target URLs are SSRF-checked before saving and again before every delivery: loopback, link-local, cloud metadata (169.254.0.0/16), RFC1918 and their IPv6 equivalents are refused, redirects are never followed and TLS verification is always enforced.
  • Delivery is queued and drained by the RISE cron job, with exponential backoff on failure. If deliveries queue but nothing arrives, check that the RISE cron job is running.
  • GET /api/webhooks/:id/logs shows every attempt: HTTP status, attempt number, response snippet, error reason, duration and timestamp. The most recent 500 attempts per webhook are kept.
curl -sS -X POST "https://yoursite.com/index.php/api/webhooks" \
  -H "authtoken: YOUR_API_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"Ops sync","url":"https://hooks.example.com/rise","events":["invoices.created","tickets.*"],"timeout":10,"retry_count":1}'

Signature verification in PHP, Python and JavaScript is in the webhooks snippet of each language folder.


Batch: many operations, one request

POST /api/batch runs up to 50 operations in the order you send them, using the same tool names as the MCP server. Batch does not require the MCP server and ignores api_mcp_enabled; it has its own switch, api_batch_enabled, which is on unless it is explicitly turned off.

curl -sS -X POST "https://yoursite.com/index.php/api/batch" \
  -H "authtoken: YOUR_API_TOKEN" -H "Content-Type: application/json" \
  -d '{
        "stop_on_error": false,
        "operations": [
          {"tool":"clients_create","arguments":{"data":{"company_name":"Acme Corporation","city":"San Francisco"}}},
          {"tool":"invoices_get","arguments":{"id":5}},
          {"tool":"taxes_list","arguments":{"limit":2}}
        ]
      }'

The response is always 200 even when an operation fails: read the per-item ok flag and the completed / failed / skipped counters. Send stop_on_error: true to abort at the first failure. Batch operations are not transactional - earlier successful writes are not rolled back.


Automation: polling triggers for n8n, Zapier and Make

Three read-only endpoints implement the polling-trigger contract every no-code platform expects:

Endpoint Purpose
GET /api/automation/resources Which resources can be polled, their cursor columns, and whether they detect updates
GET /api/automation/sample/:resource One representative record, for field mapping in the connector UI
GET /api/automation/poll/:resource The records created or changed since a cursor, newest first
# First run: no cursor, returns the last 24 hours
curl -sS -H "authtoken: YOUR_API_TOKEN" \
  "https://yoursite.com/index.php/api/automation/poll/tickets?limit=50"

# Later runs: send back meta.next_since from the previous response
curl -sS -H "authtoken: YOUR_API_TOKEN" \
  "https://yoursite.com/index.php/api/automation/poll/tickets?since=2026-07-21T09:45:12%2B00:00&limit=50"

De-duplicate on id: the cursor is inclusive and some RISE columns store a date without a time, so a record can legitimately arrive twice.

/api/automation/poll is not paginated. There is no offset parameter: the endpoint always answers with the newest limit rows on or after the cursor, starting at offset 0. Asking again for the same cursor with the same limit therefore returns exactly the same rows, for ever - so never write while (has_more) { poll(same cursor) }. meta.has_more means only "the page came back full, so older matches may have been cut off". The two honest reactions are to raise limit (100 is the ceiling) or to poll more often so one window fits in one page. The automation snippet in each language folder shows the bounded version.

meta.detects_updates tells you honestly whether the resource can fire on updates - RISE has no generic "modified" timestamp, so only tables with a column that moves when a record is touched (a ticket's last activity, a task's status change, an invoice's cancellation) do.


Reporting and custom fields

Read-only aggregates for dashboards and BI tools:

curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/reports"
curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/reports/summary"
curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/reports/invoices?from=2026-01-01&to=2026-03-31"
curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/reports/timesheets?group_by=project&limit=50"

Custom fields expose their definitions and the per-record values:

curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/custom-fields?related_to=clients"
curl -sS -H "authtoken: YOUR_API_TOKEN" "https://yoursite.com/index.php/api/custom-fields/values/clients/12"

See snippets/curl/custom_fields.sh for writing values back.


Machine-readable specs: OpenAPI, Postman, Swagger UI, Playground

Endpoint What you get
GET /api/openapi.json OpenAPI 3.0 document for the whole API
GET /api/postman.json Postman v2.1 collection generated from your own install
GET /api/swagger Swagger UI, ready to browse
GET /api/playground Interactive API playground

Point any OpenAPI code generator at /api/openapi.json to produce a typed client in your language.


Popular integrations and use cases

  • AI assistants (MCP) - let Claude Desktop, ChatGPT or Cursor query and update RISE through /api/mcp.
  • n8n, Zapier, Make - polling triggers via /api/automation/*, or push via webhooks.
  • Slack, Discord and internal services - HMAC-signed webhook deliveries on invoice, ticket, lead and project events.
  • Dashboards and BI - /api/reports/* returns pre-aggregated figures so you do not query the CRM database directly.
  • Data migration and bulk edits - POST /api/batch moves 50 operations per request.
  • Custom portals and mobile apps - build on top of clients, projects, tasks, tickets and invoices.

Troubleshooting FAQ

{"status":false,"message":"Token is not defined."} The authtoken header was missing. It is a header, not a query parameter, and the name is authtoken (case-insensitive), not Authorization.

{"status":false,"message":"Token Time Expire."} The token has passed its expiry window. Generate a fresh token from the API settings screen.

{"status":false,"code":404,"message":"Route not found"} The path does not exist. Check the spelling and the hyphens: platform and multi-word resources use hyphens (invoice-payments, custom-fields, leave-applications), never underscores. Note that the MCP and batch tool names use underscores (invoice_payments_list) while the URLs use hyphens.

Everything 404s, including /api/clients Your install probably needs index.php in the URL. Use https://yoursite.com/index.php/api/clients.

404 Not Found with {"status":false,"messages":{"error":"No data were found"}} The request was authenticated and routed fine, the resource simply has no matching rows. An empty list is reported as a 404 by the CRUD endpoints, so treat it as "empty", not as "broken".

MCP returns 403 with -32000 MCP server is disabled. The MCP server is opt-in. Enable it from the API settings screen (api_mcp_enabled).

Batch returns 403 api_batch_enabled has been set to 0. It defaults to on.

Webhook created, but nothing is delivered Deliveries are queued and sent by the RISE cron job. Confirm the cron job runs, then read GET /api/webhooks/:id/logs - blocked deliveries are logged there with the reason.

Webhook rejected with "the host resolves to ..." The SSRF policy refuses private, loopback, link-local and cloud-metadata addresses. A webhook target must be a publicly resolvable http or https URL.

A POST is rejected with a validation error listing a field I did send Check the field name against the snippet. Some create payloads use prefixed names, for example an invoice takes invoice_client_id, invoice_bill_date and invoice_due_date.

Lead creation fails on company_name Lead names are validated as letters and spaces only. Use a plain name without punctuation.

A field I sent on POST came back empty Create and update do not always read the same fields. The ones that catch people out: an invoice's invoice_note and labels are read by update only, a client's group_ids is validated on create but stored by update only, and a ticket has no description on create at all - the body of a ticket is a separate POST /api/ticket-comments. created_by is honoured by announcements, contacts, estimate-requests, estimates, events, expenses, invoices, invoice-payments, items, leave-applications, notes, orders, project-comments, projects, proposals and todos; elsewhere it is ignored. The snippets in this repo call each of these out where they occur.

A PUT or PATCH arrived with an empty body You almost certainly sent it as multipart/form-data. That works on POST but not on PUT or PATCH - PHP has no built-in parser for multipart on those verbs. Send JSON or application/x-www-form-urlencoded instead.

Signature verification always fails Recompute the HMAC over the raw request body exactly as received, before any JSON parsing or re-serialisation, and sign the string "{t}.{raw body}" where t is the timestamp from the header.


About and support

This repository is an examples companion to the commercial plugin:

REST API for RISE CRM - connect RISE with third-party applications by Themesic Interactive, version 2.1.0.

Contributions of extra examples are welcome - see CONTRIBUTING.md.

License

Example code in this repository is released under the MIT License. "RISE CRM" is a trademark of its respective owner; the REST API plugin is a commercial product by Themesic Interactive.

About

Code examples, Postman collection & multilingual catalogue for the RISE CRM REST API - connect RISE CRM with Zapier, Make, n8n & third-party apps. cURL, PHP, Python, JS.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages