Zur Dokumentation springen
API

Kontakte

Jede Operation in dieser Gruppe: was sie annimmt, was sie zurückgibt und mit welchen Fehlern sie antworten kann.

Operationen

The address book, and it belongs to the workspace rather than to whoever saved a row. Every member and every key on the workspace reads and writes the same book.

A contact is addressed by its email address on every route here, because no id is exposed. Two things write rows: somebody saving one, in the app or through this API, which lands as manual, and a member sending mail from the app composer, which lands as auto. Mail ARRIVING from an address creates nothing, so an empty book on a busy mailbox is the expected state rather than a fault.

GET/contacts

List contacts

Geltungsbereichecontacts:readLiest

The address book belongs to the workspace, so every key on it reads the same rows and a contact saved by one member is visible to the rest.

Most recently seen first, with contacts that have never been mailed last. source is manual for an address somebody saved, in the app or through this API, and auto for one recorded because a member sent mail to it from the composer. Mail arriving from an address creates no contact.

Paging is keyset. Pass nextCursor back as cursor while hasMore is true.

Requires the contacts:read scope.

Query-Parameter

limitinteger

Rows per page, a whole number from 1 to 200. The server defaults to 50.

Mindestens 1Höchstens 200Standard50
cursorstring

The nextCursor from the previous page. Never build one yourself.

sourcestring

Narrows the page to contacts recorded that way.

Einer von"manual""auto""form"
qstring

Searches the name and the address. When nothing matches exactly on the first page, close spellings are returned instead, and the pages that follow keep matching the same way.

Bis zu 200 Zeichen

Rückgabe

Contacts in this workspace.

Fehler

Die Fehler, die jede Operation zurückgeben kann400401403404422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.list()contacts.listAll()contacts.iterate()
CLI
openemail contacts list
MCP
listContacts

POST/contacts

Create a contact

Geltungsbereichecontacts:writeÄndert Daten

The address is the identity, so there is no id to choose and no id in the response. It is trimmed and lower cased before it is stored, and the contact is saved with source set to manual.

The new contact joins the built-in default audience as it is written, and any audience named in audienceIds alongside it. Naming audiences also requires the audiences:write scope.

An address already in the book is refused rather than merged, so a retry cannot overwrite a name somebody edited in the app.

Requires the contacts:write scope.

Request-Body

emailstringErforderlich

Trimmed and lower cased before it is stored.

Bis zu 320 ZeichenFormatemail
namestring

Display name. Leave it out to save the contact without one.

Kann null seinBis zu 200 Zeichen
notesstring

Free text kept with the contact and shown beside it in the app.

Kann null seinBis zu 5000 Zeichen
audienceIdsstring[]

Audiences to put the new contact in. The default audience is joined whether or not it is named here. Sending this also requires the audiences:write scope.

Bis zu 25 Einträge

Rückgabe

Created.

Fehler

409

contact_exists: that address is already in this workspace book. PATCH it instead.

Die Fehler, die jede Operation zurückgeben kann400401403404422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.create()
CLI
openemail contacts create
MCP
createContactsaveContactupdateContact

GET/contacts/people

List people

Geltungsbereichecontacts:readLiest

Everyone on the Contacts page in the app: the saved contacts, and every address seen in mail as the sender or a recipient of a thread's newest message, with the number of threads and when mail last moved. A person seen in mail and saved is one row.

The addresses seen in mail are listed only when the key also holds threads:read, because they are read out of the mail. Without it the rows are the saved contacts alone and seen is false. A key limited to particular addresses or domains gets the saved contacts alone too, with seen false, even when it holds threads:read, because the other addresses would be read out of the mail of every address in the workspace. Deleted addresses and the mailbox's own addresses are left out.

blockedBy names the workspace blocklist rule that blocks a row, the same rule blocked=true filters on.

Requires the contacts:read scope.

Query-Parameter

limitinteger

Rows per page, 1 to 100.

Mindestens 1Höchstens 100Standard25
cursorstring

