CRM Solid logo
GUIDE19 min read

How to use the CRM Solid REST API and MCP server

A developer-grade walkthrough: Bearer-token auth with scoped API keys, rate-limit headers, idempotency, sending messages and creating contacts via v1 REST endpoints, subscribing to outbound webhooks with HMAC verification, and connecting the MCP server so an AI assistant can call your CRM directly - plus the .NET SDK for typed access.

14-day free trial · No credit card required · Cancel anytime

What you will learn

Four API skills by the end of this guide

Scoped auth

Create least-privilege API keys and rotate them without downtime.

REST endpoints

Send messages, upsert contacts, and enroll contacts in sequences via v1 endpoints.

Webhooks + HMAC

Subscribe to CRM events and verify every delivery signature before trusting the payload.

MCP for AI agents

Give an AI assistant safe, scoped access to your CRM through the MCP server.

What you will need

The API integration path is quick once these are in place. Skipping any item will cost you time later.

  • A CRM Solid workspace on the Pro or Business plan (free trial works).
  • Access to the Settings > API Keys section of the panel.
  • A terminal or HTTP client (curl, Postman, or Insomnia).
  • A public HTTPS endpoint for receiving webhooks (use a local tunnel such as ngrok for testing).
  • The webhook secret shown in the panel when you register an endpoint.
  • For MCP: an MCP-compatible AI assistant (Claude Desktop, Cursor, or similar).
  • For .NET: .NET 8 or later and the CrmSolid.Client NuGet package.

Step 1: Create a scoped API key

Budget: 2 minutes. In the CRM Solid panel, go to Settings > API Keys > New key. Give the key a descriptive name such as production-sender or analytics-dashboard. Then select only the scopes that integration actually needs:

  • read:contacts - list, search, and export contacts.
  • read:messages - stream chat history and inbox threads.
  • read:analytics - pull funnel, sequence, and account stats.
  • write:messages - send DMs and bulk broadcasts.
  • write:contacts - create, update, tag, and segment contacts.
  • manage:sequences - start, pause, and resume drip sequences.
  • manage:webhooks - register and rotate webhook endpoints.

A key used only by an analytics dashboard should have read:contacts and read:analytics only. If that key is ever leaked it cannot send a single message. This is the most important security decision in any API integration.

After creating the key, copy it immediately. The full token is shown only once. Store it in an environment variable (e.g., CRMSOLID_KEY) and never commit it to source control. Live keys start with cs_live_; test keys are visually distinct so you can tell them apart at a glance.

Zero-downtime rotation: when you need to rotate a key, create the replacement key first, deploy the new value to your environment, then revoke the old key. Both keys are valid during the overlap window so there are no 401 errors during the cutover.

Step 2: Make your first authenticated request

Budget: 1 minute. Pass Authorization: Bearer cs_live_... on every request. The example below sends a Telegram DM using the POST /v1/messages/send endpoint:

curl -X POST https://api.crmsolid.com/v1/messages/send   -H "Authorization: Bearer cs_live_a4f9_YOUR_KEY"   -H "Idempotency-Key: $(uuidgen)"   -H "Content-Type: application/json"   -d '{
    "account_id": 7421,
    "to": "@sarah_miller",
    "text": "Hey Sarah, your invite is ready - check your inbox."
  }'

A successful response is HTTP 200 with a JSON body:

{
  "id": "msg_01HKQ9R2X3",
  "status": "queued",
  "eta": "2026-06-04T09:00:00Z"
}

status: "queued" means the message is in the job worker queue and will be delivered within seconds. If you receive a 403 Forbidden the key is missing the write:messages scope; if you receive 401 Unauthorized the token is invalid or revoked. Both errors return an RFC 7807 problem-detail body with a stable code field you can branch on.

Step 3: Read rate-limit headers and back off

Default limits: 600 requests per minute per key. Every API response includes four headers:

  • X-RateLimit-Limit - the per-minute cap (default 600).
  • X-RateLimit-Remaining - requests left in the current window.
  • X-RateLimit-Reset - seconds until the window resets and Remaining is restored to Limit.
  • Retry-After - only present on a 429 response; the number of seconds to wait before retrying.

The right backoff strategy reads these headers before each request and pauses when Remaining approaches zero, rather than waiting for a 429. For message-send workflows, Telegram itself enforces a separate 50 sends per day per account limit; the API surfaces this as a dedicated error code.

