Skip to main content

CRM Block

CRM Block

Enterprise customer relationship management through a simple REST API

The CRM Block provides a complete customer relationship management solution. Manage unlimited contacts, track company accounts, build deal pipelines, log activities, and score leads - all through a RESTful API with real-time webhooks.

Key Features

  • Contact Management - Unlimited contacts with custom fields, tags, and segmentation
  • Company Accounts - Link contacts to companies with hierarchies and account scoring
  • Deal Pipeline - Customizable stages, probability tracking, and revenue forecasting
  • Activity Tracking - Calls, emails, meetings, and tasks with timeline views
  • Lead Scoring - Behavioral scoring with custom rules and score decay
  • Custom Fields - Define unlimited custom fields for contacts, companies, and deals
  • Relationship Insights - Health scores, engagement analytics, and next-best-action
  • Real-time Webhooks - Instant notifications for all record changes

API Endpoint

ServiceURL
CRMhttps://crm.api.us.23blocks.com

Environment Routing: One URL, one environment. All shared-platform API keys are live keys:

  • pk_live_* / sk_live_* → your production tenant. Need a separate staging environment? It is available as a paid add-on on deployments in your own cloud account — see 23blocks in a Box.

Quick Start

Installation

npm install @23blocks/sdk

Basic Usage

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { crm: 'https://crm.api.us.23blocks.com' },
apiKey: 'your-api-key',
});

// Create a contact
const contact = await client.crm.contacts.create({
first_name: 'Jane',
last_name: 'Smith',
email: 'jane@company.com',
phone: '+1-555-0123',
tags: ['enterprise', 'decision-maker']
});

// Create a company and link the contact
const company = await client.crm.companies.create({
name: 'Acme Corp',
industry: 'Technology',
size: '100-500',
website: 'https://acme.com'
});

// Link contact to company
await client.crm.contacts.update(contact.id, {
company_id: company.id
});

// Create a deal
const deal = await client.crm.deals.create({
name: 'Enterprise License',
contact_id: contact.id,
company_id: company.id,
value: 50000,
stage: 'qualified',
probability: 60,
expected_close_date: '2025-03-31'
});

Authentication

Required Headers

All API requests require authentication:

Authorization: Bearer [JWT_TOKEN]
X-API-Key: [COMPANY_API_KEY]
Content-Type: application/json

API Reference


Contacts

Create Contact

Create a new contact record.

POST /api/v1/contacts

Request Body:

{
"data": {
"type": "contacts",
"attributes": {
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@company.com",
"phone": "+1-555-0123",
"title": "VP of Engineering",
"company_id": "comp_abc123",
"tags": ["enterprise", "decision-maker"],
"custom_fields": {
"department": "Engineering",
"budget_authority": true
}
}
}
}

Response:

{
"data": {
"id": "cont_xyz789",
"type": "contacts",
"attributes": {
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@company.com",
"phone": "+1-555-0123",
"title": "VP of Engineering",
"company_id": "comp_abc123",
"tags": ["enterprise", "decision-maker"],
"custom_fields": {
"department": "Engineering",
"budget_authority": true
},
"lead_score": 0,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
}
}

Get Contact

Retrieve a contact by ID.

GET /api/v1/contacts/:id

Query Parameters:

ParameterTypeDescription
includestringRelated resources: company,deals,activities

List Contacts

Retrieve a paginated list of contacts.

GET /api/v1/contacts

Query Parameters:

ParameterTypeDescription
page[number]integerPage number (default: 1)
page[size]integerItems per page (default: 25, max: 100)
filter[email]stringFilter by email (exact match)
filter[company_id]stringFilter by company
filter[tags]stringFilter by tags (comma-separated)
filter[lead_score_min]integerMinimum lead score
filter[lead_score_max]integerMaximum lead score
sortstringSort field: created_at, -created_at, lead_score, -lead_score

Update Contact

Update an existing contact.

PATCH /api/v1/contacts/:id

Delete Contact

Delete a contact (soft delete by default).

DELETE /api/v1/contacts/:id

Merge Contacts

Merge duplicate contacts into one.

POST /api/v1/contacts/:id/merge

Companies

Create Company

Create a new company account.

POST /api/v1/companies

Request Body:

{
"data": {
"type": "companies",
"attributes": {
"name": "Acme Corp",
"domain": "acme.com",
"industry": "Technology",
"size": "100-500",
"website": "https://acme.com",
"phone": "+1-555-0100",
"address": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"country": "US"
},
"parent_company_id": null
}
}
}

List Companies

GET /api/v1/companies

Query Parameters:

ParameterTypeDescription
filter[industry]stringFilter by industry
filter[size]stringFilter by company size
filter[parent_company_id]stringFilter by parent company
sortstringSort: name, created_at, -account_score

Get Company Hierarchy

Get the full company hierarchy (parent and children).

GET /api/v1/companies/:id/hierarchy

Deals

Create Deal

Create a new deal/opportunity.

POST /api/v1/deals

Request Body:

{
"data": {
"type": "deals",
"attributes": {
"name": "Enterprise License - Acme Corp",
"contact_id": "cont_xyz789",
"company_id": "comp_abc123",
"pipeline_id": "pipe_default",
"stage": "qualified",
"value": 50000,
"currency": "USD",
"probability": 60,
"expected_close_date": "2025-03-31"
}
}
}

Move Deal Stage

Move a deal to a different pipeline stage.

