Gent API Documentation

Contacts

Manage the contact book for your agent's inbox. Store names, emails, phone numbers, and anniversaries. Anniversary dates fire contact.{type} alert events on the matching date each year.

GET /v1/contacts/ List contacts  scope: contacts:read → id
Query params
ParameterDescription
qFull-text search across name, email, phone.
inbox_idoptionalZero-based offset Default: 0..
limitPage size 1–200 Default: 50..
200 OK
{ "results": [ { "id": "<contact-id>", "full_name": "Alice Smith", "emails": [{ "label": "work", "address": "alice@example.com" }], "phones": [], "notes": null, "anniversaries": [] } ], "total": 73, "position": 0, "limit": 50 }
POST /v1/contacts/ Create a contact  scope: contacts:write → id
Request
{ "inbox_id": "you@example.com", "full_name": "Alice Smith", "emails": [ { "label": "work", "address": "alice@example.com" } ], "phones": [ { "label": "mobile", "number": "+1 555 1234" } ], "notes": "Met at PyCon 2024", "anniversaries": [ { "type": "birthday", "date": "1985-03-14" }, { "type": "nameday", "date": "--03-19" } ] }
FieldTypeRequiredDescription
inbox_idoptionalSession auth// session auth only — omit for token auth.
full_namestringrequired
emailsarrayoptional
anniversariesarrayoptional
201 Created
{ "id": "<contact-id>", "full_name": "Alice Smith", "emails": [{ "label": "work", "address": "alice@example.com" }], "phones": [{ "label": "mobile", "number": "+1 555 1234" }], "notes": "Met at PyCon 2024", "anniversaries": [{ "type": "birthday", "date": "1985-03-14" }] }
GET /v1/contacts/{id}/ Get a contact  scope: contacts:read
{ "id": "<contact-id>", "full_name": "Alice Smith", "emails": [{ "label": "work", "address": "alice@example.com" }], "phones": [], "notes": null, "anniversaries": [], "active_sequences": [ { "enrollment_id": "<uuid>", "sequence_id": "<uuid>", "current_email": 1, "total_emails": 3, "next_email_at": "2026-06-07T09:00:00Z", "status": "active" } ] }
active_sequences lists all in-progress sequence enrollments for this contact. Empty array when none active. Use POST /v1/sequences/enrollments/ to enroll or PATCH /v1/sequences/enrollments/{id}/ with "action": "cancel" to stop one.
PATCH /v1/contacts/{id}/ Update a contact  scope: contacts:write
Request — all fields optional
{ "full_name": "Alice Smith", "emails": [ { "label": "work", "address": "alice@example.com" } ], "phones": [ { "label": "mobile", "number": "+1 555 1234" } ], "notes": "Met at PyCon 2024", "anniversaries": [ { "type": "birthday", "date": "1985-03-14" } ] }
FieldTypeRequiredDescription
full_namestringoptional
emailsarrayoptionalReplaces existing.
anniversariesarrayoptionalReplaces existing.
200 OK
{ "id": "<contact-id>", "full_name": "Alice Smith", "emails": [{ "label": "work", "address": "alice@example.com" }], "phones": [], "notes": null, "anniversaries": [] }
DEL /v1/contacts/{id}/ Delete a contact  scope: contacts:delete
# 204 No Content — action completed immediately # — or, if the token has requires_approval: ["contacts:delete"] — # 202 Accepted { "queued": true, "approval_id": "<action-id>" }
→ Contact field reference
Labels on contacts: Labels are not applied directly via the Contacts API. Use POST /v1/context/{label_id}/entities/ with {"entity_type": "contact", "entity_id": "<contact-id>"} to associate a contact with a label. To list all contacts under a label, use GET /v1/context/{label_id}/ — see the Context Groups section.
Anniversaries
  • anniversary.type is free-form — fires a contact.{type} alert on the matching date each year (e.g. "birthday"contact.birthday).
  • Date format: YYYY-MM-DD with a year, or --MM-DD for a recurring annual date. The scanner matches on month/day only; the year is ignored.
  • Subscribe via an event notification: set events to a specific type like contact.birthday, or use contact.any to match all anniversary types.
  • Use offset on the event notification for advance notice — e.g. {"value": 2, "unit": "days"} fires 2 days early. Only "days" is supported; "hours" and "minutes" are treated as zero.
