Français
Fils
Les routes sont relatives à <PUBLIC_BASE_URL> ; les corps de requête et de réponse sont en JSON sauf mention contraire. L’authentification, les portées, la pagination et le format des erreurs sont décrits dans les guides de l’API REST.
GET /api/v1/threads
Lister les fils
La boîte de réception, par conversation, paginée par curseur. Deux axes orthogonaux se combinent : folder (défaut inbox ; all exclut corbeille et spam) et filter (non lus, suivis, avec pièces jointes). q cherche dans le dossier courant ; searchEverywhere élargit à tous les dossiers, corbeille et spam compris. Une clé de dossier inconnue rend 400.
Accès — Session de membre ou clé d’API portant messages:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
mailboxId | requête | string | non |
cursor | requête | string | non |
limit | requête | integer | non |
q | requête | string | non |
filter | requête | "all" | "unread" | "flagged" | "attachments" | non |
folder | requête | string | non |
searchEverywhere | requête | boolean | non |
Réponses
200 — Une page de fils.
| Champ | Type | Requis |
|---|---|---|
threads | object[] | oui |
nextCursor | string | null | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"threads": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"mailboxId": { "type": "string" },
"subject": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"lastMessageAt": { "type": "string" },
"messageCount": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"unreadCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"participants": {
"maxItems": 3,
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
}
},
"participantCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"snippet": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"hasAttachments": { "type": "boolean" },
"flags": {
"type": "object",
"properties": {
"seen": { "type": "boolean" },
"flagged": { "type": "boolean" },
"draft": { "type": "boolean" },
"sent": { "type": "boolean" }
},
"required": [ "seen", "flagged", "draft", "sent" ],
"additionalProperties": false
},
"classification": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {}
}
},
"required": [
"id",
"mailboxId",
"subject",
"lastMessageAt",
"messageCount",
"unreadCount",
"participants",
"participantCount",
"snippet",
"hasAttachments",
"flags",
"classification"
],
"additionalProperties": false
}
},
"nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "threads", "nextCursor" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.bad_request. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
GET /api/v1/threads/{id}
Lire un fil
La conversation entière dans l’ordre de lecture, avec le corps assaini de chaque message. Un fil hors des boîtes du membre rend le même 404 qu’un fil inexistant.
Accès — Session de membre ou clé d’API portant messages:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string (uuid) | oui |
Réponses
200 — Le fil.
| Champ | Type | Requis |
|---|---|---|
thread | object | oui |
messages | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"thread": {
"type": "object",
"properties": {
"id": { "type": "string" },
"mailboxId": { "type": "string" },
"subject": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"lastMessageAt": { "type": "string" },
"messageCount": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"unreadCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"participants": {
"maxItems": 3,
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
}
},
"participantCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"snippet": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"hasAttachments": { "type": "boolean" },
"flags": {
"type": "object",
"properties": {
"seen": { "type": "boolean" },
"flagged": { "type": "boolean" },
"draft": { "type": "boolean" },
"sent": { "type": "boolean" }
},
"required": [ "seen", "flagged", "draft", "sent" ],
"additionalProperties": false
},
"classification": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {}
}
},
"required": [
"id",
"mailboxId",
"subject",
"lastMessageAt",
"messageCount",
"unreadCount",
"participants",
"participantCount",
"snippet",
"hasAttachments",
"flags",
"classification"
],
"additionalProperties": false
},
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"mailboxId": { "type": "string" },
"from": {
"anyOf": [
{
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"subject": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"snippet": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"receivedAt": { "type": "string" },
"folderLabels": { "type": "array", "items": { "type": "string" } },
"flags": {
"type": "object",
"properties": {
"seen": { "type": "boolean" },
"flagged": { "type": "boolean" },
"draft": { "type": "boolean" },
"sent": { "type": "boolean" }
},
"required": [ "seen", "flagged", "draft", "sent" ],
"additionalProperties": false
},
"signals": {
"type": "object",
"properties": {
"isAutoReply": { "type": "boolean" },
"isNoReply": { "type": "boolean" },
"isMailingList": { "type": "boolean" },
"isFromSelf": { "type": "boolean" }
},
"required": [ "isAutoReply", "isNoReply", "isMailingList", "isFromSelf" ],
"additionalProperties": false
},
"hasAttachments": { "type": "boolean" }
},
"required": [
"id",
"mailboxId",
"from",
"subject",
"snippet",
"receivedAt",
"folderLabels",
"flags",
"signals",
"hasAttachments"
],
"additionalProperties": false
}
}
},
"required": [ "thread", "messages" ],
"additionalProperties": false
}401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.not_found. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/threads/{id}/actions
Agir sur tout un fil
Les messages du fil sont résolus par l’instance au moment de l’appel : un message arrivé après l’affichage est inclus. Une opération par message. Un fil de 1000 messages ou plus est refusé plutôt que tronqué.
Accès — Session de membre ou clé d’API portant messages:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
action | string (enum) | oui |
labels | object | non |
clientToken | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"markRead",
"markUnread",
"flag",
"unflag",
"archive",
"unarchive",
"trash",
"restore",
"spam",
"notSpam",
"deletePermanently",
"move"
]
},
"labels": {
"type": "object",
"properties": {
"add": {
"maxItems": 20,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"remove": {
"maxItems": 20,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
}
}
},
"clientToken": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._:-]+$"
}
},
"required": [ "action", "clientToken" ]
}Réponses
202 — Les opérations enfilées.
| Champ | Type | Requis |
|---|---|---|
threadId | string | oui |
ops | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"threadId": { "type": "string" },
"ops": {
"type": "array",
"items": {
"type": "object",
"properties": {
"messageId": { "type": "string" },
"opId": { "type": "string" },
"duplicate": { "type": "boolean" }
},
"required": [ "messageId", "opId", "duplicate" ],
"additionalProperties": false
}
}
},
"required": [ "threadId", "ops" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.thread_not_found, webmail.thread_too_large, webmail.message_not_found, webmail.unsupported_action. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.