POST /api/v1/deals/:id/stage

Request Body:

{
"stage": "proposal",
"probability": 75,
"notes": "Sent proposal, awaiting response"
}

Win Deal

Mark a deal as won.

POST /api/v1/deals/:id/win

Lose Deal

Mark a deal as lost.

POST /api/v1/deals/:id/lose

List Deals by Pipeline

Get deals grouped by pipeline stage.

GET /api/v1/pipelines/:pipeline_id/deals

Pipelines

Create Pipeline

Create a custom sales pipeline.

POST /api/v1/pipelines

Request Body:

{
"data": {
"type": "pipelines",
"attributes": {
"name": "Enterprise Sales",
"stages": [
{ "name": "lead", "order": 1, "probability": 10 },
{ "name": "qualified", "order": 2, "probability": 25 },
{ "name": "proposal", "order": 4, "probability": 60 },
{ "name": "won", "order": 6, "probability": 100, "is_closed": true, "is_won": true },
{ "name": "lost", "order": 7, "probability": 0, "is_closed": true, "is_won": false }
]
}
}
}

Activities

Create Activity

Log a sales activity.

POST /api/v1/activities

Request Body:

{
"data": {
"type": "activities",
"attributes": {
"type": "call",
"subject": "Discovery Call",
"contact_id": "cont_xyz789",
"deal_id": "deal_def456",
"notes": "Discussed requirements. Interested in enterprise features.",
"duration_minutes": 30,
"outcome": "positive",
"completed_at": "2025-01-15T14:00:00Z"
}
}
}

Activity Types:

TypeDescription
callPhone call
emailEmail sent/received
meetingIn-person or virtual meeting
taskTo-do task
noteGeneral note

Get Contact Timeline

Get all activities for a contact as a timeline.

GET /api/v1/contacts/:id/timeline

Lead Scoring

Get Lead Score

Get the current lead score and breakdown.

GET /api/v1/contacts/:id/score

Response:

{
"data": {
"contact_id": "cont_xyz789",
"total_score": 85,
"breakdown": {
"behavioral": 45,
"demographic": 25,
"engagement": 15
},
"factors": [
{ "name": "Email opened (5x)", "points": 10 },
{ "name": "Website visited", "points": 15 },
{ "name": "Pricing page viewed", "points": 20 },
{ "name": "Enterprise company size", "points": 15 }
],
"grade": "A"
}
}

Configure Scoring Rules

Define custom lead scoring rules.

POST /api/v1/scoring-rules

Custom Fields

Create Custom Field

Define a custom field for contacts, companies, or deals.

POST /api/v1/custom-fields

Field Types:

TypeDescription
textSingle-line text
textareaMulti-line text
numberNumeric value
currencyMoney value
dateDate value
booleanYes/No
dropdownSingle select
multiselectMultiple select

Webhooks

Webhook Events

Subscribe to CRM events in real-time.

EventDescription
contact.createdNew contact created
contact.updatedContact updated
contact.deletedContact deleted
company.createdNew company created
deal.createdNew deal created
deal.stage_changedDeal moved stages
deal.wonDeal marked as won
deal.lostDeal marked as lost
activity.createdActivity logged
lead_score.changedLead score updated

Create Webhook

POST /api/v1/webhooks

SDK Examples

TypeScript

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { crm: 'https://crm.api.us.23blocks.com' },
apiKey: process.env.BLOCKS_API_KEY!,
});

// Create contact with company
async function createLead(data: LeadData) {
let company = await client.crm.companies.findByDomain(data.companyDomain);

if (!company) {
company = await client.crm.companies.create({
name: data.companyName,
domain: data.companyDomain
});
}

const contact = await client.crm.contacts.create({
first_name: data.firstName,
last_name: data.lastName,
email: data.email,
company_id: company.id,
tags: ['new-lead']
});

return contact;
}

// Move deal through pipeline
async function advanceDeal(dealId: string, newStage: string) {
const deal = await client.crm.deals.updateStage(dealId, {
stage: newStage
});

if (newStage === 'proposal') {
await client.crm.tasks.create({
subject: 'Follow up on proposal',
deal_id: dealId,
due_date: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
priority: 'high'
});
}

return deal;
}

Error Codes

CodeDescription
CRM001Contact not found
CRM002Company not found
CRM003Deal not found
CRM004Pipeline not found
CRM005Invalid stage transition
CRM006Duplicate contact (same email)
CRM007Custom field validation failed

Rate Limits

PlanRequests/minuteContactsCompaniesDeals
Free601,000100100
Starter30010,0001,0001,000
Pro1,000100,00010,00010,000
EnterpriseCustomUnlimitedUnlimitedUnlimited

Use This Block with AI Agents

This block ships an official Claude Code plugin from the public 23blocks marketplace (19 plugins, 205 skills). Your agent gets full working knowledge of this API — endpoints, identity registration, and conventions.

# one-time: add the 23blocks marketplace
claude plugin marketplace add https://github.com/23blocks-OS/ai-agents

# install this block's plugin
claude plugin install crm-block

Configure BLOCKS_API_URL, BLOCKS_API_KEY, and BLOCKS_AUTH_TOKEN. Register identity first: each block is autonomous — register the user with this block's identity endpoint before private calls (only user_unique_id is required; email/phone are optional notification-routing fields).

Full reference: AI Agents & Claude Code Plugins · github.com/23blocks-OS/ai-agents