Weezly Outreach
|Developer Docs

Pipeline CRM API

Manage your sales pipeline stages, contacts, and notes. Move contacts between stages and track your pipeline activity.

Stages

List Stages

GET/api/pipeline/stages

List all pipeline stages for the authenticated user, ordered by position. If you have no stages yet, the five default stages are created automatically on the first call.

Request — cURLcURL
curl --location --request GET 'https://outreach.weezly.com/api/pipeline/stages' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY'
Response (200 OK)JSON
{
  "stages": [
    { "id": "ps_001", "name": "Interested", "color": "#3B82F6", "emoji": "🔥", "position": 0 },
    { "id": "ps_002", "name": "Meeting Booked", "color": "#8B5CF6", "emoji": "📅", "position": 1 },
    { "id": "ps_003", "name": "Demo", "color": "#F59E0B", "emoji": "🎯", "position": 2 },
    { "id": "ps_004", "name": "Won Deal", "color": "#10B981", "emoji": "🏆", "position": 3 },
    { "id": "ps_005", "name": "Lost Deal", "color": "#EF4444", "emoji": "💀", "position": 4 }
  ]
}

Create Stage

POST/api/pipeline/stages

Create a new pipeline stage. The stage is always appended to the end of the board (position is assigned automatically); use the reorder endpoint to change the order. Stage names must be unique per user.

Request Body

ParameterTypeDescription
namerequiredstringStage name (unique per user)
colorstringHex color code (default: #3B82F6)
emojistringEmoji for the stage (default: 📌)
Request — cURLcURL
curl --location --request POST 'https://outreach.weezly.com/api/pipeline/stages' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Negotiation",
  "color": "#F59E0B",
  "emoji": "🤝"
}'
Response (200 OK)JSON
{
  "stage": {
    "id": "ps_006",
    "name": "Negotiation",
    "color": "#F59E0B",
    "emoji": "🤝",
    "position": 5,
    "userId": "user_123",
    "createdAt": "2026-08-18T10:00:00.000Z"
  }
}

Response Codes

200Stage created
400Name is required
500Creation failed (including a duplicate stage name)

Update Stage

PATCH/api/pipeline/stages/:id

Update a pipeline stage's name, color, or emoji. Position cannot be changed here; use the reorder endpoint instead.

Request Body

ParameterTypeDescription
namestringStage name
colorstringHex color code
emojistringStage emoji
Request — cURLcURL
curl --location --request PATCH 'https://outreach.weezly.com/api/pipeline/stages/:id' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Final Negotiation"
}'
Response (200 OK)JSON
{ "ok": true }

Response Codes

200Stage updated
404Stage not found

Delete Stage

DELETE/api/pipeline/stages/:id

Delete a pipeline stage. Contacts in this stage are removed from the pipeline; their conversations and notes are not affected.

Request — cURLcURL
curl --location --request DELETE 'https://outreach.weezly.com/api/pipeline/stages/:id' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY'
Response (200 OK)JSON
{ "ok": true }

Response Codes

200Stage deleted
404Stage not found

Reorder Stages

PUT/api/pipeline/stages/reorder

Reorder all stages by providing an ordered array of stage IDs. Each stage's position is set to its index in the array.

Request Body

ParameterTypeDescription
stageIdsrequiredstring[]Ordered array of stage IDs
Request — cURLcURL
curl --location --request PUT 'https://outreach.weezly.com/api/pipeline/stages/reorder' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "stageIds": [
    "ps_004",
    "ps_001",
    "ps_002",
    "ps_003",
    "ps_005"
  ]
}'
Response (200 OK)JSON
{ "ok": true }

Response Codes

200Stages reordered
400stageIds array required

Contacts

List Contacts

GET/api/pipeline/contacts

List all contacts in the pipeline with their stage. Returns every pipeline contact for the authenticated user; there are no query filters on this endpoint.

Request — cURLcURL
curl --location --request GET 'https://outreach.weezly.com/api/pipeline/contacts' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY'
Response (200 OK)JSON
{
  "contacts": [
    {
      "id": "pc_001",
      "providerContactId": "contact_abc123",
      "contactName": "Sarah Chen",
      "contactPhotoUrl": "https://media.licdn.com/...",
      "accountId": "cm3acc123mno",
      "chatId": "chat_xyz789",
      "stageId": "ps_001",
      "stage": { "id": "ps_001", "name": "Interested", "color": "#3B82F6", "emoji": "🔥", "position": 0 },
      "lastMessagePreview": "Thanks for connecting! I'd love to...",
      "lastMessageAt": "2026-08-15T14:30:00.000Z",
      "lastMessageIsSender": false,
      "createdAt": "2026-08-13T08:00:00.000Z"
    }
  ]
}

Add or Update Contact

POST/api/pipeline/contacts

Add a contact to the pipeline, or update it if it is already there. This is an upsert keyed by providerContactId: posting an existing contact moves it to the given stage and account and updates any other fields you send, so it never fails with a duplicate error.

Request Body