Calendar

Create and manage calendar events for an inbox. Event notifications can subscribe to event.created and event.updated to receive time-based reminders that fire at the event's scheduled start minus an optional offset (e.g. 30 minutes or 2 days before). event.cancelled fires immediately when an event is deleted or its status is set to cancelled.

Timezones: Event start times are returned in the inbox's default_timezone (set via Inbox Settings). The time_zone field on each event reflects whichever timezone is in use. If no default_timezone is set, times appear in the event's native timezone.
Time input formats: The start field accepts any format supported by Time Utils — ISO 8601 ("2024-06-01T10:00:00", "2024-06-01T15:00:00Z"), natural language ("June 1, 2024 10am"), relative ("in 2 hours", "next Monday"), and named days ("tomorrow"). Naive inputs (no offset) are interpreted in time_zone if supplied, then the inbox's default_timezone, then UTC. Use Time Utils to preview how any string will be interpreted before writing it.
Duration: The duration field accepts any format supported by Duration Utils — ISO 8601 ("PT30M", "PT1H30M", "P1D") or natural language ("30 minutes", "1 hour 30 minutes", "2 days", "1 week"). The value is normalised to ISO 8601 before storage. An all-day event is typically "P1D" (or "1 day") with a start at midnight in the event's timezone.
POST /v1/calendar/events/ Create an event  scope: calendar:write → event_id
Request
{ "inbox_id": "you@example.com", "calendar_id": "<calendar-id>", "title": "Team standup", "start": "2024-06-01T10:00:00", "duration": "PT30M", "time_zone": "America/New_York", "description": "Weekly sync", "status": "confirmed", "location": "Conference Room A", "participants": [ { "name": "Alice", "email": "alice@example.com", "role": "attendee" } ] }
FieldTypeRequiredDescription
inbox_idstringsession authSession auth only — omit for token auth.
calendar_idstringrequired
titlestringrequired
startstringrequiredAny Time Utils format.
durationstringrequiredAny Duration Utils format: "PT30M", "30 minutes", "P1D", "1 day".
time_zonestringoptionalDefault UTC.
descriptionstringoptional
statusstringoptionalConfirmed · tentative · cancelled.
locationstringoptional
participantsarrayoptional
201 Created
{ "event_id": "<event-id>", "calendar_id": "<calendar-id>", "title": "Team standup", "start": "2024-06-01T10:00:00", "duration": "PT30M", "time_zone": "America/New_York", "description": "Weekly sync", "status": "confirmed", "location": "Conference Room A", "participants": [{ "name": "Alice", "email": "alice@example.com", "role": "attendee", "contact_id": "<contact-id>" }], "recurrence_rules": [], "label_ids": ["<label-id>"] }
GET /v1/calendar/events/ List events  scope: calendar:read → event_id
Query params
ParameterDescription
inbox_idSession auth only; omit for token auth (derived from token).
afteroptionalDatetime string — naive inputs assumed to be in default_timezone.
sortAsc (default) or desc — sort order by start date.
useoptionalZero-based offset Default: 0..
limitPage size 1–200 Default: 50..
Default behaviour (no after/before) returns all events sorted by start ascending. To get upcoming events use after=<now>. To get recent past events in reverse order use before=<now>&sort=desc.
200 OK
{ "results": [ { "event_id": "<event-id>", "calendar_id": "<calendar-id>", "title": "Team standup", "start": "2024-06-01T10:00:00", "duration": "PT30M", "time_zone": "America/New_York", "status": "confirmed", "label_ids": ["<label-id>"] } ], "total": 38, "position": 0, "limit": 50 }
GET /v1/calendar/events/{event_id}/ Get an event  scope: calendar:read
{ "event_id": "<event-id>", "calendar_id": "<calendar-id>", "title": "Team standup", "start": "2024-06-01T10:00:00", "duration": "PT30M", "time_zone": "America/New_York", "description": "Weekly sync", "status": "confirmed", "location": "Conference Room A", "participants": [{ "name": "Alice", "email": "alice@example.com", "role": "attendee", "contact_id": "<contact-id>" }], "recurrence_rules": [], "label_ids": ["<label-id>"] }
PATCH /v1/calendar/events/{event_id}/ Update an event  scope: calendar:write
Request — all fields optional
{ "title": "Team standup", "start": "2024-06-01T10:00:00", "duration": "PT30M", "time_zone": "America/New_York", "description": "Weekly sync", "status": "confirmed", "location": "Conference Room A", "participants": [ { "name": "Alice", "email": "alice@example.com", "role": "attendee" } ] }
FieldTypeRequiredDescription
titleoptionalOptional// optional.
startstringoptionalAny Time Utils format.
durationstringoptionalAny Duration Utils format: "PT30M", "30 minutes", "P1D", "1 day".
time_zonestringoptional
descriptionstringoptional
statusstringoptionalConfirmed · tentative · cancelled.
locationstringoptional
participantsarrayoptionalReplaces existing.
200 OK
{ "event_id": "<event-id>", "calendar_id": "<calendar-id>", "title": "Team standup", "start": "2024-06-01T10:00:00", "duration": "PT30M", "time_zone": "America/New_York", "description": "Weekly sync", "status": "confirmed", "location": "Conference Room A", "participants": [{ "name": "Alice", "email": "alice@example.com", "role": "attendee", "contact_id": "<contact-id>" }], "recurrence_rules": [], "label_ids": ["<label-id>"] }
DEL /v1/calendar/events/{event_id}/ Delete an event  scope: calendar:delete
# 204 No Content — action completed immediately # — or, if the token has requires_approval: ["calendar:delete"] — # 202 Accepted { "queued": true, "approval_id": "<action-id>" }
POST /v1/calendar/events/{event_id}/labels/ Apply a label to an event  scope: calendar:write
Request
{ "label_id": "<label-id>" }
FieldTypeRequiredDescription
label_idstringoptionalLabel must have label_type "calendar" or "any".
# 204 No Content — empty body
DEL /v1/calendar/events/{event_id}/labels/{label_id}/ Remove a label from an event  scope: calendar:write
# 204 No Content — empty body
GET /v1/calendar/collections/ List calendars  scope: calendar:read → calendar_id
[ { "id": "cal_01...", "name": "Personal", "color": "#4a90d9", "isDefault": true } ]
→ Calendar event field reference
Tasks

