Swimlane
Volver al centro de ayuda

Swimlane public API reference

An overview of every public API endpoint, with the fields you can send and read. For a hands-on start, see Create an API token and make your first request. The interactive version is at https://api.getswimlane.com/docs.

Basics

  • Base URL: https://api.getswimlane.com/v1
  • Authentication: Authorization: Bearer wpa_…, with a token created in Settings → API.
  • Scope: everything happens in the organization you last used in the app. Campaigns, reminders and recurring imports are scoped further, to the token's own user — they run on that person's LinkedIn session, so a token never sees a teammate's.
  • Pagination (list endpoints): page, per_page (default 50, maximum 100). Responses are { "meta": {…}, "data": [ … ] }.
  • Limit: 100 requests per minute per user, with X-RateLimit-* on every response.
  • Errors: 401 bad token, 403 no organization, 404 resource.not_found, 409 the state forbids it, 422 validation.failed with an errors array, 429 rate_limit.exceeded.
  • Everything is logged in Settings → API: method, path, status and duration.

Imports — how contacts get in

POST /imports creates a list and fills it from LinkedIn. This is the entry point: every other endpoint works on contacts already in the workspace.

{
  "source": "competitor_engagement",
  "listName": "Engaged with Acme — September",
  "profileUrl": "https://www.linkedin.com/in/acme-founder/",
  "recurring": true
}
source Reads Needs
post_engagement who reacted to or commented on a post postUrl
competitor_engagement who engages with someone else's posts profileUrl
profile_engagement who engages with your own posts —
profile_visitors who viewed your profile in a date range from, to
people_search a people search written as a persona persona
topic_search a topic turned into a boolean search topic, strategy
suggested_contacts the people LinkedIn suggests to you —
  • It answers 202, and the list is empty. The scraping runs in the background on your LinkedIn session; follow it with GET /queue or watch the list status go scheduled → importing → done.
  • The daily import limit is claimed when the task runs, not when you call. An import started past it waits for tomorrow instead of failing, and a run outside your virtual office hours is deferred rather than dropped.
  • A source missing what it reads answers 422 import.missing_parameters.
  • recurring: true also registers a schedule. Manage them with GET /imports/recurring, PATCH /imports/recurring/:uuid ({"isActive": false} pauses) and DELETE /imports/recurring/:uuid (the list and its contacts are kept). The interval is randomized within a range on every run, so frequencyHours reports the last one used rather than a cadence you can set — a metronome is an automation fingerprint.

Contacts

  • GET /contacts: newest first. Filters: search (first name, last name or email), list_uuid, tag_id, archived.
  • GET /contacts/:uuid, POST /contacts, PATCH /contacts/:uuid, DELETE /contacts/:uuid.

Fields you can send (all optional): firstName, lastName, email, phone, website, headline, note, location, countryIso (2 letters), archived, linkedinId.

Fields you read: the above plus uuid, avatarUrl, followersCount, isPremium, isCreator, isInfluencer, listUuids, companyUuids, tagIds, pipelineStageUuid, createdAt, updatedAt.