Step 4: Core v1 REST endpoints

The complete reference is at api.crmsolid.com/swagger. The three endpoints you will use most often:

Send a message

POST /v1/messages/send - requires write:messages. Body fields: account_id (the Telegram account to send from), to (username or numeric user ID), text. Supports template variables like {first_name} resolved at send time.

Create or upsert a contact

POST /v1/contacts - requires write:contacts. Upsert on Telegram username or email. Body accepts name, username, email, tags (array of strings), and any custom fields your workspace defines. Returns the contact ID.

curl -X POST https://api.crmsolid.com/v1/contacts   -H "Authorization: Bearer cs_live_a4f9_YOUR_KEY"   -H "Idempotency-Key: $(uuidgen)"   -H "Content-Type: application/json"   -d '{
    "username": "@sarah_miller",
    "name": "Sarah Miller",
    "email": "[email protected]",
    "tags": ["trial", "webinar-2026-06"]
  }'

Enroll a contact in a sequence

POST /v1/sequences/{id}/enroll - requires manage:sequences. Body: contact_id. The sequence must already exist in the panel; the API does not create sequences. Returns the enrollment record with a status of active.

Step 5: Add idempotency keys to every write

One rule: every write request needs an Idempotency-Key header. Generate a UUID for each logical operation and store it until the operation succeeds. On a retry with the same key, the server returns the original response and does not execute the operation again.

What this prevents in practice: a message-send request times out at the network layer after the server already queued it. Without idempotency, a retry sends the same DM twice. With idempotency, the server recognises the key, returns the original msg_01HKQ9R2X3 response, and the DM is sent exactly once.

The same applies to contact creation: a retry on a failed upsert does not create a duplicate contact record.

Step 6: Subscribe to outbound webhooks

Budget: 3 minutes. Webhooks let your system react to CRM events in real time rather than polling. Register an endpoint with POST /v1/webhooks (requires manage:webhooks):

{
  "url": "https://your-app.example.com/webhooks/crm",
  "events": [
    "message.received",
    "lead.scored",
    "sequence.completed",
    "contact.created"
  ],
  "secret": "your-chosen-signing-secret"
}

CRM Solid will POST to your URL immediately when a matching event occurs. Payloads are JSON with a top-level event field, an id, a created_at timestamp, and a data object specific to the event type. Delivery is attempted with automatic exponential-backoff retries; a delivery log in the panel lets you replay any event manually.

The full list of available events includes: message.sent, message.received, message.failed, contact.created, contact.tagged, lead.scored, sequence.started, sequence.paused, sequence.completed, job.completed, and subscription.upgraded.

Step 7: Verify the webhook signature

Every webhook POST includes an X-Signature: sha256=<hex> header. Verify it before trusting the payload:

// Node.js / Express example
const crypto = require('crypto');

app.post('/webhooks/crm', express.raw({ type: 'application/json' }), (req, res) => {
  const secret = process.env.CRMSOLID_WEBHOOK_SECRET;
  const sig    = req.headers['x-signature'] || '';
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(req.body)   // raw Buffer, NOT parsed JSON
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).send('invalid signature');
  }

  const event = JSON.parse(req.body);
  // handle event.event ...
  res.status(200).send('ok');
});

Two important details: use the raw request body, not the parsed JSON object (JSON serialisation is not deterministic across environments). Use constant-time comparison (crypto.timingSafeEqual in Node.js, equivalent in other runtimes) to prevent timing attacks.

Return HTTP 200 as quickly as possible. If your handler takes longer than 10 seconds, CRM Solid marks the delivery as timed-out and retries. Enqueue the event for async processing and return 200 immediately.

Step 8: Connect the MCP server for AI agents

The Model Context Protocol (MCP) server exposes your CRM as a named tool set that an AI assistant can call directly. To configure it in Claude Desktop (or any MCP-compatible client), add a server entry pointing at the CRM Solid MCP endpoint with an API key:

// claude_desktop_config.json (or equivalent MCP config)
{
  "mcpServers": {
    "crmsolid": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.crmsolid.com/mcp"],
      "env": {
        "CRMSOLID_API_KEY": "cs_live_a4f9_YOUR_KEY"
      }
    }
  }
}

The MCP server is safe-write oriented. Read tools (list contacts, read messages, pull analytics) are always available when the key has the matching read scopes. Write tools (send message, create contact, enroll in sequence) require the corresponding write scopes and surface a permission error if the key does not have them.