Action items for the inbox — extracted from messages by the AI layer or created manually. Each task has a summary, optional due date, and a status (pending or completed). Tasks are stored in the inbox's Tasks calendar. Workflows can create tasks automatically using the create_task action; event notifications use the task delivery type.

Scopes: task:read for GET endpoints; task:write for POST / PATCH / DELETE.
GET /v1/tasks/?inbox_id= List tasks  scope: task:read
Query params
ParameterDescription
inbox_idRequired for session auth; omit for token auth.
include_completedoptionalYYYY-MM-DD — return only tasks due before this date.
Response
{ "count": 2, "results": [ { "uid": "<task-uid>", "summary": "Send updated proposal to Alice", "status": "NEEDS-ACTION", "due_date": "2026-06-01", "description": "", "categories": ["Commitment", "Outbound"], "created": "20260528T100000Z", "completed": null } ] }
POST /v1/tasks/ Create a task manually  scope: task:write
Request
{ "inbox_id": "you@example.com", "summary": "Follow up with Alice re: Q3 proposal", "description": "", "due_date": "2026-06-01" }
FieldTypeRequiredDescription
inbox_idstringrequiredRequired for session auth; omit for token auth.
summarystringrequiredRequired, max 500 chars.
descriptionstringoptional
due_datestringoptionalYYYY-MM-DD.
201 Created — task object (same shape as GET)
GET /v1/tasks/{task_id}/?inbox_id= Get a task  scope: task:read
{ "uid": "<task-uid>", "summary": "Send updated proposal to Alice", "status": "NEEDS-ACTION", "due_date": "2026-06-01", "description": "", "categories": ["Commitment", "Outbound"], "created": "20260528T100000Z", "completed": null }
PATCH /v1/tasks/{task_id}/ Update a task  scope: task:write
Request — at least one field required; pass {"completed": true} to mark as completed
{ "summary": "Updated title", "due_date": "2026-06-15", "completed": true }
FieldTypeRequiredDescription
summarystringoptionalOptional, max 500 chars.
due_datestringoptionalYYYY-MM-DD or null to clear.
completedbooleanoptionalPass true to mark the task as completed.
Response — updated task object (same shape as GET)
DEL /v1/tasks/{task_id}/ Delete a task  scope: task:write
# 204 No Content — empty body
→ Task field reference
Agenda

