Download OpenAPI specification:
The Swarmhit API lets you manage LinkedIn outreach campaigns, contacts and your inbox programmatically, and receive real-time events via webhooks.
Every request must carry an API key as a bearer token:
Authorization: Bearer swh_live_xxxxxxxxxxxxxxxxxxxxxxxx
Create and revoke keys under Settings → API & Webhooks in the Swarmhit app. A key's full value is shown only once, at creation — store it securely. Each key is scoped to the workspace it was created in.
List endpoints accept limit (1–100, default 50) and offset query
parameters, and return a paging object alongside data.
Errors use standard HTTP status codes with a JSON body:
{ "error": { "status": 404, "message": "Campaign not found." } }
Register webhook endpoints under Settings → API & Webhooks. Swarmhit POSTs a JSON payload to your URL when a subscribed event occurs. Every request includes these headers:
X-Swarmhit-Event — the event typeX-Swarmhit-Delivery — a unique delivery id; delivery is at-least-once,
so use this to deduplicateX-Swarmhit-Signature — an HMAC-SHA256 hex digest of the raw request
body, keyed by the endpoint's signing secretVerify the signature before trusting a payload:
const crypto = require('crypto');
const expected = crypto
.createHmac('sha256', SIGNING_SECRET)
.update(rawRequestBody)
.digest('hex');
const ok = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(req.headers['x-swarmhit-signature'] || ''),
);
Respond with any 2xx status to acknowledge receipt. Non-2xx responses are
retried with exponential backoff; an endpoint that keeps failing is
automatically disabled.
| limit | integer [ 1 .. 100 ] Default: 50 Page size, 1–100. |
| offset | integer >= 0 Default: 0 Number of records to skip. |
{- "data": [
- {
- "id": "string",
- "name": "string",
- "status": "draft",
- "stats": {
- "total": 0,
- "done": 0,
- "failed": 0
}, - "linkedinAccountId": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "paging": {
- "limit": 0,
- "offset": 0
}
}{- "data": {
- "id": "string",
- "name": "string",
- "status": "draft",
- "stats": {
- "total": 0,
- "done": 0,
- "failed": 0
}, - "linkedinAccountId": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
}Adds leads from LinkedIn profile URLs. Each profile is resolved best-effort for templating fields; an unresolved profile is still added. Leads already in the campaign are skipped. Max 100 per request.
| id required | string |
required | Array of strings or LeadInput (object) <= 100 items |
{- "leads": [
]
}{- "data": {
- "inserted": 0
}
}| limit | integer [ 1 .. 100 ] Default: 50 Page size, 1–100. |
| offset | integer >= 0 Default: 0 Number of records to skip. |
| search | string Case-insensitive match on name, headline, email or company. |
{- "data": [
- {
- "id": "string",
- "fullName": "string",
- "firstName": "string",
- "lastName": "string",
- "headline": "string",
- "jobTitle": "string",
- "company": "string",
- "email": "string",
- "location": "string",
- "profileUrl": "string",
- "publicIdentifier": "string",
- "tags": [
- "string"
], - "createdAt": "2019-08-24T14:15:22Z"
}
], - "paging": {
- "limit": 0,
- "offset": 0
}
}Adds contacts to the workspace address book from LinkedIn profile
URLs. Pass a single contact, or a contacts array (max 100).
Contacts are deduplicated on their LinkedIn identifier.
| profileUrl required | string |
| firstName | string |
| lastName | string |
| fullName | string |
| headline | string |
| jobTitle | string |
| company | string |
string | |
| location | string |
{- "contacts": [
]
}{- "data": {
- "created": 0,
- "skipped": 0,
- "ids": [
- "string"
]
}
}| limit | integer [ 1 .. 100 ] Default: 50 Page size, 1–100. |
| offset | integer >= 0 Default: 0 Number of records to skip. |
{- "data": [
- {
- "id": "string",
- "attendee": { },
- "contactId": "string",
- "leadId": "string",
- "lastMessage": { },
- "lastMessageAt": "2019-08-24T14:15:22Z",
- "unreadCount": 0
}
], - "paging": {
- "limit": 0,
- "offset": 0
}
}| id required | string |
| limit | integer [ 1 .. 100 ] Default: 50 Page size, 1–100. |
| offset | integer >= 0 Default: 0 Number of records to skip. |
{- "data": [
- {
- "id": "string",
- "text": "string",
- "isFromMe": true,
- "at": "2019-08-24T14:15:22Z"
}
], - "paging": {
- "limit": 0,
- "offset": 0
}
}| id required | string |
| text required | string |
{- "text": "Thanks for connecting! Happy to share more."
}{- "data": {
- "ok": true,
- "messageId": "string"
}
}Sent when a lead replies to a LinkedIn message.
| X-Swarmhit-Event | string The event type. |
| X-Swarmhit-Delivery | string Unique delivery id — delivery is at-least-once, so use this to deduplicate. |
| X-Swarmhit-Signature | string HMAC-SHA256 hex digest of the raw request body, keyed by the endpoint's signing secret. |
| event | string Value: "message.received" |
| workspaceId | string |
| createdAt | string <date-time> |
object |
{- "event": "message.received",
- "workspaceId": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "data": {
- "leadId": "string",
- "campaignId": "string",
- "contactId": "string",
- "chatId": "string",
- "message": {
- "text": "string",
- "at": "2019-08-24T14:15:22Z"
}, - "from": {
- "fullName": "string",
- "publicIdentifier": "string",
- "providerId": "string"
}
}
}Sent when a lead accepts the connection request.
| X-Swarmhit-Event | string The event type. |
| X-Swarmhit-Delivery | string Unique delivery id — delivery is at-least-once, so use this to deduplicate. |
| X-Swarmhit-Signature | string HMAC-SHA256 hex digest of the raw request body, keyed by the endpoint's signing secret. |
| event | string Value: "connection.accepted" |
| workspaceId | string |
| createdAt | string <date-time> |
object |
{- "event": "connection.accepted",
- "workspaceId": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "data": {
- "leadId": "string",
- "campaignId": "string",
- "contactId": "string",
- "acceptedAt": "2019-08-24T14:15:22Z",
- "contact": {
- "fullName": "string",
- "publicIdentifier": "string",
- "providerId": "string"
}
}
}Sent when a lead reaches a resting status — replied, done, failed or paused.
| X-Swarmhit-Event | string The event type. |
| X-Swarmhit-Delivery | string Unique delivery id — delivery is at-least-once, so use this to deduplicate. |
| X-Swarmhit-Signature | string HMAC-SHA256 hex digest of the raw request body, keyed by the endpoint's signing secret. |
| event | string Value: "lead.status_changed" |
| workspaceId | string |
| createdAt | string <date-time> |
object |
{- "event": "lead.status_changed",
- "workspaceId": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "data": {
- "leadId": "string",
- "campaignId": "string",
- "contactId": "string",
- "oldStatus": "string",
- "newStatus": "replied",
- "lead": {
- "fullName": "string",
- "publicIdentifier": "string"
}
}
}Sent when a campaign has completed every one of its leads.
| X-Swarmhit-Event | string The event type. |
| X-Swarmhit-Delivery | string Unique delivery id — delivery is at-least-once, so use this to deduplicate. |
| X-Swarmhit-Signature | string HMAC-SHA256 hex digest of the raw request body, keyed by the endpoint's signing secret. |
| event | string Value: "campaign.finished" |
| workspaceId | string |
| createdAt | string <date-time> |
object |
{- "event": "campaign.finished",
- "workspaceId": "string",
- "createdAt": "2019-08-24T14:15:22Z",
- "data": {
- "campaignId": "string",
- "name": "string",
- "stats": {
- "total": 0,
- "done": 0,
- "failed": 0
}
}
}