ParameterTypeDescription
providerContactIdrequiredstringContact identifier from the inbox
stageIdrequiredstringPipeline stage to place the contact in
accountIdrequiredstringID of the LinkedIn account (sender) this contact belongs to
contactNamestringContact display name
contactPhotoUrlstringContact avatar URL
chatIdstringChat ID for the conversation
lastMessagePreviewstringPreview text of the latest message
lastMessageAtstringISO timestamp of the latest message
lastMessageIsSenderbooleanWhether the latest message was sent by you
Request — cURLcURL
curl --location --request POST 'https://outreach.weezly.com/api/pipeline/contacts' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "providerContactId": "contact_def456",
  "stageId": "ps_001",
  "accountId": "cm3acc123mno",
  "contactName": "Marcus Johnson"
}'
Response (200 OK)JSON
{
  "contact": {
    "id": "pc_new002",
    "providerContactId": "contact_def456",
    "contactName": "Marcus Johnson",
    "accountId": "cm3acc123mno",
    "stageId": "ps_001",
    "stage": { "id": "ps_001", "name": "Interested", "emoji": "🔥" },
    "createdAt": "2026-08-18T10:00:00.000Z"
  }
}

Response Codes

200Contact created or updated
400providerContactId, stageId, and accountId are required

Update Contact

PATCH/api/pipeline/contacts/:id

Move a contact to a different pipeline stage and/or update its last-message fields. To remove a contact from the pipeline entirely, use the DELETE endpoint (stageId cannot be set to null).

Request Body

ParameterTypeDescription
stageIdstringTarget stage ID
lastMessagePreviewstringPreview text of the latest message
lastMessageAtstringISO timestamp of the latest message
lastMessageIsSenderbooleanWhether the latest message was sent by you
Request — cURLcURL
curl --location --request PATCH 'https://outreach.weezly.com/api/pipeline/contacts/:id' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "stageId": "ps_002"
}'
Response (200 OK)JSON
{ "ok": true }

Response Codes

200Contact updated
404Contact not found

Remove Contact

DELETE/api/pipeline/contacts/:id

Remove a contact from the pipeline entirely. The underlying conversation and any notes are not affected.

Request — cURLcURL
curl --location --request DELETE 'https://outreach.weezly.com/api/pipeline/contacts/:id' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY'
Response (200 OK)JSON
{ "ok": true }

Contact Notes

Notes are attached to a contact by its provider contact ID (the same identifier used by pipeline contacts), not by the pipeline contact record. All four operations live on the single /api/pipeline/notes path. Note the naming quirk: the list endpoint takes the contact identifier as a providerId query parameter, while the create endpoint takes it as providerContactId in the body. Both refer to the same value.

List Notes

GET/api/pipeline/notes

List notes for a specific contact, newest first.

Query Parameters

ParameterTypeDescription
providerIdrequiredstringThe contact's provider contact ID
Request — cURLcURL
curl --location --request GET 'https://outreach.weezly.com/api/pipeline/notes?providerId=contact_abc123' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY'
Response (200 OK)JSON
{
  "notes": [
    {
      "id": "cn_002",
      "providerContactId": "contact_abc123",
      "content": "Follow up after September 1st (on vacation until then)",
      "createdAt": "2026-08-16T09:00:00.000Z",
      "updatedAt": "2026-08-16T09:00:00.000Z"
    },
    {
      "id": "cn_001",
      "providerContactId": "contact_abc123",
      "content": "Interested in demo next week. Decision maker for their team of 15.",
      "createdAt": "2026-08-15T15:00:00.000Z",
      "updatedAt": "2026-08-15T15:00:00.000Z"
    }
  ]
}

Response Codes

200Notes for the contact
400providerId query parameter required

Create Note

POST/api/pipeline/notes

Add a note to a contact.

Request Body

ParameterTypeDescription
providerContactIdrequiredstringThe contact's provider contact ID
contentrequiredstringNote text (leading/trailing whitespace is trimmed)
Request — cURLcURL
curl --location --request POST 'https://outreach.weezly.com/api/pipeline/notes' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "providerContactId": "contact_abc123",
  "content": "Had a great call, sending proposal tomorrow"
}'
Response (200 OK)JSON
{
  "note": {
    "id": "cn_003",
    "providerContactId": "contact_abc123",
    "content": "Had a great call, sending proposal tomorrow",
    "createdAt": "2026-08-18T10:00:00.000Z",
    "updatedAt": "2026-08-18T10:00:00.000Z"
  }
}

Response Codes

200Note created
400providerContactId and content required

Update Note

PATCH/api/pipeline/notes

Update a note's content. The note ID goes in the request body, not the URL.

Request Body

ParameterTypeDescription
idrequiredstringNote ID
contentrequiredstringUpdated note text
Request — cURLcURL
curl --location --request PATCH 'https://outreach.weezly.com/api/pipeline/notes' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "id": "cn_003",
  "content": "Updated note content"
}'
Response (200 OK)JSON
{
  "note": { "id": "cn_003", "providerContactId": "contact_abc123", "content": "Updated note content", "createdAt": "2026-08-18T10:00:00.000Z", "updatedAt": "2026-08-18T10:05:00.000Z" }
}

Response Codes

200Note updated
400id and content required
404Note not found

Delete Note

DELETE/api/pipeline/notes

Delete a note. The note ID goes in the id query parameter.

Query Parameters

ParameterTypeDescription
idrequiredstringNote ID
Request — cURLcURL
curl --location --request DELETE 'https://outreach.weezly.com/api/pipeline/notes?id=cn_003' \
  --header 'X-API-KEY: sk_live_YOUR_API_KEY'
Response (200 OK)JSON
{ "ok": true }

Response Codes

200Note deleted (also returned if the note did not exist)
400id query parameter required