Registered mail
An electronic registered mail (LRE) is sent from a verified sender account to one or more recipients. Each recipient gets an item with its own status, timeline and legal proofs (deposit, delivery, refusal, negligence, content).
- GET
/v1/registered-mails/sender-accountsList sender accounts - POST
/v1/registered-mails/sender-accountsCreate or link a sender account - POST
/v1/registered-mails/sender-accounts/{id}/refreshRefresh the verification status - PUT
/v1/registered-mails/sender-accounts/{id}/otp-secretSet the OTP secret - GET
/v1/registered-mailsList registered mails - POST
/v1/registered-mailsCreate a registered mail draft - GET
/v1/registered-mails/optionsRetrieve the registered mail options of an entity - GET
/v1/registered-mails/{id}Retrieve a registered mail - PATCH
/v1/registered-mails/{id}Update a registered mail draft - POST
/v1/registered-mails/{id}/attachmentsAdd an attachment - GET
/v1/registered-mails/{id}/attachments/{attachmentId}Download an attachment - DELETE
/v1/registered-mails/{id}/attachments/{attachmentId}Remove an attachment - POST
/v1/registered-mails/{id}/sendSend a registered mail - POST
/v1/registered-mails/{id}/cancelCancel a registered mail draft - POST
/v1/registered-mails/{id}/items/{itemId}/retryRetry a failed item - GET
/v1/registered-mails/{id}/items/{itemId}/proofs/{kind}Download a proof - POST
/v1/registered-mails/{id}/items/{itemId}/recipient-updates/{updateId}Answer a recipient email change
Statuses
Section titled “Statuses”Each item goes through:
draft → sending → sent → deposited → delivered ├───────► refused recipient refused ├───────► neglected not accepted in time ├───────► bounced email undeliverable └───────► failed refused by the vendor (retryable if before acceptance)The mail itself has an aggregated status: draft, sending, in_progress (at least one item not final), completed (all final, none failed), partially_failed, failed, or canceled. progress counts the items per outcome.
Before sending: a verified sender account
Section titled “Before sending: a verified sender account”The sender must be identified at the vendor (the registered mail service). Sender accounts are shared by an entity; create one once (registered_mail.manage):
POST /v1/registered-mails/sender-accounts{ "entityId": "0192f3a1-7c2e-7b4d-9a61-200000000002", "mode": "create", "label": "Cabinet Bernard - LRE", "email": "claire.bernard@cabinet-bernard.fr", "firstName": "Claire", "lastName": "Bernard", "company": "Cabinet Bernard Immobilier", "kind": "professional"}mode: "link" associates an existing vendor account by email instead. The vendor then verifies the identity: verification goes from pending to verified (POST …/refresh reads it again). For qualified mail, also store the OTP secret of the account with PUT …/otp-secret (write-only).
Send a registered mail
Section titled “Send a registered mail”-
Create a draft with the recipients (50 max) and the content. Nothing is sent yet.
Terminal window curl -s -X POST "$MLT_API_URL/v1/registered-mails" \-H "Authorization: Bearer $MLT_TOKEN" -H "Content-Type: application/json" \-d '{"entityId": "0192f3a1-7c2e-7b4d-9a61-200000000002","type": "qualified","subject": "Mise en demeure - Loyers impayés Lot 12","clientReference": "DOSSIER-8841","contentHtml": "<p>Madame,</p><p>Malgré nos relances, les loyers de juillet à septembre restent impayés…</p>","senderAccountId": "0192f3a1-7c2e-7b4d-9a61-510000000001","recipients": [{ "firstName": "Marie", "lastName": "Durand", "email": "marie.durand@example.fr", "kind": "individual" }]}'const draft = await fetch(`${process.env.MLT_API_URL}/v1/registered-mails`, {method: 'POST',headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },body: JSON.stringify({entityId,type: 'qualified',subject: 'Mise en demeure - Loyers impayés Lot 12',clientReference: 'DOSSIER-8841',contentHtml: '<p>Madame,</p><p>Malgré nos relances, les loyers de juillet à septembre restent impayés…</p>',senderAccountId,recipients: [{ firstName: 'Marie', lastName: 'Durand', email: 'marie.durand@example.fr', kind: 'individual' }],}),}).then((r) => r.json());draft = requests.post(f"{api}/v1/registered-mails", headers=headers, json={"entityId": entity_id,"type": "qualified","subject": "Mise en demeure - Loyers impayés Lot 12","clientReference": "DOSSIER-8841","contentHtml": "<p>Madame,</p><p>Malgré nos relances, les loyers de juillet à septembre restent impayés…</p>","senderAccountId": sender_account_id,"recipients": [{"firstName": "Marie", "lastName": "Durand", "email": "marie.durand@example.fr", "kind": "individual"}],}).json()$draft = json_decode((string) $http->post("$api/v1/registered-mails", ['headers' => $headers,'json' => ['entityId' => $entityId,'type' => 'qualified','subject' => 'Mise en demeure - Loyers impayés Lot 12','clientReference' => 'DOSSIER-8841','contentHtml' => '<p>Madame,</p><p>Malgré nos relances, les loyers de juillet à septembre restent impayés…</p>','senderAccountId' => $senderAccountId,'recipients' => [['firstName' => 'Marie', 'lastName' => 'Durand', 'email' => 'marie.durand@example.fr', 'kind' => 'individual']],],])->getBody(), true); -
Attach PDFs one by one with
POST /v1/registered-mails/{id}/attachments(multipartfile, see Files & uploads). -
Send with an idempotency key you generate and keep for retries:
Terminal window curl -s -X POST "$MLT_API_URL/v1/registered-mails/$MAIL_ID/send" \-H "Authorization: Bearer $MLT_TOKEN" -H "Content-Type: application/json" \-d "{\"idempotencyKey\": \"$(uuidgen)\"}"import { randomUUID } from 'node:crypto';const idempotencyKey = randomUUID(); // store it with your own record, reuse it on retryconst sent = await fetch(`${process.env.MLT_API_URL}/v1/registered-mails/${draft.id}/send`, {method: 'POST',headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },body: JSON.stringify({ idempotencyKey }),}).then((r) => r.json());import uuididempotency_key = str(uuid.uuid4()) # store it with your own record, reuse it on retrysent = requests.post(f"{api}/v1/registered-mails/{draft['id']}/send", headers=headers, json={"idempotencyKey": idempotency_key}).json()$idempotencyKey = bin2hex(random_bytes(16)); // store it with your own record, reuse it on retry$sent = json_decode((string) $http->post("$api/v1/registered-mails/{$draft['id']}/send", ['headers' => $headers,'json' => ['idempotencyKey' => $idempotencyKey],])->getBody(), true);The mail moves to
sendingthenin_progress. Each item counts against the registered mail quota of the entity (403 quota_exceededwhen it is reached and blocking).
Track the recipients
Section titled “Track the recipients”Subscribe to registered_mail.delivered, registered_mail.refused, registered_mail.neglected and registered_mail.failed (webhooks): one event per item reaching a final status. GET /v1/registered-mails/{id} returns each item with its timeline (status, date, source) and proofs.
- Failed items: an item that failed before the vendor accepted it has
retryable: true; retry it alone withPOST …/items/{itemId}/retry. - Address change: a recipient can ask to receive the mail at another address. The request appears in
items[].recipientUpdateswithstatus: pending; accept or refuse it withPOST …/items/{itemId}/recipient-updates/{updateId}and{ "accept": true }.
Download the proofs
Section titled “Download the proofs”GET /v1/registered-mails/{id}/items/{itemId}/proofs/{kind} returns the PDF proof (deposit, delivery, refusal, negligence, content) once available. The SHA-256 of each stored proof is listed in items[].proofs.
Drafts
Section titled “Drafts”Until it is sent, a draft can be changed with PATCH (lists are replaced entirely), its attachments added or removed, or canceled with POST …/cancel. A sent mail cannot be canceled.