An opaque cursor from the previous page, with the same sort, q and blocked. Keyset, not offset: pass the previous page's nextCursor. One that names nothing in this list is a 400 invalid_cursor.

sortstring

recent puts the newest mail first, then saved contacts never seen in mail. name goes by name, or by address where there is none, ignoring case. threads puts the people with the most threads first.

Einer von"recent""name""threads"Standard"recent"
qstring

Searches names, addresses and notes, with close spellings when nothing matches exactly.

Bis zu 200 Zeichen
emailstring

One address only, matched case insensitively: the way to read one person's thread count and last mail.

Bis zu 320 Zeichen
blockedstring

true for only the people the workspace blocklist blocks, whole-domain rules included.

Einer von"true""false"

Rückgabe

A page of people.

Fehler

Die Fehler, die jede Operation zurückgeben kann400401403404422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.listPeople()contacts.listAllPeople()contacts.iteratePeople()
CLI
openemail contacts list-people
MCP
listPeople

POST/contacts/batch-delete

Delete contacts in bulk

Geltungsbereichecontacts:writeLöscht

Deletes up to 200 addresses in one call, each the way DELETE /contacts/{email} deletes one: a saved contact goes with its notes, photo and audience memberships, and every address is hidden, so a send does not record it again. Addresses that were only seen in mail are hidden too. An entry that is not an address comes back in invalid and the rest still go through.

Requires the contacts:write scope.

Request-Body

emailsstring[]Erforderlich

Addresses, matched case insensitively. A repeated address counts once.

1 bis 200 Einträge

Rückgabe

What was deleted.

Fehler

Die Fehler, die jede Operation zurückgeben kann400401403404422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.deleteMany()
CLI
openemail contacts delete-many
MCP
deleteContacts

GET/contacts/{email}

Retrieve a contact

Geltungsbereichecontacts:readLiest

The book is the workspace's. The address is matched case insensitively, and it is a path segment, so URL encode it: [email protected] travels as grace%40example.com.

A 404 means only that the address is not in the book. It says nothing about whether mail has been exchanged with it.

Requires the contacts:read scope.

Pfadparameter

emailstringErforderlich

The contact's address, matched case insensitively.

Rückgabe

The contact.

Fehler

Die Fehler, die jede Operation zurückgeben kann400401403404422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.get()
CLI
openemail contacts get
MCP
getContact

PATCH/contacts/{email}

Update a contact

Geltungsbereichecontacts:writeÄndert Daten

A partial update, never an upsert. An address not in the book is a 404.

The address itself cannot be changed: it is the identity and the path segment, so moving a contact to a new address is a delete and a create. source and lastSeenAt are the server's and are not accepted here.

Requires the contacts:write scope.

Pfadparameter

emailstringErforderlich

The contact's address, matched case insensitively.

Request-Body

namestring

New display name. Null clears it.

Kann null seinBis zu 200 Zeichen
notesstring

New notes. Null clears them.

Kann null seinBis zu 5000 Zeichen

Rückgabe

Saved.

Fehler

Die Fehler, die jede Operation zurückgeben kann400401403404422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.update()
CLI
openemail contacts update
MCP
createContactsaveContactupdateContact

PUT/contacts/{email}

Save a contact

Geltungsbereichecontacts:writeÄndert Daten

Saves the address the way Add to contacts and Keep in contacts do in the app. An address that is not a contact yet becomes one, answered with 201. One recorded from a send becomes manual, and one already saved keeps what it has, answered with 200. A deleted address is brought back. The body is optional.

Requires the contacts:write scope.

Pfadparameter

emailstringErforderlich

The address, trimmed and lower cased on the server.

Request-Body

namestring

Up to 200 characters. Left out, the stored name is kept.

Bis zu 200 Zeichen
notesstring

Up to 5,000 characters. null clears the notes; left out, they are kept.

Kann null seinBis zu 5000 Zeichen

Rückgabe

Already a contact, now kept as manual.

Saved as a new contact.

Fehler

422

unknown_parameter for any key but name and notes.

