Skip to content

CRM Integration

SM CRM (api.sprintmode.ai) is the single source of truth for contacts, companies, deals, activities, and engagements. All SM products read and write to the same DB — tagged by product field to keep data scoped.

The Product Tag

Tag every record with product to scope it to your product:

bash
# Create a company tagged to Mode
curl -X POST https://api.sprintmode.ai/api/companies \
  -H "X-SM-Key: $SM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "product": "mode",
    "company_type": "client"
  }'

Then filter by your product when reading:

bash
GET /api/companies?product=mode
GET /api/contacts?product=mode
GET /api/engagements?product=mode

Key Relationships

companies (Acme Corp)
  └── contacts (Jane Smith — portal_access: 1)
  └── engagements (Mode implementation retainer)
  └── invoices (INV-2026-001)
  └── deals (Mode expansion deal)

contacts
  └── activities (call, email, note, transcript)
  └── magic_sessions (login tokens)

Granting Portal Access

bash
# Grant Jane portal access to your product
curl -X PATCH https://api.sprintmode.ai/api/contacts/ct_abc123 \
  -H "X-SM-Key: $SM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "portal_access": 1,
    "product": "mode",
    "portal_role": "client_admin"
  }'

Jane can now:

  1. Click a magic link → log in to mode.sprintmode.ai
  2. Log in with Google SSO (if her email is in CRM)

Her JWT will include "products": ["mode"].

Logging Activities

Every significant action should generate an activity:

js
// From a product worker or page action
await api('/api/activities', null, {
  method: 'POST',
  body: {
    activity_type: 'scan_completed',
    company_id: 'co_abc123',
    contact_id: 'ct_def456',
    title: 'Mode scan completed',
    description: 'Full technology audit finished. 47 systems mapped.',
    source: 'mode',
    metadata: { scan_id: 'scan_xyz', systems_found: 47 }
  }
})

Activity types are free-form — use descriptive names like scan_completed, report_generated, phase_started.

Calling CRM from a Portal Worker

Portal workers call SM API server-to-server using CF Access service token credentials:

js
// In _worker.js

async function smApi(path, env, options = {}) {
  const res = await fetch('https://api.sprintmode.ai' + path, {
    method: options.method || 'GET',
    headers: {
      'Content-Type': 'application/json',
      'CF-Access-Client-Id': env.SM_API_CLIENT_ID,
      'CF-Access-Client-Secret': env.SM_API_CLIENT_SECRET,
      ...(options.headers || {})
    },
    body: options.body ? JSON.stringify(options.body) : undefined
  })

  if (!res.ok) throw new Error('SM API error: ' + res.status)
  return res.json()
}

// Usage
const { data: company } = await smApi('/api/companies/co_abc123', env)
const { data: engagements } = await smApi('/api/engagements?company_id=co_abc123&product=mode', env)

Calling CRM from the Browser

Use the api() helper which sends cookies automatically:

js
import { api } from '@nomadahq/sm-ui'

// GET with query params
const { data: contacts } = await api('/api/contacts', {
  company_id: 'co_abc123',
  product: 'mode'
})

// POST
await api('/api/activities', null, {
  method: 'POST',
  body: { activity_type: 'report_viewed', company_id: 'co_abc123' }
})

// PATCH
await api('/api/contacts/ct_abc123', null, {
  method: 'PATCH',
  body: { pipeline_stage: 'onboarding' }
})

Using the MCP Server

If you're building an AI agent that needs to read/write CRM data, use the SM MCP server instead of calling the API directly:

SSE endpoint: https://api.sprintmode.ai/mcp/sse
Auth: Bearer <SM_API_KEY>

The MCP server exposes all CRM data as tools that Claude can call. Register it in your Claude project settings.

Data Isolation

All SM products share the same CRM DB. Data isolation is by convention (the product tag), not by database separation. This means:

  • Any SM API key can read any product's data
  • Admin portal users can see all products' data
  • Use the product filter consistently — don't skip it

For products that need stricter isolation (e.g. competitor-sensitive client data), contact Aaron to discuss row-level security options.

Sprint Mode LLC — Internal Platform Documentation