API & API keys
Push contacts, deals and appointments in from your own systems.
What the API is for
The REST API lets your own systems — a landing page, an automation tool, your product — push records into the CRM. It currently covers creating contacts, opportunities and appointments. Reading and updating through the REST API are not yet available.
If you need software to read and update records, AI assistants can do that over MCP, within their user's permissions.
Getting a key
In Settings → API keys, admins and above can create a named key. The full key is shown once, at creation — copy it then, because only a one-way digest is stored and it cannot be shown again. Keys can be revoked or deleted at any time and stop working immediately.
Authenticating
Send the key as a bearer token:
Authorization: Bearer swc_acc_your_key_here
A missing, invalid or revoked key returns 401 with a JSON body. Every request is scoped to the
account the key belongs to, so there is no way to reach another account's data.
Endpoints
| Method | Path | Creates |
|---|---|---|
| POST | /api/v1/contacts | A contact |
| POST | /api/v1/opportunities | A deal, with its contact |
| POST | /api/v1/appointments | An appointment, with its contact |
Creating a contact
POST /api/v1/contacts
Content-Type: application/json
{
"contact": {
"name": "Dana Whitfield",
"email": "dana@example.com",
"phone_number": "+15550109999",
"custom_fields_values": { "industry": "Logistics" }
}
}
A custom field of the yes/no type accepts true or false, and an explicit
false is stored as “no” rather than dropped.
Creating an opportunity
Contact details are nested. The contact is matched by email, or created if there is no match, so you do not need to look up an identifier first.
The new deal is placed in your pipeline's first open stage, and keeps the source
you send. Identifiers for the stage, owner or other records in the request are ignored.
POST /api/v1/opportunities
Content-Type: application/json
{
"opportunity": {
"title": "Fleet renewal",
"value_cents": 450000,
"source": "website",
"contact_attributes": {
"name": "Dana Whitfield",
"email": "dana@example.com",
"phone_number": "+15550109999"
}
}
}
Creating an appointment
POST /api/v1/appointments
Content-Type: application/json
{
"appointment": {
"title": "Discovery call",
"start_time": "2026-09-01T15:00:00Z",
"end_time": "2026-09-01T15:30:00Z",
"location": "https://example.com/meet/abc",
"contact_attributes": {
"name": "Dana Whitfield",
"phone_number": "+15550109999"
}
}
}
Responses
| Status | Meaning |
|---|---|
201 | Created. |
401 | Missing, invalid or revoked key. |
403 | The email domain is blocked for your account. |
422 | Validation failed. The body lists what was wrong. |
Creating a record and its contact happens as a single unit — either both succeed or neither is written, so a failure never leaves a half-created contact behind.
Attribution
Records created through the API are attributed to the key that made them, so a record's history shows the key name marked as API rather than an anonymous change.
Rate limiting
Requests are rate limited per address. Sustained bulk imports should be paced accordingly.