Timelines, notes and tasks
What happened and what is next: timelines for contacts, companies and deals, notes on them, and tasks in your team’s queues.
Scopes: activity:read to read, activity:write to change.
The timeline entry object
attimestampWhen it happened.
kindstringWhat it was: email, call, linkedin, meeting, stage, task, note, tell, visit, form, change…
channelstring, nullableemail, call, linkedin, sms, web or null.
directionstring, nullableinbound or outbound, where it applies.
titlestring, nullableA line saying what happened.
detailstring, nullableMore, when there is more.
contact_idstring, nullableThe contact it was with, on a company’s or deal’s timeline.
refobject, nullableWhat it points at in Workloom: { type, id }, for example an email or a call.
{
"at": "2026-10-06T14:02:11.000Z",
"kind": "email",
"channel": "email",
"direction": "inbound",
"title": "Re: pricing for 10 seats",
"detail": "classified interested",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"ref": {
"type": "email",
"id": "66ff10c2e4b0a1b2c3d4ee01"
}
}The note object
idstringThe note’s id.
record_typestringWhat it is on. One of contact, company, deal.
record_idstringThe record it is on.
bodystringWhat it says. Markdown.
pinnedbooleanPinned to the top of the record.
author_seat_idstring, nullableWho wrote it. Null when an API key acting for the workspace did.
sourcestring, nullableWhere it was written, for example manual or api.
created_attimestampWhen it was written.
{
"id": "66ff6e74e4b0a1b2c3d4bb01",
"record_type": "contact",
"record_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"body": "Asked for the security pack before the call.",
"pinned": false,
"author_seat_id": null,
"source": "api",
"created_at": "2026-10-07T09:20:00.000Z"
}The task object
idstringThe task’s id.
typestringcallback, follow_up, custom, call, email_task, linkedin… Tasks made over the API are callback, follow_up or custom.
titlestring, nullableWhat to do.
instructionsstring, nullableNotes for whoever does it.
statusstringOpen until done or skipped. One of open, done, skipped.
due_attimestamp, nullableWhen it is due.
contact_idstring, nullableWho it is about.
owner_seat_idstring, nullableWhose queue it is in.
sourcestring, nullableWhat made it: manual, api, weave, campaign…
from_outreachbooleanTrue when a weave or a shuttle step made it. Those are finished in Workloom, where the step’s outcome is chosen.
completed_attimestamp, nullableWhen it was finished.
created_attimestampWhen it was made.
{
"id": "66ff7f85e4b0a1b2c3d4cc01",
"type": "follow_up",
"title": "Send the security pack",
"instructions": null,
"status": "open",
"due_at": "2026-10-08T10:00:00.000Z",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"owner_seat_id": "66e0f1a2e4b0a1b2c3d40a0b",
"source": "api",
"from_outreach": false,
"completed_at": null,
"created_at": "2026-10-07T09:21:00.000Z"
}Endpoints
A contact’s timeline
What happened with a contact, newest first: emails, calls, LinkedIn, meetings, stage moves, finished tasks, website visits, Tells and more.
idstringRequiredThe contact’s id.
limitintegerHow many, 1 to 200. Default 50.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
404not_found.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl "https://api.useworkloom.com/api/public/v1/contacts/66f2a1c0e4b0a1b2c3d4e5f6/timeline?limit=50" \
-H "Authorization: Bearer $WORKLOOM_KEY"const res = await fetch("https://api.useworkloom.com/api/public/v1/contacts/66f2a1c0e4b0a1b2c3d4e5f6/timeline?limit=50", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
}
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.useworkloom.com/api/public/v1/contacts/66f2a1c0e4b0a1b2c3d4e5f6/timeline?limit=50",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json(){
"data": [
{
"at": "2026-10-06T14:02:11.000Z",
"kind": "email",
"channel": "email",
"direction": "inbound",
"title": "Re: pricing for 10 seats",
"detail": "classified interested",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"ref": {
"type": "email",
"id": "66ff10c2e4b0a1b2c3d4ee01"
}
}
],
"unavailable": []
}A company’s timeline
What happened across a company, newest first: its website visits and Tells, and the most active people’s timelines, each entry with its contact_id.
idstringRequiredThe company’s id.
limitintegerHow many, 1 to 200. Default 50.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
404not_found.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl "https://api.useworkloom.com/api/public/v1/companies/66f19b77e4b0a1b2c3d4a1b2/timeline?limit=50" \
-H "Authorization: Bearer $WORKLOOM_KEY"const res = await fetch("https://api.useworkloom.com/api/public/v1/companies/66f19b77e4b0a1b2c3d4a1b2/timeline?limit=50", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
}
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.useworkloom.com/api/public/v1/companies/66f19b77e4b0a1b2c3d4a1b2/timeline?limit=50",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json(){
"data": [
{
"at": "2026-10-06T14:02:11.000Z",
"kind": "email",
"channel": "email",
"direction": "inbound",
"title": "Re: pricing for 10 seats",
"detail": "classified interested",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"ref": {
"type": "email",
"id": "66ff10c2e4b0a1b2c3d4ee01"
}
}
],
"unavailable": []
}A deal’s timeline
A deal’s stage moves, the changes made to it and its notes, newest first.
idstringRequiredThe deal’s id.
limitintegerHow many, 1 to 200. Default 50.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
404not_found.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl "https://api.useworkloom.com/api/public/v1/deals/66f5c3d1e4b0a1b2c3d4c3d4/timeline?limit=50" \
-H "Authorization: Bearer $WORKLOOM_KEY"const res = await fetch("https://api.useworkloom.com/api/public/v1/deals/66f5c3d1e4b0a1b2c3d4c3d4/timeline?limit=50", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
}
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.useworkloom.com/api/public/v1/deals/66f5c3d1e4b0a1b2c3d4c3d4/timeline?limit=50",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json(){
"data": [
{
"at": "2026-10-06T14:02:11.000Z",
"kind": "stage",
"channel": null,
"direction": null,
"title": "discovery → proposal",
"detail": "By user",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"ref": null
}
],
"unavailable": []
}List notes on a record
Notes on one contact, company or deal, newest first.
record_typestringRequiredcontact, company or deal.
record_idstringRequiredThe record.
limitintegerHow many to return, 1 to 100. Default 25.
cursorstringThe next_cursor from the previous page.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl "https://api.useworkloom.com/api/public/v1/notes?record_type=contact&record_id=66f2a1c0e4b0a1b2c3d4e5f6&limit=25" \
-H "Authorization: Bearer $WORKLOOM_KEY"const res = await fetch("https://api.useworkloom.com/api/public/v1/notes?record_type=contact&record_id=66f2a1c0e4b0a1b2c3d4e5f6&limit=25", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
}
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.useworkloom.com/api/public/v1/notes?record_type=contact&record_id=66f2a1c0e4b0a1b2c3d4e5f6&limit=25",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json(){
"data": [
{
"id": "66ff6e74e4b0a1b2c3d4bb01",
"record_type": "contact",
"record_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"body": "Asked for the security pack before the call.",
"pinned": false,
"author_seat_id": null,
"source": "api",
"created_at": "2026-10-07T09:20:00.000Z"
}
],
"has_more": true,
"next_cursor": "66ff6e74e4b0a1b2c3d4bb01"
}Add a note
Adds a note to a contact, company or deal the key may edit. It shows on the record and its timeline, named as written by the API key.
Idempotency-KeystringAny unique string, up to 255 characters. Send the same key when you retry and the request runs once; the first answer comes back with Idempotent-Replayed: true. Kept 24 hours.
record_typestringRequiredWhat it goes on.
record_idstringRequiredThe record.
bodystringRequiredWhat it says. Markdown, up to 20,000 characters.
pinnedbooleanPin it to the top of the record.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
409duplicate, conflict or idempotency_key_in_use.
422idempotency_key_reused.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl -X POST "https://api.useworkloom.com/api/public/v1/notes" \
-H "Authorization: Bearer $WORKLOOM_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"record_type": "contact",
"record_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"body": "Asked for the security pack before the call."
}'const res = await fetch("https://api.useworkloom.com/api/public/v1/notes", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
"record_type": "contact",
"record_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"body": "Asked for the security pack before the call."
})
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://api.useworkloom.com/api/public/v1/notes",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"record_type": "contact",
"record_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"body": "Asked for the security pack before the call."
},
)
data = res.json(){
"data": {
"id": "66ff6e74e4b0a1b2c3d4bb01",
"record_type": "contact",
"record_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"body": "Asked for the security pack before the call.",
"pinned": false,
"author_seat_id": null,
"source": "api",
"created_at": "2026-10-07T09:20:00.000Z"
},
"livemode": true
}List tasks
Tasks in the queues the key reaches, oldest first.
statusstringopen (default), done, skipped or all.
contact_idstringOnly tasks about this contact.
owner_seat_idstringOnly tasks in this teammate’s queue.
due_beforetimestampOnly tasks due before this time (ISO 8601).
limitintegerHow many to return, 1 to 100. Default 25.
cursorstringThe next_cursor from the previous page.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl "https://api.useworkloom.com/api/public/v1/tasks?status=open&owner_seat_id=66e0f1a2e4b0a1b2c3d40a0b&limit=25" \
-H "Authorization: Bearer $WORKLOOM_KEY"const res = await fetch("https://api.useworkloom.com/api/public/v1/tasks?status=open&owner_seat_id=66e0f1a2e4b0a1b2c3d40a0b&limit=25", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
}
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.useworkloom.com/api/public/v1/tasks?status=open&owner_seat_id=66e0f1a2e4b0a1b2c3d40a0b&limit=25",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json(){
"data": [
{
"id": "66ff7f85e4b0a1b2c3d4cc01",
"type": "follow_up",
"title": "Send the security pack",
"instructions": null,
"status": "open",
"due_at": "2026-10-08T10:00:00.000Z",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"owner_seat_id": "66e0f1a2e4b0a1b2c3d40a0b",
"source": "api",
"from_outreach": false,
"completed_at": null,
"created_at": "2026-10-07T09:21:00.000Z"
}
],
"has_more": true,
"next_cursor": "66ff7f85e4b0a1b2c3d4cc01"
}Add a task
Puts a callback, follow-up or task of your own into someone’s queue: the owner you name, else the contact’s owner, else the person the key acts for.
Idempotency-KeystringAny unique string, up to 255 characters. Send the same key when you retry and the request runs once; the first answer comes back with Idempotent-Replayed: true. Kept 24 hours.
typestringRequiredcallback: call them back. follow_up: get back to them. custom: anything else.
titlestringRequiredWhat to do.
instructionsstring, nullableNotes for whoever does it.
contact_idstring, nullableWho it is about.
due_attimestamp, nullableWhen it is due. Defaults to now.
owner_seat_idstring, nullableWhose queue it goes in. Defaults to the contact’s owner, then the person the key acts for.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
409duplicate, conflict or idempotency_key_in_use.
422idempotency_key_reused.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl -X POST "https://api.useworkloom.com/api/public/v1/tasks" \
-H "Authorization: Bearer $WORKLOOM_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"type": "follow_up",
"title": "Send the security pack",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"due_at": "2026-10-08T10:00:00Z"
}'const res = await fetch("https://api.useworkloom.com/api/public/v1/tasks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
"type": "follow_up",
"title": "Send the security pack",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"due_at": "2026-10-08T10:00:00Z"
})
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://api.useworkloom.com/api/public/v1/tasks",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"type": "follow_up",
"title": "Send the security pack",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"due_at": "2026-10-08T10:00:00Z"
},
)
data = res.json(){
"data": {
"id": "66ff7f85e4b0a1b2c3d4cc01",
"type": "follow_up",
"title": "Send the security pack",
"instructions": null,
"status": "open",
"due_at": "2026-10-08T10:00:00.000Z",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"owner_seat_id": "66e0f1a2e4b0a1b2c3d40a0b",
"source": "api",
"from_outreach": false,
"completed_at": null,
"created_at": "2026-10-07T09:21:00.000Z"
},
"livemode": true
}Get a task
idstringRequiredThe task’s id.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
404not_found.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl "https://api.useworkloom.com/api/public/v1/tasks/66ff7f85e4b0a1b2c3d4cc01" \
-H "Authorization: Bearer $WORKLOOM_KEY"const res = await fetch("https://api.useworkloom.com/api/public/v1/tasks/66ff7f85e4b0a1b2c3d4cc01", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
}
});
const data = await res.json();import os, requests
res = requests.get(
"https://api.useworkloom.com/api/public/v1/tasks/66ff7f85e4b0a1b2c3d4cc01",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json(){
"data": {
"id": "66ff7f85e4b0a1b2c3d4cc01",
"type": "follow_up",
"title": "Send the security pack",
"instructions": null,
"status": "open",
"due_at": "2026-10-08T10:00:00.000Z",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"owner_seat_id": "66e0f1a2e4b0a1b2c3d40a0b",
"source": "api",
"from_outreach": false,
"completed_at": null,
"created_at": "2026-10-07T09:21:00.000Z"
}
}Finish or reschedule a task
Marks a task done or skipped, reopens it, or moves its due time. A step of a weave or a shuttle (from_outreach: true) is finished in Workloom, where its outcome is chosen, and answers conflict here.
idstringRequiredThe task’s id.
statusstringdone or skipped finishes it; open reopens it.
due_attimestamp, nullableA new due time.
400invalid_request, unknown_fields, reason_required or unsupported_version.
401authentication_required or invalid_key.
403missing_scope, forbidden, seat_inactive or organisation_inactive.
404not_found.
409duplicate, conflict or idempotency_key_in_use.
429rate_limited. Wait Retry-After seconds.
500internal_error.
curl -X PATCH "https://api.useworkloom.com/api/public/v1/tasks/66ff7f85e4b0a1b2c3d4cc01" \
-H "Authorization: Bearer $WORKLOOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "done"
}'const res = await fetch("https://api.useworkloom.com/api/public/v1/tasks/66ff7f85e4b0a1b2c3d4cc01", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"status": "done"
})
});
const data = await res.json();import os, requests
res = requests.patch(
"https://api.useworkloom.com/api/public/v1/tasks/66ff7f85e4b0a1b2c3d4cc01",
headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
json={
"status": "done"
},
)
data = res.json(){
"data": {
"id": "66ff7f85e4b0a1b2c3d4cc01",
"type": "follow_up",
"title": "Send the security pack",
"instructions": null,
"status": "open",
"due_at": "2026-10-08T10:00:00.000Z",
"contact_id": "66f2a1c0e4b0a1b2c3d4e5f6",
"owner_seat_id": "66e0f1a2e4b0a1b2c3d40a0b",
"source": "api",
"from_outreach": false,
"completed_at": null,
"created_at": "2026-10-07T09:21:00.000Z"
},
"livemode": true
}