Die Fehler, die jede Operation zurückgeben kann400401403404500Fehlerkatalog

Auch verfügbar über

SDK
contacts.save()
CLI
openemail contacts save
MCP
createContactsaveContactupdateContact

DELETE/contacts/{email}

Delete a contact

Geltungsbereichecontacts:writeLöscht

Deletes somebody from the contacts the way Delete does in the app. A saved contact goes with its notes, its photo and every audience membership, the built-in default one included. The address is then hidden: it leaves GET /contacts/people, and mail sent to it from the app composer no longer records it. The address can be one that was only ever seen in mail.

No mail moves. Saving the address again, with POST /contacts or PUT /contacts/{email}, brings it back as a new contact.

Requires the contacts:write scope.

Pfadparameter

emailstringErforderlich

The contact's address, matched case insensitively.

Rückgabe

Deleted and hidden.

Fehler

422

invalid_contact when the path is not an address.

Die Fehler, die jede Operation zurückgeben kann400401403404500Fehlerkatalog

Auch verfügbar über

SDK
contacts.delete()
CLI
openemail contacts delete
MCP
deleteContact

PUT/contacts/{email}/photo

Set a contact photo

Geltungsbereichecontacts:writeÄndert Daten

Uploads the photo shown for the contact, replacing any there was. Send the image itself as the body, not JSON, with its type in Content-Type: image/png, image/jpeg, image/webp, image/gif. Up to 5 MB goes in. It is fitted into a 512 pixel square and stored as WebP, and an animated image keeps its first frame.

The address has to be a saved contact: save it with PUT /contacts/{email} first.

Requires the contacts:write scope.

Pfadparameter

emailstringErforderlich

The contact's address, matched case insensitively.

Request-Body

Inhaltstypimage/png, image/jpeg, image/webp, image/gif

binary

Rückgabe

The contact, with its new photoUrl.

Fehler

404

contact_not_found on email: the address is not a saved contact.

422

invalid_image when the body is not an image of an accepted type, is too large or cannot be read.

502

image_not_stored: the image was read but could not be stored. Try again.

503

image_busy: the image service is saturated. Try again shortly.

Die Fehler, die jede Operation zurückgeben kann400401403500Fehlerkatalog

Auch verfügbar über

SDK
contacts.setPhoto()
CLI
openemail contacts set-photo
MCP
setContactPhoto

DELETE/contacts/{email}/photo

Remove a contact photo

Geltungsbereichecontacts:writeLöscht

Removes the contact photo and deletes the stored image. Removing a photo from a contact that has none changes nothing.

Requires the contacts:write scope.

Pfadparameter

emailstringErforderlich

The contact's address, matched case insensitively.

Rückgabe

The contact, with photoUrl null.

Fehler

404

contact_not_found on email: the address is not a saved contact.

Die Fehler, die jede Operation zurückgeben kann400401403422500Fehlerkatalog

Auch verfügbar über

SDK
contacts.removePhoto()
CLI
openemail contacts remove-photo
MCP
removeContactPhoto

POST/contacts/{email}/block

Block a contact

Geltungsbereichesettings:writeÄndert Daten

Puts the address on the workspace blocklist, the one PATCH /settings edits as blockedSenders, so mail from it is refused from then on. A plus tag is dropped: blocking [email protected] blocks [email protected]. When a rule already blocks the address, a whole-domain one included, nothing is added and created is false. The address does not have to be a contact.

It needs settings:write, because it writes the blocklist rather than the contact.

Requires the settings:write scope.

Pfadparameter

emailstringErforderlich

The address to block.

Rückgabe

Blocked.

Fehler

422

invalid_contact when the path is not an address, blocklist_entry_too_broad when it has fewer than two letters or numbers, or the narrowed-key refusal. capability_unsupported on addressAllowlist: the blocklist belongs to the whole workspace and filters the mail of every address in it, so a key limited to particular addresses or domains cannot change it. Use a key with no address or domain restriction.

Die Fehler, die jede Operation zurückgeben kann400401403404500Fehlerkatalog

