REST API

The Breadbox public API lets you read and write data from any tool — PSA, RMM, automation platforms, or your own code. Every API call is scoped, authenticated, and audit-logged.

Base URL

https://app.mspcrm.com/api/v1

All endpoints are versioned under /api/v1. Breaking changes will be released as /api/v2 with a minimum 6-month deprecation window.

Authentication

Every request requires a Bearer token in the Authorization header. Generate API keys in Settings → API & Webhooks.

# Example request curl https://app.mspcrm.com/api/v1/accounts \ -H "Authorization: Bearer msp_live_xxxxxxxx"

Keys are prefixed with msp_live_ for production and msp_test_ for test environments. Keys are SHA-256 hashed at rest — store them securely as they cannot be retrieved after creation.

Scopes

Each API key is granted one or more scopes. A request will fail with 403 Forbidden if the key lacks the required scope. Write scopes imply the corresponding read scope.

ScopeWhat it grants
accounts:readRead accounts, sites, account details
accounts:writeCreate and update accounts (implies accounts:read)
contacts:readRead contacts and account relationships
contacts:writeCreate and update contacts
contracts:readRead contracts, service lines, amendments
deals:readRead pipeline deals and stages
deals:writeCreate and update deals, change stages
health:readRead health scores and signal breakdowns
health:writePush external health signals
touchpoints:readRead touchpoints and QBR records
touchpoints:writeLog touchpoints from external tools
devices:readRead device inventory
devices:writePush/update device data from RMM
reconciliation:readRead reconciliation records
reconciliation:writeSubmit seat/device count reports
mrr:readRead MRR data and financial summaries
leads:readRead leads and ICP scores
leads:writeCreate and update leads
compliance:readRead compliance items and framework status
onboarding:readRead onboarding projects and milestones
admin:readImplies all :read scopes — use for full integrations

Rate Limits

Rate limits are enforced per API key and per organization. Every response includes rate limit headers so you can track consumption.

PlanPer-key limitOrg-wide limit
Starter30 req/min60 req/min
Growth60 req/min120 req/min
Scale120 req/min240 req/min
Pro / Enterprise120 req/min480 req/min
# Rate limit response headers X-RateLimit-Limit: 60 X-RateLimit-Remaining: 55 X-RateLimit-Reset: 1710000060 Retry-After: 30 # Only on 429 responses

Response Envelope

All responses follow a consistent JSON envelope:

// Single object { "success": true, "data": { ... }, "requestId": "req_xxxxx" }
// Paginated list { "success": true, "data": [...], "hasMore": true, "nextCursor": "cuid_xxxxx", "requestId": "req_xxxxx" }
// Error { "success": false, "error": { "code": "validation_error", "message": "name must be at least 1 character" }, "requestId": "req_xxxxx" }

Pagination

All list endpoints use cursor-based pagination. Pass the cursor from the previous response to fetch the next page.

# First page GET /api/v1/accounts?take=50 # Next page GET /api/v1/accounts?take=50&cursor=cuid_xxxxx

Default page size is 50. Maximum is 100. When hasMore: false, you have reached the last page.

Available Endpoints

GET/api/v1/accountsList accounts (filter by lifecycle, industry)
POST/api/v1/accountsCreate an account
GET/api/v1/accounts/:idGet a single account
PATCH/api/v1/accounts/:idUpdate an account
DELETE/api/v1/accounts/:idSoft-delete an account (sets lifecycle to CHURNED)
GET/api/v1/contactsList contacts (filter by accountId)
POST/api/v1/contactsCreate a contact (optionally link to account)
GET/api/v1/contacts/:idGet a single contact with account relationships
PATCH/api/v1/contacts/:idUpdate a contact
GET/api/v1/contractsList contracts (read-only in v1)
GET/api/v1/contracts/:idGet a contract with service lines and amendments
GET/api/v1/dealsList deals (filter by stage, accountId)
POST/api/v1/dealsCreate a deal
GET/api/v1/deals/:idGet a single deal
PATCH/api/v1/deals/:idUpdate a deal (including stage change and Won/Lost outcome)
GET/api/v1/health-scoresList accounts with their current health scores
GET/api/v1/health-scores/:accountIdGet health score + signal breakdown + 90-day history
POST/api/v1/health-scores/:accountId/signalsPush an external health signal
GET/api/v1/touchpointsList touchpoints (filter by accountId)
POST/api/v1/touchpointsLog a touchpoint from an external tool
GET/api/v1/devicesList devices (filter by accountId)
POST/api/v1/devicesCreate a device
POST/api/v1/devices/bulkBatch upsert devices by rmmAgentId (max 500)
GET/api/v1/mrrOrg-level MRR summary broken down by service category
GET/api/v1/reconciliationList reconciliation records
POST/api/v1/reconciliationSubmit a seat/device count report for reconciliation

Error Codes

HTTP StatusError CodeMeaning
400bad_requestMissing or malformed path parameter
400invalid_jsonRequest body is not valid JSON
401unauthorizedMissing or invalid API key
403forbiddenKey lacks the required scope
404not_foundRecord not found or belongs to another org
405method_not_allowedHTTP method not supported on this endpoint
422validation_errorRequest body failed schema validation
429rate_limitedRate limit exceeded — see Retry-After header
500internal_errorUnexpected server error — retry with backoff

Webhooks

Breadbox can push real-time events to your endpoints as data changes. Configure endpoints in Settings → API & Webhooks.

Every webhook POST includes an X-MSP-Signature header — an HMAC-SHA256 signature of the request body using your endpoint's signing secret. Always verify signatures before processing.

// Webhook payload envelope { "id": "evt_1710000000_abc123", "event": "account.created", "timestamp": "2025-03-15T14:00:00.000Z", "orgId": "org_xxxxx", "data": { ... } }

Available events:

account.createdaccount.updatedaccount.deletedcontact.createdcontact.updatedcontract.createdcontract.updatedcontract.expiring_soondeal.createddeal.stage_changeddeal.closed_wondeal.closed_losthealth_score.changedhealth_score.alerttouchpoint.createddevice.createddevice.updateddevice.offlinedevice.end_of_lifereconciliation.variance_detectednotification.created
// Node.js signature verification import { createHmac, timingSafeEqual } from 'crypto'; function verifyWebhook(body: string, signature: string, secret: string) { const expected = createHmac('sha256', secret) .update(body) .digest('hex'); return timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); }

SDK & Examples

The Breadbox API follows standard REST conventions — any HTTP client works. Here are quick-start examples:

# Python import requests BASE = "https://app.mspcrm.com/api/v1" HEADERS = {"Authorization": "Bearer msp_live_xxxxx"} # List accounts accounts = requests.get(f"{BASE}/accounts", headers=HEADERS).json() # Create a deal deal = requests.post(f"{BASE}/deals", headers=HEADERS, json={ "name": "Acme Corp — Managed IT", "accountId": "cuid_xxxxx", "estimatedMrr": 3500, "probability": 60, }).json()
# PowerShell (for MSP tools) $headers = @{ Authorization = "Bearer msp_live_xxxxx" } $base = "https://app.mspcrm.com/api/v1" # Push device data from RMM $body = @{ accountId = "cuid_xxxxx"; hostname = "WS-SMITH-01" deviceType = "Workstation"; os = "Windows 11" } | ConvertTo-Json Invoke-RestMethod -Uri "$base/devices" -Method POST -Headers $headers -Body $body -ContentType "application/json"

Need help or found a bug?

API questions, feature requests, and bug reports: reach out at api@mspcrm.com or open an issue in the GitHub repo.