Notes:

  • linkedinId is the field that decides everything. It takes the public identifier or the profile URL it sits in (https://www.linkedin.com/in/…), and it is what makes a contact reachable. A contact without one is a CRM record and nothing else: every campaign step that touches LinkedIn refuses it, retries three times and lands in failed. It cannot be guessed later from a name or an email, so carry the profile URL when you push leads in from elsewhere.
  • It is unique per organization. A duplicate answers 409 contact.linkedin_id_taken and names the contact that already holds it, rather than merging two people.
  • Writing note or headline marks the contact's cached ICP scores stale, so they are recomputed.
  • pipelineStageUuid gives one stage, taken from the pipelines you can see.
  • The responses to POST and PATCH leave listUuids, companyUuids and tagIds empty and pipelineStageUuid null. Read the contact again with GET to get them.
  • Responses also carry a score field. It is an internal value the app no longer shows. Don't build on it.

Lists

  • GET /lists, GET /lists/:uuid, POST /lists (name required, description, icon), PATCH, DELETE.
  • POST /lists/:uuid/contacts: body {"contactUuids": ["…"]}. Contacts already in the list, and unknown uuids, are skipped without error.
  • DELETE /lists/:uuid/contacts/:contactUuid.

Fields you read: uuid, name, description, icon, status, source, createdAt, updatedAt. source names the import that produced the list, or is null when someone created it by hand.

Adding to a list is not inert. If a running campaign uses it as its source and was created with continuous: true, the contacts you add are enrolled on its next scan — within a minute or so, they start receiving its invitations and messages.

Companies (read only)

GET /companies (filter: search), GET /companies/:uuid. Fields: uuid, name, linkedinId, logoUrl, createdAt, updatedAt.

Tags

  • GET /tags, POST /tags (name required, color as #RRGGBB), PATCH /tags/:id, DELETE /tags/:id.
  • GET /contacts/:uuid/tags, POST /contacts/:uuid/tags with {"tagIds": [12, 18]}. It replaces all the contact's tags. Send [] to remove them all.

A tag is one row per name, shared by every workspace. "inbound" is the same tag everywhere. So renaming one that others also use copies it first and renames the copy, and deleting one only detaches it from your contacts. Neither can reach into someone else's workspace.

Pipelines and stages

  • GET /pipelines, POST /pipelines (name required, visibility private or team, icon), PATCH, DELETE.
  • GET /pipelines/:uuid/stages, POST /pipelines/:uuid/stages, PATCH /pipelines/stages/:stageUuid, DELETE /pipelines/stages/:stageUuid.
  • POST /pipelines/stages/:stageUuid/contacts with {"contactUuids": ["…"]}. A contact sits in one stage per pipeline, so this also moves it.
  • DELETE /pipelines/stages/:stageUuid/contacts/:contactUuid.

Stage fields: uuid, name, icon, color, type, order, createdAt, updatedAt.

  • type is done, abandoned or null, and you can set it on create and update. Both values are terminal: Swimlane stops offering those contacts for follow-up. A "Won" column created without it keeps nudging you about deals you closed months ago.
  • A new pipeline comes with the same four stages the app creates — Cold, Connected, Engaged and Closed, the last already typed done.
  • A teammate's private pipeline cannot be read or changed. visibility: team is the only way to share one.

Reminders

GET /reminders (filters: completed, contact_uuid, due_after, due_before, order), GET /reminders/:uuid, POST, PATCH, DELETE, and GET /contacts/:uuid/reminders.

A reminder is a personal to-do, scoped to the token's own user. The due date is stored at midnight — the app offers no hour selection, so a time you send is dropped rather than sorting against the app's.

Campaigns

  • GET /campaigns (filters: type, status), GET /campaigns/:uuid, POST, PATCH, DELETE.
  • POST /campaigns/:uuid/start|pause|resume.
  • GET|PUT /campaigns/:uuid/steps, GET /campaigns/:uuid/contacts, GET /campaigns/:uuid/stats.

Three calls take you from nothing to a running campaign: create a draft pointed at a list, PUT the flow, then start.

The flow is a tree sent in one array. Each step carries an id you choose and points at its parent with parentId; a parent must appear earlier in the array, and exactly one step has no parent. branchKey is "yes" or "no", nothing else: required under a condition, optional under connection_request (yes = the invitation was accepted) and send_message (yes = they answered), refused anywhere else. A flow that cannot work is refused with a 422 naming the problem.

Steps are frozen once a campaign leaves draft — enrolled contacts point at the step they are on. After start, enrollment runs in the background, so the stats stay empty for about a minute.

Deleting a campaign also cancels everything it had queued.

The queue and your account

  • GET /queue (filters: state pending/running/done, method, since), GET /queue/:id. Read-only: it reports what the app scheduled, is running or has finished, failed included.
  • GET|PATCH /account, GET|PATCH /account/settings (daily automation limits, virtual office hours, tone of voice), GET /account/usage.

When nothing seems to happen, these two answer fastest. GET /account/usage puts every daily counter next to its ceiling — a counter at the limit is the usual reason a campaign went quiet. GET /queue shows what failed. The quotas exist so an account looks like a person using LinkedIn, and they apply to API-triggered work exactly as they do to the app.

What the API does not cover

There are no endpoints for conversations and messages: the API can tell you that someone replied, not what they wrote, and it cannot send a one-off message to a single person. Notes, ICP fit as a filter, and the activity feed are not exposed either.

To react to new or changed contacts without polling, use webhooks (see Set up webhooks). To hand the whole surface to an AI assistant instead of writing the calls, see Connect an AI assistant with the MCP server.

¿Te resulto util este articulo?