Auch verfügbar über

SDK
contacts.block()
CLI
openemail contacts block

DELETE/contacts/{email}/block

Unblock a contact

Geltungsbereichesettings:writeLöscht

Takes every workspace blocklist rule that blocks the address off the list, and lists them in removed. When one is a whole-domain rule, everybody at that domain is unblocked with it. Rules set for one address or one domain in the settings are not touched. An address no rule blocks answers with removed empty.

Requires the settings:write scope.

Pfadparameter

emailstringErforderlich

The address to unblock.

Rückgabe

Unblocked.

Fehler

422

invalid_contact when the path is not an address, or the narrowed-key refusal. capability_unsupported on addressAllowlist: the blocklist belongs to the whole workspace and filters the mail of every address in it, so a key limited to particular addresses or domains cannot change it. Use a key with no address or domain restriction.

Die Fehler, die jede Operation zurückgeben kann400401403404500Fehlerkatalog

Auch verfügbar über

SDK
contacts.unblock()
CLI
openemail contacts unblock

GET/contacts/{email}/threads

List conversations with a contact

Geltungsbereichethreads:readLiest

Every thread the address wrote or was written to, in every folder, the Mail tab on a contact in the app. The address does not have to be a saved contact. Each row is a summary of the thread; GET /threads/{id} reads the messages.

Requires the threads:read scope.

Pfadparameter

emailstringErforderlich

The address. It does not have to be a saved contact.

Query-Parameter

limitinteger

Threads per page, 1 to 100.

Mindestens 1Höchstens 100Standard25
cursorstring

The previous page's nextCursor, with the same q and sort.

qstring

Searches inside those threads, with the same syntax as the mailbox search.

Bis zu 200 Zeichen
sortstring

newest (the default), oldest, sender or subject.

Einer von"newest""oldest""sender""subject"Standard"newest"

Rückgabe

A page of threads.

Fehler

422

invalid_contact when the path is not an address, or the narrowed-key refusal. capability_unsupported on addressAllowlist: a contact's threads and activity are read from the mail of every address in the workspace, so a key limited to particular addresses or domains cannot read them. Use a key with no address or domain restriction.

Die Fehler, die jede Operation zurückgeben kann400401403404500Fehlerkatalog

Auch verfügbar über

SDK
contacts.listThreads()contacts.listAllThreads()contacts.iterateThreads()
CLI
openemail contacts list-threads

GET/contacts/{email}/activity

Read activity with a contact

Geltungsbereichethreads:readLiest

The Activity tab on a contact in the app: messages received from the address and sent to it, per bucket, over a window that ends now, with the threads that moved, the threads waiting on a reply from the mailbox, and the median time each side takes to answer. Mail in the bin or in spam is left out.

Requires the threads:read scope.

Pfadparameter

emailstringErforderlich

The address. It does not have to be a saved contact.

Query-Parameter

minutesinteger

How far back the window reaches from now. The default is 90 days.

Mindestens 1Höchstens 10540800Standard129600
grainstring

Bucket width: minute, hour or day, defaulting to day.

Einer von"minute""hour""day"Standard"day"
offsetMinutesinteger

The reader's offset from UTC in minutes, so that a day bucket falls on their calendar.

Mindestens -840Höchstens 840Standard0

Rückgabe

The activity.

Fehler

422

invalid_contact when the path is not an address, or the narrowed-key refusal. capability_unsupported on addressAllowlist: a contact's threads and activity are read from the mail of every address in the workspace, so a key limited to particular addresses or domains cannot read them. Use a key with no address or domain restriction.

Die Fehler, die jede Operation zurückgeben kann400401403404500Fehlerkatalog

Auch verfügbar über

SDK
contacts.activity()
CLI
openemail contacts activity
MCP
getContactActivity

PUT/contacts/{email}/audiences

Set a contact's audiences

Geltungsbereicheaudiences:writeÄndert Daten

