Zudo API
External API for accessing and creating data in your Zudo workspace programmatically.
Getting Started
Base URL
All API requests should be made to:
https://zudo.so/api/v1
Authentication
Every request must include your API key in the
Keys start with
Example:
x-api-key header.Keys start with
psk_ and can be generated from your Settings → API Key page.Example:
x-api-key: psk_your_key_here
Rate Limits
Requests are rate-limited per API key using a 1-minute sliding window (default: 100 requests/min).
Rate limit status is returned in response headers:
Rate limit status is returned in response headers:
X-RateLimit-Limit— your per-minute quotaX-RateLimit-Remaining— requests remaining in the current windowX-RateLimit-Reset— seconds until the window resets
429 Too Many Requests.
Pagination
All list endpoints return paginated results. Use
Responses include a
page and pageSize query parameters to navigate.pageSize defaults to 25 and the maximum is 100. Requesting a page beyond totalPages returns an empty data array.Responses include a
pagination object:
{
"page": 1,
"pageSize": 25,
"total": 142,
"totalPages": 6,
"hasNextPage": true,
"hasPrevPage": false
}
Errors
Errors return a JSON body with an
Common status codes:
error string field.Common status codes:
400— Validation error:{ "error": "title is required" }401— Unauthorized:{ "error": "Invalid API key" }403— Forbidden:{ "error": "Forbidden" }404— Not found:{ "error": "Account not found" }405— Method not allowed:{ "error": "Method not allowed" }429— Rate limited:{ "error": "Rate limit exceeded" }500— Server error:{ "error": "Internal server error" }
Supported Methods
The API supports
Other
For any other updates or deletes, use the Zudo web application.
GET (read), POST (create), and PATCH for /accounts/{accountId} and /contacts/{contactId} activity updates.Other
PUT, PATCH, and DELETE requests will return 405 Method Not Allowed.For any other updates or deletes, use the Zudo web application.
Timestamps
All timestamps are returned in ISO 8601 format with UTC timezone:
Timestamps you send in request bodies (e.g.
2025-01-15T12:00:00.000ZTimestamps you send in request bodies (e.g.
dueAt, startAt) should also be ISO 8601 unless otherwise noted. contactActivityAt and lastSeenAt also accept Unix timestamps in seconds or milliseconds. The API normalizes dueAt to noon UTC on the given date.
Enums & Status Values
Task status:
Task priority:
Request status:
Account status (filter):
Issue state: synced from your issue tracker (e.g.
OPEN IN_PROGRESS DONE CANCELLEDTask priority:
LOW MEDIUM HIGH URGENTRequest status:
Open DoneAccount status (filter):
active onboarding churned inactiveIssue state: synced from your issue tracker (e.g.
Backlog, In Progress, Done)
Filtering & Sorting
List endpoints accept query parameters for filtering and sorting. Filters are combined with AND logic.
- Accounts:
search(partial name match),status,sortBy,sortOrder - Requests:
search,status,minSeverity/maxSeverity,accountId,sortBy,sortOrder - Tasks:
search,status,priority,sortBy,sortOrder - Meetings:
search,accountId,sortBy,sortOrder - Issues:
search,state,sortBy,sortOrder
Relationships
Resources are connected through many-to-many relationships:
- Accounts have contacts, meetings, and requests
- Requests link to accounts and issues
- Tasks link to accounts, issues, requests, and meetings
- Issues link to requests (and accounts are deduced from those requests)
Idempotency
POST endpoints are not idempotent — repeated identical requests will create duplicate resources.
The API does not currently support an
The API does not currently support an
Idempotency-Key header. Ensure your integration guards against retries that could create duplicates.
Versioning
The current API version is v1, embedded in the URL path (
Non-breaking changes (new fields, new endpoints) may be added without a version bump. Breaking changes will be released under a new version prefix with advance notice.
/api/v1/).Non-breaking changes (new fields, new endpoints) may be added without a version bump. Breaking changes will be released under a new version prefix with advance notice.
Import into API Tools
The full OpenAPI 3.0 specification is available as JSON:
Postman: File → Import → paste the URL above or upload the downloaded JSON file.
Insomnia: Application → Import/Export → Import Data → From URL or File.
HTTPie: Import the spec from the URL or file to generate a collection.
You can also use the download link in the header to save the file directly.
Postman: File → Import → paste the URL above or upload the downloaded JSON file.
Insomnia: Application → Import/Export → Import Data → From URL or File.
HTTPie: Import the spec from the URL or file to generate a collection.
You can also use the download link in the header to save the file directly.
Webhooks
Webhook support is coming soon. You will be able to subscribe to events like account creation, request status changes, and task updates.
In the meantime, use polling against list endpoints with
In the meantime, use polling against list endpoints with
sortBy=updatedAt&sortOrder=desc to detect recent changes.
Accounts
Customer accounts
GET
List accounts
/accounts
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
externalId
string
optional
query
status
string
optional
query
sortBy
string
optional
query
sortOrder
string
optional
query
Responses
200Paginated list of accounts
401Unauthorized
curl https://zudo.so/api/v1/accounts \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/accounts", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/accounts",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"name": "Pied Piper",
"externalId": "piedpiper",
"mrr": 48000,
"active": true,
"churned": false,
"onboarding": false,
"logoUrl": null,
"createdAt": "2024-03-15T08:00:00.000Z",
"updatedAt": "2025-01-10T14:22:00.000Z"
},
{
"id": 2,
"name": "Hooli",
"externalId": "hooli",
"mrr": 250000,
"active": true,
"churned": false,
"onboarding": false,
"logoUrl": null,
"createdAt": "2024-01-08T10:30:00.000Z",
"updatedAt": "2025-01-12T09:15:00.000Z"
},
{
"id": 3,
"name": "Raviga Capital",
"externalId": "raviga",
"mrr": 12000,
"active": true,
"churned": false,
"onboarding": false,
"logoUrl": null,
"createdAt": "2024-06-20T16:00:00.000Z",
"updatedAt": "2025-01-05T11:30:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 3,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
POST
Create account
/accounts
Request Body
name
string
required
body
externalId
string | null
optional
body
mrr
number | null
optional
body
status
string
optional
body
contactName
string | null
optional
body
contactEmail
string | null
optional
body
Responses
201Account created
400Validation error
curl -X POST https://zudo.so/api/v1/accounts \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Bachmanity Insanity",
"externalId": "bachmanity",
"mrr": 15000,
"status": "active",
"contactName": "Erlich Bachman",
"contactEmail": "[email protected]"
}'
const res = await fetch("https://zudo.so/api/v1/accounts", {
method: "POST",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"name": "Bachmanity Insanity",
"externalId": "bachmanity",
"mrr": 15000,
"status": "active",
"contactName": "Erlich Bachman",
"contactEmail": "[email protected]"
})
});
const data = await res.json();
import requests
res = requests.post("https://zudo.so/api/v1/accounts",
headers={"x-api-key": "psk_your_key_here"},
json={
"name": "Bachmanity Insanity",
"externalId": "bachmanity",
"mrr": 15000,
"status": "active",
"contactName": "Erlich Bachman",
"contactEmail": "[email protected]"
})
data = res.json()
Response
{
"data": {
"id": 4,
"name": "Bachmanity Insanity",
"externalId": "bachmanity",
"mrr": 15000,
"active": true,
"churned": false,
"onboarding": false,
"logoUrl": null,
"createdAt": "2025-01-15T12:00:00.000Z",
"updatedAt": "2025-01-15T12:00:00.000Z"
}
}
GET
Get account by ID
/accounts/{accountId}
Path Parameters
accountId
integer
required
path
Responses
200Account details with contacts, recent meetings, and linked requests
404Account not found
curl https://zudo.so/api/v1/accounts/1 \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/accounts/1", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/accounts/1",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": {
"id": 1,
"name": "Pied Piper",
"externalId": "piedpiper",
"mrr": 48000,
"active": true,
"churned": false,
"onboarding": false,
"logoUrl": null,
"createdAt": "2024-03-15T08:00:00.000Z",
"updatedAt": "2025-01-10T14:22:00.000Z",
"contacts": [
{
"id": 1,
"name": "Richard Hendricks",
"email": "[email protected]"
},
{
"id": 4,
"name": "Dinesh Chugtai",
"email": "[email protected]"
}
],
"meetings": [
{
"id": 1,
"title": "Pied Piper Q1 Business Review",
"startAt": "2025-01-20T17:00:00.000Z",
"endAt": "2025-01-20T18:00:00.000Z"
}
],
"requests": [
{
"id": 1,
"title": "Middle-out compression API endpoint",
"status": "Open",
"severity": 4,
"requestedAt": "2024-11-02T09:00:00.000Z"
}
]
}
}
PATCH
Update account
/accounts/{accountId}
Path Parameters
accountId
integer
required
path
Request Body
externalId
string | null
optional
body
contactActivityAt
string | integer | null
optional
body
Responses
200Updated account
400Invalid input
404Account not found
curl -X PATCH https://zudo.so/api/v1/accounts/1 \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"externalId": "piedpiper",
"contactActivityAt": 1744113600
}'
const res = await fetch("https://zudo.so/api/v1/accounts/1", {
method: "PATCH",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"externalId": "piedpiper",
"contactActivityAt": 1744113600
})
});
const data = await res.json();
import requests
res = requests.patch("https://zudo.so/api/v1/accounts/1",
headers={"x-api-key": "psk_your_key_here"},
json={
"externalId": "piedpiper",
"contactActivityAt": 1744113600
})
data = res.json()
Response
{
"data": {
"id": 1,
"name": "Pied Piper",
"externalId": "piedpiper",
"mrr": 48000,
"active": true,
"churned": false,
"onboarding": false,
"contactActivityAt": "2025-04-08T12:00:00.000Z",
"createdAt": "2024-03-15T08:00:00.000Z",
"updatedAt": "2025-04-08T12:00:00.000Z"
}
}
Requests
Customer requests / feature requests
GET
List requests
/requests
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
status
string
optional
query
minSeverity
integer
optional
query
maxSeverity
integer
optional
query
sortBy
string
optional
query
sortOrder
string
optional
query
Responses
200Paginated list of requests
curl https://zudo.so/api/v1/requests \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/requests", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/requests",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"title": "Middle-out compression API endpoint",
"description": "Need a public API to expose the middle-out compression algorithm for third-party integrations.",
"status": "Open",
"severity": 4,
"requestedAt": "2024-11-02T09:00:00.000Z",
"createdAt": "2024-11-02T09:00:00.000Z",
"updatedAt": "2025-01-08T16:45:00.000Z",
"accounts": [
{
"id": 1,
"name": "Pied Piper"
}
],
"issues": [
{
"id": 10,
"identifier": "ENG-142",
"title": "Implement compression API",
"state": "In Progress"
}
]
},
{
"id": 2,
"title": "Nucleus platform SSO integration",
"description": "Hooli Nucleus team needs SAML SSO support for enterprise rollout.",
"status": "Open",
"severity": 3,
"requestedAt": "2024-12-10T14:00:00.000Z",
"createdAt": "2024-12-10T14:00:00.000Z",
"updatedAt": "2025-01-11T10:00:00.000Z",
"accounts": [
{
"id": 2,
"name": "Hooli"
}
],
"issues": []
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 2,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
POST
Create request
/requests
Request Body
title
string
required
body
notes
string | null
optional
body
severity
integer
optional
body
requestedAt
string
optional
body
accountIds
integer[]
optional
body
issueIds
integer[]
optional
body
Responses
201Request created
400Validation error
curl -X POST https://zudo.so/api/v1/requests \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Weissman score dashboard widget",
"notes": "Gavin wants a real-time Weissman score displayed on the Hooli dashboard.",
"severity": 3,
"accountIds": [2]
}'
const res = await fetch("https://zudo.so/api/v1/requests", {
method: "POST",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"title": "Weissman score dashboard widget",
"notes": "Gavin wants a real-time Weissman score displayed on the Hooli dashboard.",
"severity": 3,
"accountIds": [2]
})
});
const data = await res.json();
import requests
res = requests.post("https://zudo.so/api/v1/requests",
headers={"x-api-key": "psk_your_key_here"},
json={
"title": "Weissman score dashboard widget",
"notes": "Gavin wants a real-time Weissman score displayed on the Hooli dashboard.",
"severity": 3,
"accountIds": [2]
})
data = res.json()
Response
{
"data": {
"id": 3,
"title": "Weissman score dashboard widget",
"description": null,
"status": "Open",
"severity": 3,
"requestedAt": "2025-01-15T12:00:00.000Z",
"createdAt": "2025-01-15T12:00:00.000Z",
"updatedAt": "2025-01-15T12:00:00.000Z",
"accounts": [
{
"id": 2,
"name": "Hooli"
}
],
"issues": []
}
}
GET
Get request by ID
/requests/{requestId}
Path Parameters
requestId
integer
required
path
Responses
200Request details with linked accounts and issues
404Request not found
curl https://zudo.so/api/v1/requests/1 \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/requests/1", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/requests/1",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": {
"id": 1,
"title": "Middle-out compression API endpoint",
"description": "Need a public API to expose the middle-out compression algorithm for third-party integrations.",
"status": "Open",
"severity": 4,
"requestedAt": "2024-11-02T09:00:00.000Z",
"createdAt": "2024-11-02T09:00:00.000Z",
"updatedAt": "2025-01-08T16:45:00.000Z",
"accounts": [
{
"id": 1,
"name": "Pied Piper"
}
],
"issues": [
{
"id": 10,
"identifier": "ENG-142",
"title": "Implement compression API",
"state": "In Progress"
}
]
}
}
GET
Find accounts likely interested in this request
/requests/{requestId}/similar-accounts
Path Parameters
requestId
integer
required
path
Query Parameters
limit
integer
optional
query
Responses
200Ranked similar accounts with reasoning.
400Request has no linked accounts yet.
403AI features are disabled for this organization.
404Request not found.
Meetings
Meeting records and transcripts
GET
List meetings
/meetings
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
from
string
optional
query
to
string
optional
query
sortOrder
string
optional
query
Responses
200Paginated list of meetings
curl https://zudo.so/api/v1/meetings?search=compression \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/meetings?search=compression", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/meetings?search=compression",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"title": "Pied Piper Q1 Business Review",
"startAt": "2025-01-20T17:00:00.000Z",
"endAt": "2025-01-20T18:00:00.000Z",
"overview": "Discussed platform adoption metrics and the new decentralized internet initiative.",
"topicsDiscussed": "Compression benchmarks, new internet architecture, Series C timeline",
"transcriptMatch": "…Richard: our compression scores are still ahead of Hooli but the gap is narrowing. We need to ship the new encoder before…",
"account": {
"id": 1,
"name": "Pied Piper"
}
},
{
"id": 2,
"title": "Hooli-XYZ Partnership Sync",
"startAt": "2025-01-18T15:00:00.000Z",
"endAt": "2025-01-18T15:45:00.000Z",
"overview": "Gavin Belson's team wants to explore a deeper integration with the Nucleus platform.",
"topicsDiscussed": "API limits, data residency, Nucleus roadmap",
"transcriptMatch": null,
"account": {
"id": 2,
"name": "Hooli"
}
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 2,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
POST
Create meeting
/meetings
Request Body
title
string
required
body
startAt
string | null
optional
body
endAt
string | null
optional
body
overview
string | null
optional
body
topicsDiscussed
string | null
optional
body
gist
string | null
optional
body
transcriptUrl
string | null
optional
body
sentences
Sentence[] | null
optional
body
accountId
integer
optional
body
attendees
object[]
optional
body
Responses
201Meeting created
400Validation error
curl -X POST https://zudo.so/api/v1/meetings \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Raviga Board Meeting",
"startAt": "2025-02-01T18:00:00.000Z",
"endAt": "2025-02-01T19:00:00.000Z",
"overview": "Laurie Bream presented the new fund allocation strategy.",
"accountId": 3,
"attendees": [
{ "email": "[email protected]", "name": "Laurie Bream" },
{ "email": "[email protected]", "name": "Monica Hall" }
],
"sentences": [
{ "text": "Welcome everyone, let us start with the fund update.", "speaker_name": "Laurie Bream", "speaker_id": 1, "start_time": 0 },
{ "text": "We exited two positions this quarter.", "speaker_name": "Monica Hall", "speaker_id": 2, "start_time": 18.5 }
]
}'
const res = await fetch("https://zudo.so/api/v1/meetings", {
method: "POST",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"title": "Raviga Board Meeting",
"startAt": "2025-02-01T18:00:00.000Z",
"endAt": "2025-02-01T19:00:00.000Z",
"overview": "Laurie Bream presented the new fund allocation strategy.",
"accountId": 3,
"attendees": [
{ "email": "[email protected]", "name": "Laurie Bream" },
{ "email": "[email protected]", "name": "Monica Hall" }
],
"sentences": [
{ "text": "Welcome everyone, let us start with the fund update.", "speaker_name": "Laurie Bream", "speaker_id": 1, "start_time": 0 },
{ "text": "We exited two positions this quarter.", "speaker_name": "Monica Hall", "speaker_id": 2, "start_time": 18.5 }
]
})
});
const data = await res.json();
import requests
res = requests.post("https://zudo.so/api/v1/meetings",
headers={"x-api-key": "psk_your_key_here"},
json={
"title": "Raviga Board Meeting",
"startAt": "2025-02-01T18:00:00.000Z",
"endAt": "2025-02-01T19:00:00.000Z",
"overview": "Laurie Bream presented the new fund allocation strategy.",
"accountId": 3,
"attendees": [
{ "email": "[email protected]", "name": "Laurie Bream" },
{ "email": "[email protected]", "name": "Monica Hall" }
],
"sentences": [
{ "text": "Welcome everyone, let us start with the fund update.", "speaker_name": "Laurie Bream", "speaker_id": 1, "start_time": 0 },
{ "text": "We exited two positions this quarter.", "speaker_name": "Monica Hall", "speaker_id": 2, "start_time": 18.5 }
]
})
data = res.json()
Response
{
"data": {
"id": 3,
"title": "Raviga Board Meeting",
"startAt": "2025-02-01T18:00:00.000Z",
"endAt": "2025-02-01T19:00:00.000Z",
"overview": "Laurie Bream presented the new fund allocation strategy.",
"topicsDiscussed": null,
"transcriptText": "Welcome everyone, let us start with the fund update. We exited two positions this quarter.",
"sentences": [
{
"text": "Welcome everyone, let us start with the fund update.",
"speaker_name": "Laurie Bream",
"speaker_id": 1,
"start_time": 0
},
{
"text": "We exited two positions this quarter.",
"speaker_name": "Monica Hall",
"speaker_id": 2,
"start_time": 18.5
}
],
"account": {
"id": 3,
"name": "Raviga Capital"
}
}
}
GET
Get meeting by ID
/meetings/{meetingId}
Path Parameters
meetingId
integer
required
path
Responses
200Meeting details with attendees and duration
404Meeting not found
curl https://zudo.so/api/v1/meetings/1 \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/meetings/1", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/meetings/1",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": {
"id": 1,
"title": "Pied Piper Q1 Business Review",
"startAt": "2025-01-20T17:00:00.000Z",
"endAt": "2025-01-20T18:00:00.000Z",
"overview": "Discussed platform adoption metrics and the new decentralized internet initiative.",
"topicsDiscussed": "Compression benchmarks, new internet architecture, Series C timeline",
"gist": "Reviewed Q1 adoption metrics; agreed to fast-track the decentralized internet POC.",
"transcriptUrl": "https://app.fireflies.ai/view/abc123",
"transcriptText": "Richard: our compression scores are still ahead of Hooli but the gap is narrowing. Jared: we need to ship the new encoder before Series C diligence…",
"sentences": [
{
"text": "Our compression scores are still ahead of Hooli but the gap is narrowing.",
"speaker_name": "Richard Hendricks",
"speaker_id": 1,
"start_time": 12.4
},
{
"text": "We need to ship the new encoder before Series C diligence.",
"speaker_name": "Jared Dunn",
"speaker_id": 2,
"start_time": 18.9
}
],
"durationMinutes": 60,
"account": {
"id": 1,
"name": "Pied Piper"
},
"attendees": [
{
"id": 1,
"name": "Richard Hendricks",
"email": "[email protected]"
},
{
"id": 5,
"name": "Jared Dunn",
"email": "[email protected]"
}
]
}
}
Conversations
Email threads and messages
GET
List email threads
/conversations/threads
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
accountId
integer
optional
query
sortBy
string
optional
query
sortOrder
string
optional
query
Responses
200Paginated list of email threads
curl https://zudo.so/api/v1/conversations/threads \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/conversations/threads", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/conversations/threads",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"subject": "Re: Pied Piper platform migration timeline",
"snippet": "Richard, just following up on the migration window we discussed...",
"latestMessageDirection": "inbound",
"latestMessageAt": "2025-01-14T11:30:00.000Z",
"createdAt": "2025-01-10T09:00:00.000Z",
"messageCount": 5,
"account": {
"id": 1,
"name": "Pied Piper"
}
},
{
"id": 2,
"subject": "Hooli Nucleus - API rate limit increase",
"snippet": "We need to bump up our rate limits before the Nucleus launch...",
"latestMessageDirection": "outbound",
"latestMessageAt": "2025-01-13T16:15:00.000Z",
"createdAt": "2025-01-12T08:00:00.000Z",
"messageCount": 3,
"account": {
"id": 2,
"name": "Hooli"
}
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 2,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
POST
Create email thread
/conversations/threads
Request Body
accountId
integer
required
body
subject
string
required
body
body
string | null
optional
body
fromEmail
string | null
optional
body
toEmails
string[]
optional
body
receivedAt
string
optional
body
Responses
201Thread created with initial message
400Validation error
404Account not found
curl -X POST https://zudo.so/api/v1/conversations/threads \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"accountId": 1,
"subject": "Decentralized internet POC update",
"body": "Hey Richard, attached are the latest throughput numbers from the new internet tests.",
"fromEmail": "[email protected]",
"toEmails": ["[email protected]"]
}'
const res = await fetch("https://zudo.so/api/v1/conversations/threads", {
method: "POST",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"accountId": 1,
"subject": "Decentralized internet POC update",
"body": "Hey Richard, attached are the latest throughput numbers from the new internet tests.",
"fromEmail": "[email protected]",
"toEmails": ["[email protected]"]
})
});
const data = await res.json();
import requests
res = requests.post("https://zudo.so/api/v1/conversations/threads",
headers={"x-api-key": "psk_your_key_here"},
json={
"accountId": 1,
"subject": "Decentralized internet POC update",
"body": "Hey Richard, attached are the latest throughput numbers from the new internet tests.",
"fromEmail": "[email protected]",
"toEmails": ["[email protected]"]
})
data = res.json()
Response
{
"data": {
"id": 3,
"subject": "Decentralized internet POC update",
"snippet": "Hey Richard, attached are the latest throughput numbers from the new internet tests.",
"latestMessageDirection": "outbound",
"latestMessageAt": "2025-01-15T12:00:00.000Z",
"createdAt": "2025-01-15T12:00:00.000Z",
"messageCount": 1,
"account": {
"id": 1,
"name": "Pied Piper"
},
"messages": [
{
"id": 3,
"direction": "outbound",
"isInternalSender": true,
"isInternalRecipient": false,
"fromEmail": "[email protected]",
"toEmails": [
"[email protected]"
],
"subject": "Decentralized internet POC update",
"snippet": "Hey Richard, attached are the latest throughput numbers from the new internet tests.",
"receivedAt": "2025-01-15T12:00:00.000Z"
}
]
}
}
GET
Get messages in a thread
/conversations/threads/{threadId}/messages
Path Parameters
threadId
integer
required
path
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
Responses
200Paginated messages in the thread
404Thread not found
curl https://zudo.so/api/v1/conversations/threads/1/messages \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/conversations/threads/1/messages", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/conversations/threads/1/messages",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"direction": "inbound",
"isInternalSender": false,
"isInternalRecipient": true,
"fromEmail": "[email protected]",
"toEmails": [
"[email protected]"
],
"subject": "Re: Pied Piper platform migration timeline",
"snippet": "Jared, can we push the migration to next week? Gilfoyle is still setting up the servers.",
"receivedAt": "2025-01-10T09:00:00.000Z",
"createdAt": "2025-01-10T09:00:00.000Z"
},
{
"id": 2,
"direction": "outbound",
"isInternalSender": true,
"isInternalRecipient": false,
"fromEmail": "[email protected]",
"toEmails": [
"[email protected]"
],
"subject": "Re: Pied Piper platform migration timeline",
"snippet": "Absolutely, Richard. I will adjust the timeline and notify the stakeholders.",
"receivedAt": "2025-01-10T09:45:00.000Z",
"createdAt": "2025-01-10T09:45:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 2,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
Issues
Linked engineering issues
GET
List issues
/issues
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
state
string
optional
query
sortBy
string
optional
query
sortOrder
string
optional
query
Responses
200Paginated list of issues
curl https://zudo.so/api/v1/issues \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/issues", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/issues",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 10,
"identifier": "ENG-142",
"title": "Implement compression API",
"description": "Expose middle-out compression as a public REST endpoint.",
"state": "In Progress",
"creator": "[email protected]",
"url": "https://linear.app/piedpiper/issue/ENG-142",
"issueCreatedAt": "2024-11-05T10:00:00.000Z",
"issueUpdatedAt": "2025-01-08T16:45:00.000Z"
},
{
"id": 11,
"identifier": "ENG-143",
"title": "Fix Gilfoyle's crypto-mining daemon conflicts",
"description": "Server resources are being consumed by an unauthorized mining process.",
"state": "Backlog",
"creator": "[email protected]",
"url": "https://linear.app/piedpiper/issue/ENG-143",
"issueCreatedAt": "2024-12-01T08:00:00.000Z",
"issueUpdatedAt": "2024-12-15T14:30:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 2,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
GET
Get issue by ID
/issues/{issueId}
Path Parameters
issueId
integer
required
path
Responses
200Issue details with linked requests and accounts
404Issue not found
curl https://zudo.so/api/v1/issues/10 \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/issues/10", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/issues/10",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": {
"id": 10,
"identifier": "ENG-142",
"title": "Implement compression API",
"description": "Expose middle-out compression as a public REST endpoint.",
"state": "In Progress",
"creator": "[email protected]",
"url": "https://linear.app/piedpiper/issue/ENG-142",
"issueCreatedAt": "2024-11-05T10:00:00.000Z",
"issueUpdatedAt": "2025-01-08T16:45:00.000Z",
"updatedAt": "2025-01-08T16:45:00.000Z",
"requests": [
{
"id": 1,
"title": "Middle-out compression API endpoint",
"status": "Open"
}
],
"accounts": [
{
"id": 1,
"name": "Pied Piper"
}
]
}
}
Contacts
Customer contacts
GET
List contacts
/contacts
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
accountId
integer
optional
query
Responses
200Paginated list of contacts
curl https://zudo.so/api/v1/contacts \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/contacts", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/contacts",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"name": "Richard Hendricks",
"email": "[email protected]",
"createdAt": "2024-03-15T08:00:00.000Z",
"accounts": [
{
"id": 1,
"name": "Pied Piper"
}
]
},
{
"id": 2,
"name": "Gavin Belson",
"email": "[email protected]",
"createdAt": "2024-01-08T10:30:00.000Z",
"accounts": [
{
"id": 2,
"name": "Hooli"
}
]
},
{
"id": 3,
"name": "Monica Hall",
"email": "[email protected]",
"createdAt": "2024-06-20T16:00:00.000Z",
"accounts": [
{
"id": 3,
"name": "Raviga Capital"
}
]
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 3,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
POST
Create contact
/contacts
Request Body
name
string
required
body
email
string
required
body
accountIds
integer[]
required
body
Responses
201Contact created
400Validation error
403Account not authorized
curl -X POST https://zudo.so/api/v1/contacts \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Dinesh Chugtai",
"email": "[email protected]",
"accountIds": [1]
}'
const res = await fetch("https://zudo.so/api/v1/contacts", {
method: "POST",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"name": "Dinesh Chugtai",
"email": "[email protected]",
"accountIds": [1]
})
});
const data = await res.json();
import requests
res = requests.post("https://zudo.so/api/v1/contacts",
headers={"x-api-key": "psk_your_key_here"},
json={
"name": "Dinesh Chugtai",
"email": "[email protected]",
"accountIds": [1]
})
data = res.json()
Response
{
"data": {
"id": 4,
"name": "Dinesh Chugtai",
"email": "[email protected]",
"createdAt": "2025-01-15T12:00:00.000Z",
"accounts": [
{
"id": 1,
"name": "Pied Piper"
}
]
}
}
PATCH
Update contact
/contacts/{contactId}
Path Parameters
contactId
integer
required
path
Request Body
lastSeenAt
string | integer | null
optional
body
Responses
200Updated contact
400Invalid input
404Contact not found
curl -X PATCH https://zudo.so/api/v1/contacts/42 \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"lastSeenAt": "2025-04-08T12:00:00.000Z"
}'
const res = await fetch("https://zudo.so/api/v1/contacts/42", {
method: "PATCH",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"lastSeenAt": "2025-04-08T12:00:00.000Z"
})
});
const data = await res.json();
import requests
res = requests.patch("https://zudo.so/api/v1/contacts/42",
headers={"x-api-key": "psk_your_key_here"},
json={
"lastSeenAt": "2025-04-08T12:00:00.000Z"
})
data = res.json()
Response
{
"data": {
"id": 42,
"name": "Monica Hall",
"email": "[email protected]",
"lastSeenAt": "2025-04-08T12:00:00.000Z",
"createdAt": "2024-03-15T08:00:00.000Z",
"updatedAt": "2025-04-08T12:00:00.000Z",
"accounts": [
{
"id": 1,
"name": "Pied Piper"
}
]
}
}
Tasks
Tasks and action items
GET
List tasks
/tasks
Query Parameters
page
integer
optional
query
pageSize
integer
optional
query
search
string
optional
query
status
string
optional
query
priority
string
optional
query
accountId
integer
optional
query
sortBy
string
optional
query
sortOrder
string
optional
query
Responses
200Paginated list of tasks
curl https://zudo.so/api/v1/tasks \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/tasks", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/tasks",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": [
{
"id": 1,
"title": "Send updated Weissman scores to Hooli",
"description": "Gavin's team needs the latest benchmark numbers before the Nucleus launch.",
"status": "OPEN",
"priority": "HIGH",
"dueAt": "2025-01-25T12:00:00.000Z",
"createdAt": "2025-01-10T09:00:00.000Z",
"updatedAt": "2025-01-10T09:00:00.000Z"
},
{
"id": 2,
"title": "Follow up with Raviga on Series C docs",
"description": "Monica needs the financials by end of week.",
"status": "OPEN",
"priority": "URGENT",
"dueAt": "2025-01-17T12:00:00.000Z",
"createdAt": "2025-01-12T14:00:00.000Z",
"updatedAt": "2025-01-13T08:30:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 2,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}
POST
Create task
/tasks
Request Body
title
string
required
body
description
string | null
optional
body
priority
string | null
optional
body
status
string
optional
body
dueAt
string | null
optional
body
accountIds
integer[]
optional
body
accountUrgencies
object
optional
body
issueIds
integer[]
optional
body
requestIds
integer[]
optional
body
Responses
201Task created
400Validation error
curl -X POST https://zudo.so/api/v1/tasks \
-H "x-api-key: psk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Prepare TechCrunch Disrupt demo",
"description": "Build the live demo showcasing new internet compression ratios.",
"priority": "URGENT",
"status": "OPEN",
"dueAt": "2025-02-10T12:00:00.000Z",
"accountIds": [1]
}'
const res = await fetch("https://zudo.so/api/v1/tasks", {
method: "POST",
headers: {
"x-api-key": "psk_your_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify({
"title": "Prepare TechCrunch Disrupt demo",
"description": "Build the live demo showcasing new internet compression ratios.",
"priority": "URGENT",
"status": "OPEN",
"dueAt": "2025-02-10T12:00:00.000Z",
"accountIds": [1]
})
});
const data = await res.json();
import requests
res = requests.post("https://zudo.so/api/v1/tasks",
headers={"x-api-key": "psk_your_key_here"},
json={
"title": "Prepare TechCrunch Disrupt demo",
"description": "Build the live demo showcasing new internet compression ratios.",
"priority": "URGENT",
"status": "OPEN",
"dueAt": "2025-02-10T12:00:00.000Z",
"accountIds": [1]
})
data = res.json()
Response
{
"data": {
"id": 3,
"title": "Prepare TechCrunch Disrupt demo",
"description": "Build the live demo showcasing new internet compression ratios.",
"status": "OPEN",
"priority": "URGENT",
"dueAt": "2025-02-10T12:00:00.000Z",
"createdAt": "2025-01-15T12:00:00.000Z",
"updatedAt": "2025-01-15T12:00:00.000Z"
}
}
GET
Get task by ID
/tasks/{taskId}
Path Parameters
taskId
integer
required
path
Responses
200Task details with linked accounts, issues, requests, meetings, and assignee
404Task not found
curl https://zudo.so/api/v1/tasks/1 \
-H "x-api-key: psk_your_key_here"
const res = await fetch("https://zudo.so/api/v1/tasks/1", {
headers: { "x-api-key": "psk_your_key_here" }
});
const data = await res.json();
import requests
res = requests.get("https://zudo.so/api/v1/tasks/1",
headers={"x-api-key": "psk_your_key_here"})
data = res.json()
Response
{
"data": {
"id": 1,
"title": "Send updated Weissman scores to Hooli",
"description": "Gavin's team needs the latest benchmark numbers before the Nucleus launch.",
"status": "OPEN",
"priority": "HIGH",
"dueAt": "2025-01-25T12:00:00.000Z",
"createdAt": "2025-01-10T09:00:00.000Z",
"updatedAt": "2025-01-10T09:00:00.000Z",
"assignee": {
"id": 5,
"fullName": "Jared Dunn"
},
"accounts": [
{
"id": 2,
"name": "Hooli"
}
],
"issues": [
{
"id": 10,
"identifier": "ENG-142",
"title": "Implement compression API"
}
],
"requests": [
{
"id": 1,
"title": "Middle-out compression API endpoint",
"status": "Open"
}
],
"meetings": [
{
"id": 2,
"title": "Hooli-XYZ Partnership Sync",
"startAt": "2025-01-18T15:00:00.000Z"
}
]
}
}
Search
Cross-record search and AI Q&A
GET
Search a single account's records
/accounts/{accountId}/search
Path Parameters
accountId
integer
required
path
Query Parameters
q
string
required
query
Responses
200Grouped search results scoped to the account.
400Missing or invalid query.
404Account not found.
POST
Ask an AI question about a single account
/search/ai-chat
Request Body
query
string
required
body
accountId
integer
required
body
Responses
200AI answer with citations referencing the source records.
400Missing or invalid query.
403AI search is disabled for this organization.
Schemas
Pagination
page |
integer |
pageSize |
integer |
total |
integer |
totalPages |
integer |
hasNextPage |
boolean |
hasPrevPage |
boolean |
Error
error |
string |
Account
id |
integer |
name |
string |
externalId |
string | null |
mrr |
number | null |
active |
boolean |
churned |
boolean |
onboarding |
boolean |
logoUrl |
string | null |
contactActivityAt |
string | null |
createdAt |
string |
updatedAt |
string |
Request
id |
integer |
title |
string |
notes |
string | null |
status |
string |
severity |
number | null |
userSeverity |
integer | null |
effectiveUserSeverity |
number | null |
requestedAt |
string | null |
createdAt |
string |
updatedAt |
string |
accounts |
object[] |
issues |
object[] |
Sentence
text |
string |
speaker_name |
string | null |
speaker_id |
integer | string | null |
start_time |
number | null |
Meeting
id |
integer |
title |
string |
startAt |
string | null |
endAt |
string | null |
overview |
string | null |
topicsDiscussed |
string | null |
gist |
string | null |
transcriptUrl |
string | null |
transcriptText |
string | null |
sentences |
Sentence[] | null |
transcriptMatch |
string | null |
durationMinutes |
number | null |
account |
object | null |
attendees |
object[] |
Thread
id |
integer |
subject |
string |
snippet |
string | null |
latestMessageDirection |
string |
latestMessageAt |
string | null |
createdAt |
string |
messageCount |
integer |
account |
object | null |
messages |
Message[] |
Issue
id |
integer |
identifier |
string |
title |
string |
description |
string | null |
state |
string |
creator |
string | null |
url |
string | null |
issueCreatedAt |
string | null |
issueUpdatedAt |
string | null |
updatedAt |
string |
requests |
object[] |
accounts |
object[] |
Contact
id |
integer |
name |
string |
email |
string |
lastSeenAt |
string | null |
createdAt |
string |
updatedAt |
string |
accounts |
object[] |
Message
id |
integer |
direction |
string |
isInternalSender |
boolean | null |
isInternalRecipient |
boolean | null |
fromEmail |
string |
toEmails |
string[] |
subject |
string | null |
snippet |
string | null |
receivedAt |
string | null |
createdAt |
string |
Task
id |
integer |
title |
string |
description |
string | null |
status |
string |
priority |
string | null |
dueAt |
string | null |
createdAt |
string |
updatedAt |
string |
assignee |
object | null |
CreateAccount
name |
string |
externalId |
string | null |
mrr |
number | null |
status |
string |
contactName |
string | null |
contactEmail |
string | null |
CreateContact
name |
string |
email |
string |
accountIds |
integer[] |
CreateTask
title |
string |
description |
string | null |
priority |
string | null |
status |
string |
dueAt |
string | null |
accountIds |
integer[] |
accountUrgencies |
object |
issueIds |
integer[] |
requestIds |
integer[] |
CreateRequest
title |
string |
notes |
string | null |
severity |
integer |
requestedAt |
string |
accountIds |
integer[] |
issueIds |
integer[] |
CreateMeeting
title |
string |
startAt |
string | null |
endAt |
string | null |
overview |
string | null |
topicsDiscussed |
string | null |
gist |
string | null |
transcriptUrl |
string | null |
sentences |
Sentence[] | null |
accountId |
integer |
attendees |
object[] |
CreateThread
accountId |
integer |
subject |
string |
body |
string | null |
fromEmail |
string | null |
toEmails |
string[] |
receivedAt |
string |