For agents & developers

Connect your own software to Stacks. External integrations use the core API; built-in AI uses its own credits. Stacks-managed Agentic remains Coming Soon.

Use a separate scoped API key for each integration. Module, write, send and approval rules apply to every supported action. API usage is observed without commercial quota enforcement. Technical request and resource limits still apply.

Start with a read

  1. Open your workspace’s Settings → API Keys. Create a separate read-only key for this integration and select the modules it needs.
  2. Copy the workspace URL shown there. Replace YOUR_WORKSPACE and YOUR_KEY in the illustrative request below. Keep keys out of shared prompts, source control and screenshots.
  3. Read a small page, inspect the result, then retrieve usage. Enable write or send permission only for an intended workflow.
GET https://YOUR_WORKSPACE.stackscrm.com/api/v1/contacts?per_page=10
Authorization: Bearer YOUR_KEY

GET https://YOUR_WORKSPACE.stackscrm.com/api/v1/usage
Authorization: Bearer YOUR_KEY

These are templates, not an executable client configuration. Your workspace’s /api/v1/openapi.json and Settings → API Reference describe the REST schema. Authentication errors return 401, denied permissions 403, missing owned records 404, validation errors 422, conflicts 409 and technical throttles 429.

MCP connection requirements

The MCP adapter supports stateless JSON HTTP with a custom Bearer header. Local protocol tests pass; hosted-client compatibility is unverified. Endpoint: https://YOUR_WORKSPACE.stackscrm.com/mcp.

POST an initialize request with a protocol-version date, then tools/list. Follow nextCursor until it is absent. Call tools with a JSON object for arguments. Supported selections are 2025-03-26 and 2025-06-18; reject a negotiated version your client cannot use. No OAuth, GET event stream or resumable session is provided.

get_api_usage exposes observed units, operation weights, meter version and technical limits in both text and structured content. Commercial allowance and remaining are null in observe-only mode. Check isError and the business result even when HTTP returns 200. The tested client is a local PHP/cURL fixture; Claude, ChatGPT, Cursor and other hosted clients have not been verified.

Read the outcome before the next action

Tasks return is_completed and completed_at. After complete_task, read the task again to confirm completion. Repeating completion preserves its timestamp. Deals return status (open, won, or lost), plus won_at and lost_at; pipeline stage alone does not establish the outcome.

Contact tags is always an array, including [] when empty. Contact context includes at most 20 contact-record activity entries, newest first by created_at then id. These entries contain identifiers and action names, with no message bodies or metadata. This is a contact-record history, not every event across the workspace.

get_invoice (REST GET /api/v1/invoices/{id}) returns headers and totals. Use get_invoice_context (REST GET /api/v1/invoices/{id}/context) for line_items, payments, amount_paid and balance_due. Invoice and contact context require both CRM and invoicing access; a missing permission rejects the entire combined request.

Discover inputs with tools/list: check required, valid choices in enum, and conditional inputs in oneOf. A follow-up needs exactly one of contact_id or deal_id. Dates use YYYY-MM-DD. Omit assignee_id when calling assign_ticket to unassign it.

MCP business errors have isError: true and an error object in both text and structuredContent. It contains type, message, http_status, recovery and a request reference. HTTP 200 is not proof of business success. Correct invalid inputs; reload after an edit_conflict. Inspect the existing record and activity reference before retrying an uncertain write.

{"isError":true,"structuredContent":{"error":{"type":"invalid_params","message":"arguments.tag: required.","http_status":400,"recovery":"Correct the named input using the tool schema, then retry.","request_id":"EXAMPLE_REFERENCE"}}}

create_ticket creates the optional first message as an agent-authored public-thread entry (is_internal=false). Creation sends no email, whether or not it is linked to a contact. This tool does not create private notes or send customer replies. Words such as “internal” in the subject do not change visibility.

GET /api/v1/usage and get_api_usage expose API units and technical limits. Hosted AI credits are separate. In observe-only mode, commercial allowance and remaining are null. Rejected operations and successful idempotent replays consume zero units. API Activity shows safe error categories, status codes and a timezone label; an ok operation does not confirm email delivery.

Timestamp fields such as created_at, completed_at and appointment scheduled_at use UTC in YYYY-MM-DD HH:MM:SS format. Treat them as UTC even though the string has no offset. Calendar fields such as due_date and issued_date are dates and must not be shifted. The workspace timezone controls CRM display; changing it preserves booked moments. An appointment's timezone is the guest preference, not the timezone of its stored timestamp.

Available resource operations

ResourceCore operationsAdditional actions
contacts list, get, create, update, delete tag, untag, request_review, send_email, send_sms
companies list, get, create, update, delete tag, untag
deals list, get, create, update win, lose
tasks list, get, create, update complete
invoices list, get, create, update record_payment, send_invoice
products list, get, create, update, delete
tickets list, get, create assign, set_status, set_priority
users list, get
pipelines list, get
appointment_types list, get
appointments list, get

The catalog lists supported operations, not your key’s permissions. Combined context reads require every included module. Appointments are read-only through these API resources; availability lookup does not book or reschedule a slot. Sending also requires the provider, current send rights and the account’s approval policy.

Retries, outcomes and limits

Create/update of contacts, companies, tasks and products support an idempotency_key; REST also accepts Idempotency-Key. Use a random 16–128-character key per intended write. Reuse it after a timeout to retrieve the original result, including across REST and MCP. Different input with the same key conflicts. Updates can use if_match with the returned _version; conditional custom-field updates are not supported.

Other actions have their own recovery rules. A pending approval is not a sent message, provider acceptance is not delivery, and an unavailable paid booking can require staff resolution. Inspect the existing result before resubmitting an uncertain external send or payment.

REST and MCP share 120 requests per minute per key, four concurrent requests per key and eight per workspace. JSON bodies are limited to 1 MiB, lists to 100 records per page and MCP discovery to 32 tools per page. Large jobs should use bounded pages and stop when permissions or limits reject a request.

Five local workflow examples

The repository’s automated workflow fixture is reproducible in isolated Docker and uses synthetic data. It demonstrates lead/company/deal/task creation, bounded relationship context, invoice ledger/status, calendar record inspection, and an internal follow-up that sends no message. Payment callbacks and booking conflicts have separate synthetic-provider regressions. These results do not establish provider-sandbox or hosted-client compatibility.

Read the examples and their boundaries · Built-in AI credits · Export coverage

Connect your own supported email, SMS and payment providers. Saving credentials does not verify a successful send or payment.

Private integrations use their own scoped keys. A public multi-customer application, hosted agent runtime or distribution program is not implied by this API. Start a Free workspace.