Activities
Log, read, update and delete activities such as Actions, calls, meetings and emails.
An activity is something someone did, or plans to do, about a record: an Action, a call, a meeting, an email, a LinkedIn touchpoint or a note. Activities can link to a Deal, a Contact, an Account and a prospect contact at the same time. They appear on the Activities page and on each linked record in Signal.
Actions are activities with type_id rat_action. To create an Action that appears in Signal's Actions list, use POST /activities with that type.
To log a phone call with its duration and direction, you can also use POST /calls.
The activity object#
| Field | Type | Notes |
|---|---|---|
id |
string | UUID. |
subject |
string | |
description |
string or null | |
type_id |
string | See Activity types. |
start_at |
string or null | ISO 8601 timestamp. |
end_at |
string or null | ISO 8601 timestamp. |
is_completed |
boolean | |
completed_at |
string or null | Set when the activity is marked complete. |
outcome |
string or null | Free text. |
deal_id |
string or null | Linked Deal. |
contact_id |
string or null | Linked Contact. |
prospect_id |
string or null | Linked prospect contact. |
account_id |
string or null | Linked Account. |
owner_id |
string or null | User ID of the person the activity belongs to. |
assigned_user_id |
string or null | User ID of the teammate the activity has been handed to, if any. |
created_at |
string | ISO 8601 timestamp. |
updated_at |
string | ISO 8601 timestamp. |
{
"id": "4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22",
"subject": "Send revised quote",
"description": "Include the 3-year option.",
"type_id": "rat_action",
"start_at": "2026-11-14T15:00:00.000Z",
"end_at": null,
"is_completed": false,
"completed_at": null,
"outcome": null,
"deal_id": "7c2e9f14-3a6b-4d1e-8f5a-9b0c2d4e6f81",
"contact_id": "a1d4e7b2-5c3f-4e8a-b9d6-0f2c7e1a3b54",
"prospect_id": null,
"account_id": "3f6c2a1e-8b4d-4c2a-9f1e-2b7d5a9c4e10",
"owner_id": "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20",
"assigned_user_id": null,
"created_at": "2026-11-12T09:30:00.000Z",
"updated_at": "2026-11-12T09:30:00.000Z"
}
Activity types#
type_id |
Type |
|---|---|
rat_action |
Action |
rat_call |
Call |
rat_email |
|
rat_meeting |
Meeting |
rat_linkedin |
|
rat_task |
Task |
rat_note |
Note |
Signal also records some activities itself, which you may see when reading: rat_stage_change (a Deal moved stage), rat_deal_won and rat_deal_lost.
type_id must be one of these, or an older type Signal still records, such as rat_demo or rat_follow_up. A bare name also works and means the type with the rat_ prefix: call is rat_call, Meeting is rat_meeting. Any other value answers 400 INVALID_REQUEST ("Unknown type_id"), and nothing is created.
List activities#
GET /activities · Scope: activities:read
Returns activities newest first (by when they were created).
Query parameters#
| Parameter | Type | Required | Notes |
|---|---|---|---|
deal_id |
string | No | Only activities linked to this Deal. |
contact_id |
string | No | Only activities linked to this Contact. |
prospect_id |
string | No | Only activities linked to this prospect contact. |
account_id |
string | No | Only activities linked to this Account. |
limit |
integer | No | 1 to 100. Default 20. |
cursor |
string | No | meta.cursor from the previous page. |
Example#
curl "https://crm.empiraa.app/api/v1/activities?deal_id=7c2e9f14-3a6b-4d1e-8f5a-9b0c2d4e6f81" \
-H "Authorization: Bearer YOUR_API_KEY"
const url = new URL("https://crm.empiraa.app/api/v1/activities");
url.searchParams.set("deal_id", "7c2e9f14-3a6b-4d1e-8f5a-9b0c2d4e6f81");
const res = await fetch(url, { headers: { Authorization: "Bearer YOUR_API_KEY" } });
const { data, meta } = await res.json();
Response 200#
An array of activity objects in data; meta has cursor and hasMore.
Create an activity#
POST /activities · Scope: activities:write · Supports Idempotency-Key
Request body#
| Field | Type | Required | Notes |
|---|---|---|---|
subject |
string | Yes | |
type_id |
string | Yes | See Activity types. |
description |
string or null | No | |
start_at |
string or null | No | ISO 8601 timestamp. |
end_at |
string or null | No | ISO 8601 timestamp. |
outcome |
string or null | No | |
deal_id |
string or null | No | Must be a Deal in this workspace. |
contact_id |
string or null | No | Must be a Contact in this workspace. |
prospect_id |
string or null | No | Must be a prospect contact in this workspace. |
account_id |
string or null | No | Must be an Account in this workspace. |
owner_id |
string or null | No | A member of the workspace. Leave out for no owner. |
assigned_user_id |
string or null | No | A member of the workspace. |
Example: create an Action#
curl -X POST https://crm.empiraa.app/api/v1/activities \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6d1f3b5a-8c2e-4a7d-9f0b-1e3c5a7d9b42" \
-d '{
"subject": "Send revised quote",
"type_id": "rat_action",
"start_at": "2026-11-14T15:00:00Z",
"deal_id": "7c2e9f14-3a6b-4d1e-8f5a-9b0c2d4e6f81",
"owner_id": "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20"
}'
const res = await fetch("https://crm.empiraa.app/api/v1/activities", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
subject: "Send revised quote",
type_id: "rat_action",
start_at: "2026-11-14T15:00:00Z",
deal_id: "7c2e9f14-3a6b-4d1e-8f5a-9b0c2d4e6f81",
owner_id: "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20",
}),
});
Response 201#
The new activity object in data.
Errors#
| Status | Code | When |
|---|---|---|
| 400 | INVALID_REQUEST |
subject or type_id is missing, or type_id isn't an activity type; start_at or end_at isn't a date; or owner_id or assigned_user_id isn't a string or null. |
| 404 | NOT_FOUND |
A linked Deal, Contact, Account or prospect contact isn't in this workspace (title says which), or owner_id or assigned_user_id isn't a member of the workspace. |
Webhook events: none.
Get an activity#
GET /activities/{id} · Scope: activities:read
Example#
curl https://crm.empiraa.app/api/v1/activities/4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22 \
-H "Authorization: Bearer YOUR_API_KEY"
await fetch("https://crm.empiraa.app/api/v1/activities/4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
Response 200#
The activity object in data.
Errors#
| Status | Code | When |
|---|---|---|
| 404 | NOT_FOUND |
No activity with that ID in this workspace. |
Update an activity#
PATCH /activities/{id} · Scope: activities:write
Send only the fields you want to change. Use is_completed to mark an activity done.
Request body#
| Field | Type | Notes |
|---|---|---|
subject |
string | |
description |
string or null | |
outcome |
string or null | |
start_at |
string or null | ISO 8601 timestamp. |
end_at |
string or null | ISO 8601 timestamp. |
is_completed |
boolean | true marks it done and sets completed_at to now; false clears completed_at. |
deal_id |
string or null | Must be a Deal in this workspace. |
contact_id |
string or null | Must be a Contact in this workspace. |
account_id |
string or null | Must be an Account in this workspace. |
owner_id |
string or null | A member of the workspace, or null. |
assigned_user_id |
string or null | A member of the workspace, or null. |
type_id and prospect_id can't be changed after creation.
Example: mark complete#
curl -X PATCH https://crm.empiraa.app/api/v1/activities/4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"is_completed": true, "outcome": "Quote sent"}'
await fetch("https://crm.empiraa.app/api/v1/activities/4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22", {
method: "PATCH",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ is_completed: true, outcome: "Quote sent" }),
});
Response 200#
The updated activity object in data.
Errors#
| Status | Code | When |
|---|---|---|
| 400 | INVALID_REQUEST |
A date isn't valid, or owner_id or assigned_user_id isn't a string or null. |
| 404 | NOT_FOUND |
The activity, a linked record or a named user isn't in this workspace. |
Webhook events: none.
Delete an activity#
DELETE /activities/{id} · Scope: activities:write
Deletes the activity permanently.
Example#
curl -X DELETE https://crm.empiraa.app/api/v1/activities/4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22 \
-H "Authorization: Bearer YOUR_API_KEY"
await fetch("https://crm.empiraa.app/api/v1/activities/4e6a8c0b-2d4f-4a6c-8e0b-3d5f7a9c1e22", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
Response 204#
No body.
Errors#
| Status | Code | When |
|---|---|---|
| 404 | NOT_FOUND |
No activity with that ID in this workspace. |

