Skip to main content

Activities

One thing that happened, logged by a person or by an integration: a call made, a meeting held, a note taken. An activity hangs off a contact, a company or a deal — at least one — because an activity attached to nothing is a sentence nobody can find from anywhere.

An activity is a log entry, and a log is written once. There is no PATCH: an entry that turns out to be wrong is deleted and logged again, which keeps every row's at and byUid the record of what was logged rather than what somebody later wished had been.

Scopes and the site rule are shared with every CRM resource — see companies.

The activity object

{
"id": "a_8f21",
"object": "activity",
"kind": "call",
"body": "Walked through the proposal. They want the Q4 volume tier.",
"at": "2026-09-05T16:30:00.000Z",
"byUid": "u_9f1c",
"contactId": "k7d2b9f104",
"companyId": null,
"dealId": "d_3c9a",
"outcome": "Interested",
"durationMinutes": 25,
"siteId": "site_a1b2c3",
"created": "2026-09-05T18:23:23.941Z",
"updated": "2026-09-05T18:23:23.941Z"
}
FieldTypeNotes
idstringOpaque activity id.
objectstringAlways "activity".
kindstringcall, email, meeting, note or other. note when not sent.
bodystringRequired. What happened, 5,000 characters.
atstringWhen it happened — which is not when it was logged. ISO 8601 instant; defaults to the moment of the request, for the integration logging a call as it ends.
byUidstringWho did it. Must be a member of your organization; "api" when not sent.
contactId, companyId, dealIdstring | nullWhat it is about. At least one is required, and each must exist.
outcomestring | nullA short label, 120 characters.
durationMinutesinteger | nullA whole number, 0 or more.
siteIdstringThe site the activity was logged from. Read-only.
created / updatedstring | nullISO 8601.

Endpoints

List activities

GET /v1/activities — scope crm:read. Paginated, ordered by activity id unless updatedAfter is given.

ParamNotes
dealId, contactId, companyIdActivities about that record.
kindOne of the five kinds. Anything else is a 400.
updatedAfterActivities updated after this instant — the sync filter. An activity is written once, so this is when it was logged.
limit, cursorStandard pagination.
# the history of one deal
curl "https://app.aglyn.com/api/v1/activities?dealId=d_3c9a" \
-H "Authorization: Bearer aglyn_sk_…"

One filter narrows the query — dealId, then contactId, companyId, kind — and the rest are checked on the page, which can come back short.

Retrieve an activity

GET /v1/activities/{activityId} — scope crm:read. Returns an activity, or 404 not_found ("No such activity").

Log an activity

POST /v1/activities — scope crm:write. Accepts an Idempotency-Key, scoped to the organization — send one from a dialer or a mail integration, where a retry after a lost response would otherwise log the call twice. body, consentSiteId and at least one of contactId, companyId, dealId are required.

curl -X POST "https://app.aglyn.com/api/v1/activities" \
-H "Authorization: Bearer aglyn_sk_…" \
-H "Idempotency-Key: 9a41f0c2-…" \
-H "Content-Type: application/json" \
-d '{"kind":"call","body":"Walked through the proposal.","at":"2026-09-05T16:30:00Z","byUid":"u_9f1c","dealId":"d_3c9a","durationMinutes":25,"consentSiteId":"site_a1b2c3"}'

Returns 201, or 200 with the original when an Idempotency-Key replays.

Delete an activity

DELETE /v1/activities/{activityId} — scope crm:write. Accepts an Idempotency-Key, scoped to the organization.

{ "id": "a_8f21", "object": "activity", "deleted": true }

Errors

StatustypeWhen
400bad_requestcode: "validation_failed" — a missing body or consentSiteId, no contactId, companyId or dealId at all (fields.contactId explains), a kind outside its list, an at that is not an ISO 8601 instant, a byUid who is not a member, a reference that does not exist, or a durationMinutes that is not a whole number 0 or more. On the list, a ?kind= outside the list or a malformed ?updatedAfter=.
403insufficient_scopeKey lacks crm:read / crm:write.
404not_found"No such activity".
405method_not_allowedAllow: GET, POST on /v1/activities, GET, DELETE on one activity — a PATCH is refused here rather than with a 404 that would read as "no such activity".
409conflictcode: "idempotency_in_progress". code: "activity_log_full" — the record named already carries 5,000 activities, the most one record can hold; the key is given back.

See Conventions → Errors for the shared envelope.

  • Tasks — what is owed, as opposed to what happened.
  • Contacts — the platform's own record of what a person did (a form, an order, a booking) lives on the contact's timeline in the console, not here.