Français
Boîtes
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/mailboxes
Lister mes boîtes
Les boîtes connectées par le membre appelant, avec leur état, le nombre de messages, la date du dernier delta et celle de la dernière analyse conclue.
Accès — Session de membre ou clé d’API portant mailboxes:read.
Réponses
200 — Les boîtes.
| Champ | Type | Requis |
|---|---|---|
mailboxes | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"mailboxes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"provider": { "type": "string", "enum": [ "gmail", "msgraph", "imap" ] },
"address": { "type": "string" },
"status": { "type": "string", "enum": [ "active", "disconnected", "error" ] },
"syncMode": { "type": "string", "enum": [ "full", "processing_only" ] },
"connectedAt": { "type": "string" },
"backfill": {
"anyOf": [
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [ "pending", "running", "done", "failed" ]
},
"progressPct": {
"anyOf": [
{ "type": "number", "minimum": 0, "maximum": 100 },
{ "type": "null" }
]
},
"oldestSyncedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "status", "progressPct", "oldestSyncedAt" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"lastDeltaAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"lastSuccessfulSyncAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"lastError": {
"anyOf": [
{
"type": "object",
"properties": {
"kind": { "type": "string" },
"code": { "type": "string" },
"message": { "type": "string" },
"at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"operation": { "type": "string" },
"httpStatus": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [ "kind" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"messageCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"analyzedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [
"id",
"provider",
"address",
"status",
"syncMode",
"connectedAt",
"backfill",
"lastDeltaAt",
"lastError",
"messageCount"
],
"additionalProperties": false
}
}
},
"required": [ "mailboxes" ],
"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.
POST /api/v1/mailboxes/imap
Connecter une boîte IMAP/SMTP
Le seul fournisseur sans flux OAuth. Les deux serveurs sont éprouvés AVANT d’enregistrer quoi que ce soit, et l’échec dit lequel a refusé. Reconnecter une adresse déjà connue du membre remplace son secret au lieu de créer une seconde boîte (created: false). Le mot de passe n’apparaît dans aucune réponse ni aucun log.
Accès — Session de membre ou clé d’API portant mailboxes:write.
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
address | string | oui |
imapHost | string | oui |
imapPort | integer | non |
imapSecure | boolean | non |
smtpHost | string | oui |
smtpPort | integer | non |
smtpSecure | boolean | non |
username | string | non |
password | string | oui |
allowInvalidCertificate | boolean | non |
Schéma JSON
json
{
"type": "object",
"properties": {
"address": { "type": "string" },
"imapHost": { "type": "string", "minLength": 1, "maxLength": 255 },
"imapPort": { "default": 993, "type": "integer", "minimum": 1, "maximum": 65535 },
"imapSecure": { "default": true, "type": "boolean" },
"smtpHost": { "type": "string", "minLength": 1, "maxLength": 255 },
"smtpPort": { "default": 465, "type": "integer", "minimum": 1, "maximum": 65535 },
"smtpSecure": { "default": true, "type": "boolean" },
"username": { "type": "string", "minLength": 1, "maxLength": 255 },
"password": { "type": "string", "minLength": 1, "maxLength": 1024 },
"allowInvalidCertificate": { "type": "boolean" }
},
"required": [ "address", "imapHost", "smtpHost", "password" ]
}Réponses
201 — La boîte, connectée ou reconnectée.
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
address | string | oui |
created | boolean | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"mailboxId": { "type": "string" },
"address": { "type": "string" },
"created": { "type": "boolean" }
},
"required": [ "mailboxId", "address", "created" ],
"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 — request.bad_request, credentials.encryption_disabled, imap.host_not_found, imap.unreachable, imap.tls_failed, imap.auth_failed, smtp.host_not_found, smtp.unreachable, smtp.tls_failed, smtp.auth_failed. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
Exemple de requête
json
{
"address": "alice@example.test",
"password": "••••••••",
"imapHost": "imap.example.test",
"imapPort": 993,
"imapSecure": true,
"smtpHost": "smtp.example.test",
"smtpPort": 465,
"smtpSecure": true
}Exemple de réponse (201)
json
{
"mailboxId": "0192f1c2-3b4d-7e8f-9a0b-1c2d3e4f5a6b",
"address": "alice@example.test",
"created": true
}POST /api/v1/mailboxes/{id}/sync
Synchroniser une boîte maintenant
Demande un delta au fournisseur. enqueued: false n’est pas un échec : un delta était déjà en attente pour cette boîte. Une boîte qui n’est pas active est refusée en 409 plutôt qu’enfilée dans le vide.
Accès — Session de membre ou clé d’API portant mailboxes:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Réponses
202 — Synchronisation demandée.
| Champ | Type | Requis |
|---|---|---|
enqueued | boolean | oui |
Schéma JSON
json
{
"type": "object",
"properties": { "enqueued": { "type": "boolean" } },
"required": [ "enqueued" ],
"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.
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 — mailbox.not_found, mailbox.not_active. 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/mailboxes/{id}/resync
Rattraper une période
Relit la boîte de since à maintenant, par tranches. Idempotent (un message connu n’est pas re-téléchargé) et muet : aucune ligne de journal, aucun dispatch — on peut rejouer trois semaines sans déclencher trois semaines de réponses automatiques. since doit être dans le passé et à moins de 92 jours.
Accès — Session de membre ou clé d’API portant mailboxes:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
since | string (date-time) | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"since": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [ "since" ]
}Réponses
202 — Rattrapage demandé.
| Champ | Type | Requis |
|---|---|---|
enqueued | boolean | oui |
Même schéma que POST /api/v1/mailboxes/{id}/sync.
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 — mailbox.not_found, mailbox.resync_window_invalid, mailbox.not_active. 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/mailboxes/{id}/removal-impact
Ce que retirer une boîte emporterait
Pour le dialogue de confirmation : messages, exécutions en cours et workflows publiés qui se déclenchent sur cette boîte ou envoient depuis elle.
Accès — Session de membre ou clé d’API portant mailboxes:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Réponses
200 — L’impact.
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
address | string | oui |
messages | integer | oui |
pendingExecutions | integer | oui |
workflows | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"mailboxId": { "type": "string" },
"address": { "type": "string" },
"messages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"pendingExecutions": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"workflows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"link": { "type": "string", "enum": [ "trigger", "sender" ] }
},
"required": [ "id", "name", "link" ],
"additionalProperties": false
}
}
},
"required": [ "mailboxId", "address", "messages", "pendingExecutions", "workflows" ],
"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 — mailbox.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/mailboxes/{id}/disconnect
Déconnecter une boîte
La synchronisation s’arrête et le secret est retiré ; l’historique du miroir reste lisible. Réversible (reconnecter réactive la même boîte), donc sans confirmation. Idempotent.
Accès — Session de membre ou clé d’API portant mailboxes:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Réponses
200 — La boîte, déconnectée.
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
address | string | oui |
disarmedWorkflows | integer | oui |
credential | "deleted" | "kept" | "none" | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"mailboxId": { "type": "string" },
"address": { "type": "string" },
"disarmedWorkflows": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"credential": { "type": "string", "enum": [ "deleted", "kept", "none" ] }
},
"required": [ "mailboxId", "address", "disarmedWorkflows", "credential" ],
"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 — mailbox.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.
DELETE /api/v1/mailboxes/{id}
Supprimer une boîte et son miroir
Le geste le plus destructeur de l’instance : messages, fils, pièces jointes, journal et exécutions sont purgés, les workflows qui envoyaient depuis la boîte sont dépubliés. Le corps doit répéter l’adresse de la boîte dans confirm (insensible à la casse). Les lignes sont supprimées quand la réponse part ; les objets sont purgés de façon asynchrone.
Accès — Session de membre ou clé d’API portant mailboxes:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
confirm | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": { "confirm": { "type": "string", "minLength": 1, "maxLength": 320 } },
"required": [ "confirm" ]
}Réponses
200 — Ce qui a été supprimé.
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
address | string | oui |
deleted | object | oui |
unpublishedWorkflows | integer | oui |
credential | "deleted" | "kept" | "none" | oui |
blobsQueued | boolean | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"mailboxId": { "type": "string" },
"address": { "type": "string" },
"deleted": {
"type": "object",
"properties": {
"messages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"threads": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"attachments": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"journalEntries": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"outboundOps": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"executions": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }
},
"required": [
"messages",
"threads",
"attachments",
"journalEntries",
"outboundOps",
"executions"
],
"additionalProperties": false
},
"unpublishedWorkflows": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"credential": { "type": "string", "enum": [ "deleted", "kept", "none" ] },
"blobsQueued": { "type": "boolean" }
},
"required": [
"mailboxId",
"address",
"deleted",
"unpublishedWorkflows",
"credential",
"blobsQueued"
],
"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 — mailbox.not_found, mailbox.confirmation_mismatch. 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/journal
Lister le journal d’entrée
« Pourquoi ce mail n’a-t-il rien déclenché ? » Une entrée par message reçu avec son sort, les plus récents d’abord, paginée par curseur. mailboxId est intersecté avec les boîtes du membre, jamais substitué ; q est accepté et ignoré.
Accès — Session de membre ou clé d’API portant mailboxes: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 |
Réponses
200 — Une page d’entrées.
| Champ | Type | Requis |
|---|---|---|
entries | object[] | oui |
nextCursor | string | null | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"entries": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"mailboxId": { "type": "string" },
"providerMessageId": { "type": "string" },
"outcome": {
"type": "string",
"enum": [
"excluded_org",
"excluded_member",
"guardrail",
"unmatched",
"dispatched"
]
},
"ruleRef": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"subject": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"from": {
"anyOf": [
{
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"messageId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"threadId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"executions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"workflowId": { "type": "string" },
"workflowName": { "type": "string" }
},
"required": [ "id", "workflowId", "workflowName" ],
"additionalProperties": false
}
},
"createdAt": { "type": "string" }
},
"required": [
"id",
"mailboxId",
"providerMessageId",
"outcome",
"ruleRef",
"subject",
"from",
"messageId",
"threadId",
"executions",
"createdAt"
],
"additionalProperties": false
}
},
"nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "entries", "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/journal/stats
Compter le journal par sort
Reçus, exclus, traités… sur les boîtes du membre, ou l’une d’elles.
Accès — Session de membre ou clé d’API portant mailboxes: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 |
Réponses
200 — Les compteurs.
| Champ | Type | Requis |
|---|---|---|
byOutcome | object | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"byOutcome": {
"type": "object",
"propertyNames": {
"type": "string",
"enum": [
"excluded_org",
"excluded_member",
"guardrail",
"unmatched",
"dispatched"
]
},
"additionalProperties": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"required": [
"excluded_org",
"excluded_member",
"guardrail",
"unmatched",
"dispatched"
]
}
},
"required": [ "byOutcome" ],
"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.