Pipeline CRM API
Manage your sales pipeline stages, contacts, and notes. Move contacts between stages and track your pipeline activity.
Stages
List Stages
/api/pipeline/stagesList 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.
curl --location --request GET 'https://outreach.weezly.com/api/pipeline/stages' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"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
/api/pipeline/stagesCreate 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
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Stage name (unique per user) |
color | string | Hex color code (default: #3B82F6) |
emoji | string | Emoji for the stage (default: 📌) |
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": "🤝"
}'{
"stage": {
"id": "ps_006",
"name": "Negotiation",
"color": "#F59E0B",
"emoji": "🤝",
"position": 5,
"userId": "user_123",
"createdAt": "2026-08-18T10:00:00.000Z"
}
}Response Codes
| 200 | Stage created |
| 400 | Name is required |
| 500 | Creation failed (including a duplicate stage name) |
Update Stage
/api/pipeline/stages/:idUpdate a pipeline stage's name, color, or emoji. Position cannot be changed here; use the reorder endpoint instead.
Request Body
| Parameter | Type | Description |
|---|---|---|
name | string | Stage name |
color | string | Hex color code |
emoji | string | Stage emoji |
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"
}'{ "ok": true }Response Codes
| 200 | Stage updated |
| 404 | Stage not found |
Delete Stage
/api/pipeline/stages/:idDelete a pipeline stage. Contacts in this stage are removed from the pipeline; their conversations and notes are not affected.
curl --location --request DELETE 'https://outreach.weezly.com/api/pipeline/stages/:id' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{ "ok": true }Response Codes
| 200 | Stage deleted |
| 404 | Stage not found |
Reorder Stages
/api/pipeline/stages/reorderReorder all stages by providing an ordered array of stage IDs. Each stage's position is set to its index in the array.
Request Body
| Parameter | Type | Description |
|---|---|---|
stageIdsrequired | string[] | Ordered array of stage IDs |
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"
]
}'{ "ok": true }Response Codes
| 200 | Stages reordered |
| 400 | stageIds array required |
Contacts
List Contacts
/api/pipeline/contactsList all contacts in the pipeline with their stage. Returns every pipeline contact for the authenticated user; there are no query filters on this endpoint.
curl --location --request GET 'https://outreach.weezly.com/api/pipeline/contacts' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"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
/api/pipeline/contactsAdd 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
| Parameter | Type | Description |
|---|---|---|
providerContactIdrequired | string | Contact identifier from the inbox |
stageIdrequired | string | Pipeline stage to place the contact in |
accountIdrequired | string | ID of the LinkedIn account (sender) this contact belongs to |
contactName | string | Contact display name |
contactPhotoUrl | string | Contact avatar URL |
chatId | string | Chat ID for the conversation |
lastMessagePreview | string | Preview text of the latest message |
lastMessageAt | string | ISO timestamp of the latest message |
lastMessageIsSender | boolean | Whether the latest message was sent by you |
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"
}'{
"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
| 200 | Contact created or updated |
| 400 | providerContactId, stageId, and accountId are required |
Update Contact
/api/pipeline/contacts/:idMove 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
| Parameter | Type | Description |
|---|---|---|
stageId | string | Target stage ID |
lastMessagePreview | string | Preview text of the latest message |
lastMessageAt | string | ISO timestamp of the latest message |
lastMessageIsSender | boolean | Whether the latest message was sent by you |
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"
}'{ "ok": true }Response Codes
| 200 | Contact updated |
| 404 | Contact not found |
Remove Contact
/api/pipeline/contacts/:idRemove a contact from the pipeline entirely. The underlying conversation and any notes are not affected.
curl --location --request DELETE 'https://outreach.weezly.com/api/pipeline/contacts/:id' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{ "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
/api/pipeline/notesList notes for a specific contact, newest first.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
providerIdrequired | string | The contact's provider contact ID |
curl --location --request GET 'https://outreach.weezly.com/api/pipeline/notes?providerId=contact_abc123' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"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
| 200 | Notes for the contact |
| 400 | providerId query parameter required |
Create Note
/api/pipeline/notesAdd a note to a contact.
Request Body
| Parameter | Type | Description |
|---|---|---|
providerContactIdrequired | string | The contact's provider contact ID |
contentrequired | string | Note text (leading/trailing whitespace is trimmed) |
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"
}'{
"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
| 200 | Note created |
| 400 | providerContactId and content required |
Update Note
/api/pipeline/notesUpdate a note's content. The note ID goes in the request body, not the URL.
Request Body
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Note ID |
contentrequired | string | Updated note text |
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"
}'{
"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
| 200 | Note updated |
| 400 | id and content required |
| 404 | Note not found |
Delete Note
/api/pipeline/notesDelete a note. The note ID goes in the id query parameter.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Note ID |
curl --location --request DELETE 'https://outreach.weezly.com/api/pipeline/notes?id=cn_003' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{ "ok": true }Response Codes
| 200 | Note deleted (also returned if the note did not exist) |
| 400 | id query parameter required |