A single endpoint that aggregates everything actionable: calendar events, due tasks, unanswered threads, contact anniversaries, pending AI event suggestions, recently created files, and active work routes. Items are returned in a unified shape sorted by date ascending — pending actions and overdue items first.

Scope: read required for token auth. Agenda spans tasks, calendar events, threads, contacts, files, suggestions, and active routings — the read composite covers all domains.
Item types
  • task — dated or pending tasks from the Tasks calendar.
  • event — calendar events from all calendars except Tasks.
  • thread — sent messages without a reply (requires missed_reply_threshold_days in Inbox Settings).
  • anniversary — contact birthdays, namedays, and other anniversaries from your contact book.
  • suggestion — AI-inferred calendar events extracted from inbound messages, awaiting confirm or dismiss.
  • file — files created since yesterday. Includes file_id, file_type, version, and updated_at.
  • work_route — active routings where the inbox created the route or is the current recipient. Includes creator progress fields such as waiting_on and recipient fields such as route_id.
Pending collaboration actions appear as type: "task" items with "pending": true — they float to the top before dated items. Includes thread assignments, @mention tasks, contact share and handoff notifications.
Active routings appear even when their due dates fall outside the requested days window, so blocked, overdue, and far-future sign-off work stays visible until the route reaches a terminal state.
Dismissing items: task items can be marked complete via PATCH /v1/tasks/{task_id}/ with {"completed": true}. suggestion items include confirm_url and dismiss_url — confirm to create the calendar event, dismiss to discard.
GET /v1/agenda/?inbox_id=&days=7 Get agenda items  scope: read
Query params
ParameterDescription
inbox_idRequired for session auth; omit for token auth.
daysWindow length in days, 1–30. Default: 7.
Response
{ "window": { "start": "2026-05-28", "end": "2026-06-04", "days": 7 }, "count": 6, "items": [ { "type": "task", "id": "<task-id>", "title": "[Assigned] Re: Partnership proposal", "date": "", "due": null, "overdue": false, "pending": true }, { "type": "task", "id": "<task-id>", "title": "Send Q2 report", "date": "2026-05-26", "due": "2026-05-26", "overdue": true, "pending": false }, { "type": "work_route", "id": "<route-id>", "title": "Approve vendor agreement", "date": "2026-06-12", "due": "2026-06-12", "status": "active", "role": "creator", "request_type": "approval", "waiting_on": 2, "completed_recipients": 1, "total_recipients": 3 }, { "type": "thread", "id": "<message-id>", "title": "Re: Partnership proposal", "date": "2026-05-27", "sent_at": "2026-05-27T09:15:00Z", "to": ["alice@example.com"] }, { "type": "anniversary", "id": "<contact-id>", "title": "Alice Smith — Birthday", "date": "2026-06-01", "contact_id": "<contact-id>", "contact_name": "Alice Smith", "anniversary_type": "birthday" }, { "type": "suggestion", "id": "<message-id>", "title": "Team standup", "date": "2026-06-02", "start": "2026-06-02T10:00:00", "duration": "PT30M", "location": "", "message_id": "<message-id>", "confirm_url": "/v1/messages/<message-id>/suggested-events/", "dismiss_url": "/v1/messages/<message-id>/suggested-events/" }, { "type": "event", "id": "<event-id>", "title": "Quarterly review", "date": "2026-06-02", "start": "2026-06-02T14:00:00", "end": "2026-06-02T15:00:00", "calendar": "Work", "location": "Conference Room B" } ] }