Sets exactly which audiences the contact is in, the way the audience picker on a contact does in the app. The contact joins every listed audience it is not in yet and leaves every other one, in one transaction. The built-in default audience is always kept, so { "audienceIds": [] } leaves the contact in the default audience alone. Memberships it keeps also keep their addedAt.

The address is matched case insensitively and has to be a contact already. Create it with POST /contacts, which takes audienceIds too. An id that names no audience in this workspace refuses the whole call and changes nothing.

audiences:write is the only scope checked, because this writes memberships rather than the contact. Sending the same list again changes nothing, so a retry is safe.

Requires the audiences:write scope.

Pfadparameter

emailstringErforderlich

The contact's address, matched case insensitively.

Request-Body

audienceIdsstring[]Erforderlich

Every audience the contact should be in once the call returns, up to 100. The default audience is kept whether or not it is named, so an empty array leaves only the default one. A repeated id counts once.

Bis zu 100 Einträge

Rückgabe

The contact, with the audiences it is in after the change.

Fehler

404

contact_not_found on email when the address is not in the workspace book, or audience_not_found on audienceIds when an id names no audience here. Nothing is changed.

422

invalid_parameter on audienceIds for more than 100 ids, and on the entry, such as audienceIds.0, for an empty one, unknown_parameter for any other key in the body.

Die Fehler, die jede Operation zurückgeben kann400401403500Fehlerkatalog

Auch verfügbar über

SDK
contacts.setAudiences()
CLI
openemail contacts set-audiences
MCP
setContactAudiences

Objekte

Contactobject

objectstring
Einer von"contact"
emailstring

Trimmed and lower cased on write. This is the key every contact route takes, because no contact id is exposed.

namestring
Kann null sein
sourcestring

auto when a send from the app composer recorded the address, manual when somebody saved it here or in the app. A recorded send never downgrades a manual contact to auto.

Einer von"manual""auto""form"
notesstring
Kann null sein
photoUrlstring

Where the contact photo is served, or null when the contact has none. Set it with PUT /contacts/{email}/photo. A new upload gets a new URL.

Kann null sein
lastSeenAtstring

When mail last went to this address from the app composer. Null until it does.

Kann null seinFormatdate-time
createdAtstring
Formatdate-time
updatedAtstring
Formatdate-time

ContactActivityobject

objectstring
Einer von"contact_activity"
emailstring
sincestring

The start of the first bucket, on the boundary grain and offsetMinutes put it.

Formatdate-time
untilstring
Formatdate-time
grainstring
Einer von"minute""hour""day"
bucketsobject[]

Only the buckets with mail in them, oldest first.

bucketstring

The bucket in the reader's time: 2026-09-23, 2026-09-23T14 or 2026-09-23T14:05.

receivedinteger

Messages from this address.

sentinteger

Messages from the mailbox to this address.

totalsobject
receivedinteger
sentinteger
threadsinteger

Threads with at least one message in the window.

waitinginteger

Threads whose newest message is from this address, so the mailbox owes the reply.

lastReceivedAtstring
Kann null seinFormatdate-time
lastSentAtstring
Kann null seinFormatdate-time
replyTimeobject
yoursnumber

Median milliseconds the mailbox took to answer, or null without a reply to measure.

Kann null sein
theirsnumber

Median milliseconds this address took to answer.

Kann null sein

ContactBatchDeleteobject

objectstring
Einer von"contact_batch_delete"
deletedinteger

Addresses deleted and hidden, saved or not.

savedinteger

Of those, how many were saved contacts.

invalidstring[]

Entries that are not addresses, lower cased. Nothing happened to them.

ContactBlockobject

objectstring
Einer von"contact_block"
emailstring

The address as the blocklist sees it: lower cased, with any plus tag dropped.

blockedboolean
blockedByobject

On a block, the rule that now blocks the address.

Kann null sein
rulestring

The entry on the workspace blocklist that matches this address, exactly as it is stored.

liststring

blockedSenders for an address or pattern rule, blockedDomains for a rule that blocks a whole domain and every subdomain under it.

Einer von"blockedSenders""blockedDomains"
createdboolean