Scope your MCP key to exactly what the agent needs. A summarization or reporting agent works well with read:contacts and read:messages only. An outreach agent additionally needs write:messages and optionally manage:sequences. Never grant manage:webhooks to a general-purpose chat assistant.

Note on the .NET SDK: the CrmSolid.Client NuGet package provides typed C# methods for every v1 endpoint. It handles Bearer auth, auto-generates idempotency keys per call, and implements the rate-limit backoff loop. The SDK wraps the same REST contract described in this guide; every endpoint path, scope, and header applies identically.

REST API vs MCP server vs Webhooks vs .NET SDK - when to use which

Four integration surfaces, each optimised for a different use case.

CapabilityREST APIRecommendedMCP serverWebhooks.NET SDK
Trigger model
You initiate the call
CRM pushes to you
Triggered by an AI assistant
Best for
Automation scripts and backend services
AI agent / LLM integration
Real-time event reaction (Slack, n8n, Zapier)
Typed, testable C# / .NET applications
Auth model
Bearer token (API key)
Signing secret
Scope enforcement

Use webhooks alongside the REST API or .NET SDK - they are complementary, not alternatives. Webhooks give you push events; the API gives you pull and write.

“We replaced a fragile Zapier chain with a 40-line Python script that calls the v1 API directly. Idempotency keys meant we could finally retry on transient errors without sending duplicate DMs. The whole migration took an afternoon.”
Marcus Feld
Backend Engineer · Outbound Labs

API and MCP integration FAQ

The questions developers ask most in the first hour of integration.

Every request must include an Authorization header with the value "Bearer cs_live_..." where the token is a key you generate in the panel. Live keys start with cs_live_ and test keys are visually distinct so you cannot accidentally mix them. The key is validated on every request; there is no session or cookie involved.
Yes. When you create a key you choose the exact scopes it needs: read:contacts, read:messages, read:analytics, write:messages, write:contacts, manage:sequences, and manage:webhooks. A leaked read-only dashboard key cannot send a message, start a sequence, or register a webhook. Use the smallest set of scopes each integration needs.
The default limit is 600 requests per minute per key. Every response includes four headers: X-RateLimit-Limit (the cap), X-RateLimit-Remaining (budget left in the current window), X-RateLimit-Reset (seconds until the window resets), and Retry-After (seconds to wait, only present on a 429 response). Read these headers before each request and pause when Remaining approaches zero to avoid ever receiving a 429.
An idempotency key is a UUID you generate and pass in the Idempotency-Key request header on every write operation (send message, create contact, start sequence). If the request times out and you retry with the same key, the API returns the original response instead of executing the operation again. This prevents duplicate messages and duplicate contacts even under network instability.
The Model Context Protocol (MCP) server exposes your CRM as a set of tools an AI assistant (such as Claude) can call directly. You configure it with an API key that has the scopes the assistant needs. The MCP server is safe-write oriented: read and analytics tools are always available, and write tools (send message, create contact, start sequence) require explicit write scopes. The assistant cannot call operations the key does not authorize.
Yes, within the limits of the scopes you grant. Scope your MCP key to only what the agent needs: read:contacts + read:messages for a summarization agent, or write:messages + manage:sequences for an outreach agent. The server rejects any tool call that exceeds the key's scopes. Never grant manage:webhooks or write:contacts to a general-purpose chat assistant.
Yes. The CRMSolid .NET SDK (NuGet: CrmSolid.Client) provides strongly-typed methods for every v1 endpoint. It handles Bearer auth, idempotency key generation, and rate-limit backoff out of the box. The SDK mirrors the REST contract, so everything in this guide applies equally to SDK calls.
Every outbound webhook POST includes an X-Signature header with the value "sha256=<hex>". To verify it, compute HMAC-SHA256 of the raw request body using your webhook secret, encode the result as a lowercase hex string, and compare it to the value after "sha256=". If they do not match, return 401 and discard the event. Always use a constant-time comparison to avoid timing attacks.
Ready to ship

Start building with the CRM Solid API

A 14-day trial includes full API access, all scopes, outbound webhooks, and the MCP server. Your first key is ready in 60 seconds.

Trusted by 2,500+ teams · GDPR-ready · 99.95% uptime

We value your privacy

We use cookies to improve our site, analyze traffic, and personalize ads. You can accept all, reject non-essential, or customize your choices. Read our Cookie Policy.