On a block, false when a rule already blocked the address and nothing was added.

removedobject[]

On an unblock, every rule taken off the workspace blocklist. A blockedDomains entry here unblocked the whole domain.

rulestring

The entry on the workspace blocklist that matches this address, exactly as it is stored.

liststring

blockedSenders for an address or pattern rule, blockedDomains for a rule that blocks a whole domain and every subdomain under it.

Einer von"blockedSenders""blockedDomains"

ContactDetailobject

objectstring
Einer von"contact"
emailstring

Trimmed and lower cased on write. This is the key every contact route takes, because no contact id is exposed.

namestring
Kann null sein
sourcestring

auto when a send from the app composer recorded the address, manual when somebody saved it here or in the app. A recorded send never downgrades a manual contact to auto.

Einer von"manual""auto""form"
notesstring
Kann null sein
photoUrlstring

Where the contact photo is served, or null when the contact has none. Set it with PUT /contacts/{email}/photo. A new upload gets a new URL.

Kann null sein
lastSeenAtstring

When mail last went to this address from the app composer. Null until it does.

Kann null seinFormatdate-time
createdAtstring
Formatdate-time
updatedAtstring
Formatdate-time
audiencesobject[]

Every audience this contact is in, the built-in default one included. Single-contact responses carry it; the list route does not.

idstring

The audience handle, aud_ plus 24 hex.

namestring
builtinstring

default on the one audience every contact joins, null on an audience somebody created.

Kann null seinEiner von"default"

ContactListobject

objectstring
Einer von"list"
hasMoreboolean
nextCursorstring
Kann null sein

ContactThreadobject

objectstring
Einer von"thread"
idstring

The id GET /threads/{id} takes.

subjectstring
Kann null sein
fromobject

Who sent the newest message.

Kann null sein
namestring
Kann null sein
emailstring
receivedAtstring

When the newest message arrived or went out.

Kann null sein
messageCountinteger
hasUnreadboolean
labelsobject[]
idstring
namestring

ContactThreadListobject

objectstring
Einer von"list"
hasMoreboolean

True when another page follows. Pass nextCursor back as cursor to read it.

nextCursorstring

Opaque. Pass it back as cursor for the next page, and never build one yourself.

Kann null sein

DeletedContactobject

objectstring
Einer von"contact"
emailstring
deletedboolean
Einer vontrue
wasSavedboolean

True when a saved contact was removed, false when the address was only seen in mail and has now been hidden.

Personobject

objectstring
Einer von"person"
emailstring

Lower cased. The key every contact route takes.

displayEmailstring

The address as the most recent message wrote it, which may carry capitals.

namestring

The saved name, or else the newest display name seen in mail.

Kann null sein
savedboolean

True when the address is a saved contact.

sourcestring

As on a contact, or null when the address is only seen in mail.

Kann null seinEiner von"manual""auto""form"
notesstring
Kann null sein
photoUrlstring
Kann null sein
threadsinteger

How many threads have this address as the sender or a recipient of their newest message. Null when the key does not read mail or the address has never been seen in it.

Kann null sein
lastAtstring

When the newest of those threads last moved. Null for a saved contact never seen in mail.

Kann null seinFormatdate-time
createdAtstring
Kann null seinFormatdate-time
updatedAtstring
Kann null seinFormatdate-time
blockedByobject

The workspace blocklist rule that blocks this address, or null when none does.

Kann null sein
rulestring

The entry on the workspace blocklist that matches this address, exactly as it is stored.

liststring

blockedSenders for an address or pattern rule, blockedDomains for a rule that blocks a whole domain and every subdomain under it.

Einer von"blockedSenders""blockedDomains"

PersonListobject

objectstring
Einer von"list"
hasMoreboolean

True when another page follows. Pass nextCursor back as cursor to read it.

nextCursorstring

Opaque. Pass it back as cursor for the next page, and never build one yourself.

Kann null sein
seenboolean

True when the addresses seen in mail are included, which needs threads:read. False means the rows are the saved contacts alone.