{"id":29995,"date":"2026-10-25T13:14:13","date_gmt":"2026-10-25T12:14:13","guid":{"rendered":"https:\/\/www.e-signature.eu\/?page_id=29995"},"modified":"2026-10-25T21:46:57","modified_gmt":"2026-10-25T20:46:57","slug":"registered-mail-documentation-api-v3","status":"publish","type":"page","link":"https:\/\/www.e-signature.eu\/en\/eidas-registered-electronic-mail\/registered-mail-documentation-api-v3\/","title":{"rendered":"Registered mail documentation API v3"},"content":{"rendered":"<style>\n.esig-api{--ink:#1f2937;--muted:#6b7280;--line:#e5e7eb;--soft:#f8fafc;--brand:#1d4ed8;--code:#0f172a;\n font-family:inherit;color:var(--ink);line-height:1.6;max-width:1100px;margin:0 auto;font-size:16px}\n.esig-api h2{font-size:1.6em;margin:2.2em 0 .6em;padding-top:.6em;border-top:1px solid var(--line)}\n.esig-api h3{font-size:1.2em;margin:1.8em 0 .5em}\n.esig-api h4{font-size:1em;margin:1.4em 0 .4em;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}\n.esig-api p,.esig-api li{max-width:820px}\n.esig-api code{font-family:SFMono-Regular,Consolas,Menlo,monospace;font-size:.88em;background:#eef2ff;color:#1e3a8a;padding:.1em .35em;border-radius:4px;word-break:break-word}\n.esig-api pre{background:var(--code);color:#e2e8f0;padding:16px 18px;border-radius:8px;overflow-x:auto;font-size:13.5px;line-height:1.5;margin:.8em 0 1.4em}\n.esig-api pre code{background:none;color:inherit;padding:0;font-size:inherit;word-break:normal}\n.esig-api table{border-collapse:collapse;width:100%;margin:.8em 0 1.4em;font-size:.94em;display:block;overflow-x:auto}\n.esig-api th,.esig-api td{border:1px solid var(--line);padding:8px 10px;text-align:left;vertical-align:top}\n.esig-api th{background:var(--soft);font-weight:600}\n.esig-api{display:grid;grid-template-columns:230px minmax(0,1fr);gap:40px;max-width:1240px}\n.esig-api-main{min-width:0}\n.esig-api-nav{position:relative}\n.esig-api-nav-in{position:sticky;top:var(--esig-top,110px);z-index:20}\n.esig-api-nav-in.is-fixed{position:fixed}\n.esig-api-toc{max-height:calc(100vh - var(--esig-top,110px) - 20px);overflow-y:auto;background:var(--soft);border:1px solid var(--line);border-radius:8px;padding:14px 16px;font-size:.92em}\n.esig-api-toc strong{display:block;margin-bottom:.4em}\n.esig-api-toc ol{margin:0;padding-left:1.3em}.esig-api-toc li{margin:.3em 0;max-width:none}\n.esig-api-main a{color:var(--brand)!important;text-decoration:underline!important;text-underline-offset:2px;text-decoration-thickness:1px}.esig-api-main a:hover{text-decoration-thickness:2px}\n.esig-api-details{border:1px solid var(--line);border-radius:8px;padding:10px 16px;margin:.8em 0 1.4em;background:var(--soft)}.esig-api-details summary{cursor:pointer;font-weight:600;color:var(--brand)}.esig-api-details[open] summary{margin-bottom:.6em}.esig-api-details h4{margin:1em 0 .3em;text-transform:none;letter-spacing:0;color:var(--ink)}.esig-api-details ul{margin:.2em 0 .6em}\n.esig-api-toc a{text-decoration:none;color:var(--ink)}.esig-api-toc a:hover{color:var(--brand);text-decoration:underline}\n.esig-api-toc a.is-active{color:var(--brand);font-weight:600;background:#e8efff;border-radius:4px;padding:1px 5px;margin-left:-5px}.esig-api-toc li.is-active::marker{color:var(--brand);font-weight:600}\n.esig-api-toggle{position:absolute;opacity:0;pointer-events:none}\n.esig-api-toc-btn{display:none}\n.esig-api h2{scroll-margin-top:calc(var(--esig-top,110px) + 10px)}\n@media (max-width:900px){\n .esig-api{display:block}\n .esig-api-nav{margin:0 0 1.2em}\n .esig-api-nav-in{top:var(--esig-top,0px)}\n .esig-api-toc-btn{display:flex;align-items:center;justify-content:space-between;background:var(--soft);border:1px solid var(--line);border-radius:8px;padding:10px 14px;font-weight:600;cursor:pointer}\n .esig-api-toc-btn::after{content:\"\u25be\";font-size:1.1em}\n .esig-api-toggle:checked + .esig-api-toc-btn::after{content:\"\u25b4\"}\n .esig-api-toc{display:none;position:static;max-height:60vh;margin-top:6px;box-shadow:0 6px 16px rgba(0,0,0,.08);background:#fff}\n .esig-api-toc strong{display:none}\n .esig-api-toggle:checked ~ .esig-api-toc{display:block}\n .esig-api h2{scroll-margin-top:calc(var(--esig-top,0px) + 60px)}\n}\n.esig-api .ep{display:flex;flex-wrap:wrap;align-items:center;gap:10px;background:var(--soft);border:1px solid var(--line);border-radius:8px;padding:10px 14px;margin:.6em 0 1em;font-family:SFMono-Regular,Consolas,Menlo,monospace;font-size:.95em}\n.esig-api .m{font-weight:700;color:#fff;border-radius:4px;padding:2px 8px;font-size:.85em}\n.esig-api .GET{background:#059669}.esig-api .POST{background:#1d4ed8}.esig-api .PATCH{background:#d97706}.esig-api .DELETE{background:#dc2626}\n.esig-api .note{border-left:4px solid var(--brand);background:#eff6ff;padding:10px 14px;border-radius:0 6px 6px 0;margin:1em 0}\n.esig-api .warn{border-left:4px solid #d97706;background:#fffbeb;padding:10px 14px;border-radius:0 6px 6px 0;margin:1em 0}\n.esig-api .badge{display:inline-block;font-size:.75em;font-weight:700;background:#dbeafe;color:#1e40af;border-radius:999px;padding:1px 8px;margin-left:4px;vertical-align:middle}\n.esig-api .req{color:#dc2626;font-weight:700}\n<\/style>\n<div class=\"esig-api\">\n<nav class=\"esig-api-nav\" aria-label=\"Contents\">\n<div class=\"esig-api-nav-in\"><input type=\"checkbox\" id=\"esig-api-toc\" class=\"esig-api-toggle\"><label for=\"esig-api-toc\" class=\"esig-api-toc-btn\">Contents<\/label><\/p>\n<div class=\"esig-api-toc\"><strong>Contents<\/strong><\/p>\n<ol>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#overview\">Overview<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#auth\">Authentication<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#conventions\">Conventions<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#credits\">Credits<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#flow\">How a registered mail works<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#sender\">Sender address<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#request\">Send a registered mail<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#object\">The registered mail object<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#endpoints\">Other endpoints<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#callbacks\">Callbacks (webhooks)<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#errors\">Errors<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#retention\">Retention<\/a><\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/nav>\n<div class=\"esig-api-main\">\n<p style=\"color:#6b7280;margin-top:0\">e-Signature.eu REST API \u2014 electronic registered mail<\/p>\n<h2 id=\"overview\">1. Overview<\/h2>\n<p>The e-Signature.eu REST API lets your application send electronic registered mail without using our website. You send the PDF, a verified sender address and the recipient; the document receives a qualified electronic timestamp, and the recipient signs an acknowledgement of receipt after verifying his identity. You get the result back through the API or a callback.<\/p>\n<table style=\"display:table;width:100%\">\n<tbody>\n<tr>\n<td style=\"width:180px;min-width:140px;white-space:nowrap\">Base URL<\/td>\n<td><code>https:\/\/api.e-signature.eu\/v3\/regis\/<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"width:180px;min-width:140px;white-space:nowrap\">Postman<\/td>\n<td><a href=\"https:\/\/documenter.getpostman.com\/view\/10230512\/2sBYHUSKry\" target=\"_blank\" rel=\"noopener\">Postman documentation and collection<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"note\">The previous base URL <code>https:\/\/www.e-signature.eu\/wp-json\/esig\/v3\/regis\/<\/code> remains valid. We recommend using the <code>api.e-signature.eu<\/code> URL.<\/p>\n<h2 id=\"auth\">2. Authentication<\/h2>\n<p>Your credentials are available in <strong>My account &gt; Signatures API<\/strong> once you are logged in on e-signature.eu:<\/p>\n<ul>\n<li><strong>User ID<\/strong>: sent in the URL as the <code>userid<\/code> parameter of every call;<\/li>\n<li><strong>API token<\/strong>: sent in the <code>x-api-key<\/code> HTTP header of every call.<\/li>\n<\/ul>\n<pre><code>curl -X GET \"https:\/\/api.e-signature.eu\/v3\/regis\/requestBalance?userid=123\" \\\n  -H \"x-api-key: YOUR_API_TOKEN\"<\/code><\/pre>\n<p>Keep your token secret: it gives full access to your account through the API. Calls must be made from your server, never from a browser or a mobile app.<\/p>\n<h2 id=\"conventions\">3. Conventions<\/h2>\n<h3>Requests and responses<\/h3>\n<ul>\n<li>HTTPS only. Request bodies are JSON (<code>Content-Type: application\/json<\/code>).<\/li>\n<li>Every response is JSON, in one of these two forms:<\/li>\n<\/ul>\n<pre><code>{ \"success\": true,  \"result\": { ... } }\n{ \"success\": false, \"error\": \"Readable error message\" }<\/code><\/pre>\n<h3>Limits<\/h3>\n<table>\n<thead>\n<tr>\n<th>Limit<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Requests<\/td>\n<td>10 per minute per account and IP address (HTTP 403 beyond, retry after one minute)<\/td>\n<\/tr>\n<tr>\n<td>Document<\/td>\n<td>One PDF per request, 30 MB maximum, not encrypted \/ not password protected<\/td>\n<\/tr>\n<tr>\n<td>Download of signed documents<\/td>\n<td>30 days after completion (see <a href=\"#retention\">Retention<\/a>)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"credits\">4. Credits<\/h2>\n<p>Requests are paid with your prepaid e-signature.eu credits. The price of a method can be retrieved with <a href=\"#getMethods\"><code>getMethods<\/code><\/a> (it takes your specific prices into account). Your balance is returned by <a href=\"#requestBalance\"><code>requestBalance<\/code><\/a> and in every request object (<code>credits_balance<\/code>).<\/p>\n<h3 id=\"auto-recharge\">Automatic credit recharge<\/h3>\n<p>To avoid running out of credits, you can let your account recharge itself automatically. It is set up once in <strong>My account &gt; Signatures API<\/strong>, not through the API:<\/p>\n<ol>\n<li>Choose a <strong>threshold<\/strong> (in credits) and the <strong>credit pack<\/strong> to order.<\/li>\n<li>Save a payment method with our payment provider Mollie (card, or SEPA Direct Debit through Bancontact, iDEAL\u2026). A verification payment of \u20ac0.01 is requested once.<\/li>\n<li>Whenever credits are debited and your balance falls below the threshold, an order for the chosen pack is created and paid automatically with the saved payment method. The invoice is sent to you by email.<\/li>\n<\/ol>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Automatic recharge<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Trigger<\/td>\n<td>A debit of credits (e.g. a new request) that brings the balance below the threshold<\/td>\n<\/tr>\n<tr>\n<td>Credits added<\/td>\n<td>As soon as the payment is confirmed: immediately by card, after a few working days by SEPA Direct Debit<\/td>\n<\/tr>\n<tr>\n<td>Recharges in progress<\/td>\n<td>One at a time<\/td>\n<\/tr>\n<tr>\n<td>Safety limit<\/td>\n<td>A maximum number of automatic recharges per 30 days<\/td>\n<\/tr>\n<tr>\n<td>Payment failure<\/td>\n<td>The order is marked as failed, automatic recharge is turned off and you are informed by email<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"note\">The recharge is triggered by a debit. A request that costs more than your current balance is refused (HTTP 403, <code>You do not have enough credits<\/code>) and does not trigger a recharge: choose a threshold higher than the cost of your largest requests, and keep a margin when paying by SEPA Direct Debit. Your balance remains available at any time through <a href=\"#requestBalance\"><code>requestBalance<\/code><\/a> and <code>credits_balance<\/code>.<\/div>\n<h2 id=\"flow\">5. How a registered mail works<\/h2>\n<ol>\n<li>You send the PDF, a <strong>verified<\/strong> sender address and the recipient. The document receives a qualified electronic timestamp and the credits are debited.<\/li>\n<li>The recipient receives an email with two links: one to sign the acknowledgement of receipt and access the document, one to decline.<\/li>\n<li>To sign, the recipient verifies his identity with one of the accepted methods (itsme\u00ae, Evrotrust, OTP\u2026).<\/li>\n<li>The registered mail becomes <code>finished<\/code> (signed), <code>declined<\/code>, or <code>expired<\/code> if nothing happened after 14 days.<\/li>\n<\/ol>\n<p>One sender, one recipient per registered mail. As on the website, an automatic reminder is sent every 4 days (not configurable); there is no manual reminder and no cancellation.<\/p>\n<h2 id=\"sender\">6. Sender address<\/h2>\n<p>As on the website, the sender address (<code>sender_email<\/code>) must be <strong>verified<\/strong> before it can be used:<\/p>\n<ol>\n<li>Call <code>verifySender<\/code>: an email with a verification link is sent to the address (response <code>202<\/code>). If the address is already verified, the response is <code>200<\/code> with <code>\"verified\": true<\/code>.<\/li>\n<li>The owner of the address clicks the link.<\/li>\n<li>The address can then be used in <code>request<\/code>.<\/li>\n<\/ol>\n<div class=\"ep\"><span class=\"m POST\">POST<\/span><span>\/v3\/regis\/verifySender?userid={userid}<\/span><\/div>\n<pre><code>{ \"email\": \"contact@example.com\", \"lang\": \"en\" }<\/code><\/pre>\n<pre><code>{\n  \"success\": true,\n  \"result\": {\n    \"email\": \"contact@example.com\",\n    \"verified\": false,\n    \"message\": \"A verification email has been sent to contact@example.com. The address can be used as sender_email once the link in this email has been clicked.\"\n  }\n}<\/code><\/pre>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/regis\/senders?userid={userid}<\/span><\/div>\n<p>Lists the sender addresses of your account with their status.<\/p>\n<pre><code>{\n  \"success\": true,\n  \"result\": [\n    {\n      \"email\": \"contact@example.com\",\n      \"verified\": true\n    },\n    {\n      \"email\": \"legal@example.com\",\n      \"verified\": false\n    }\n  ]\n}<\/code><\/pre>\n<h2 id=\"request\">7. Send a registered mail<\/h2>\n<div class=\"ep\"><span class=\"m POST\">POST<\/span><span>\/v3\/regis\/request?userid={userid}<\/span><\/div>\n<pre><code>{\n  \"title\": \"Formal notice rent October\",\n  \"lang\": \"en\",\n  \"sender_email\": \"contact@example.com\",\n  \"recipient\": {\n    \"firstname\": \"Ann\",\n    \"lastname\": \"Peeters\",\n    \"email\": \"ann.peeters@example.com\",\n    \"phone\": \"+32475111222\"\n  },\n  \"methods\": [\n    \"itsme-qes-signature\",\n    \"evrotrust-signature\"\n  ],\n  \"send_email\": true,\n  \"note_html\": \"Please acknowledge receipt.\",\n  \"signature_redirect\": \"https:\/\/www.example.com\/thank-you\",\n  \"external_reference\": \"INV-2026-0042\",\n  \"metadata\": {\n    \"customer_id\": 311\n  },\n  \"pdf_file_base64\": \"JVBERi0xLjcKJeLjz9MK...\"\n}<\/code><\/pre>\n<table>\n<thead>\n<tr>\n<th>Field<\/th>\n<th>Required<\/th>\n<th>Type<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>title<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td>Name of the document. Letters, digits and dashes are kept; a suffix <code>-1<\/code>, <code>-2<\/code>\u2026 is added if the name already exists.<\/td>\n<\/tr>\n<tr>\n<td><code>lang<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td>Language of the emails and pages: <code>fr<\/code>, <code>nl<\/code>, <code>en<\/code>, <code>de<\/code>, <code>es<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>sender_email<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td><strong>Verified<\/strong> sender address, see <a href=\"#sender\">Sender address<\/a>.<\/td>\n<\/tr>\n<tr>\n<td><code>recipient.lastname<\/code>, <code>recipient.email<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><code>recipient.firstname<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><code>recipient.phone<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td>International format (<code>+32\u2026<\/code>). An invalid number is ignored.<\/td>\n<\/tr>\n<tr>\n<td><code>methods<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>array<\/td>\n<td>Methods accepted to sign the acknowledgement of receipt, see <a href=\"#getMethods\"><code>getMethods<\/code><\/a>.<\/td>\n<\/tr>\n<tr>\n<td><code>pdf_file_base64<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td>The PDF, base64 encoded. One file, 30 MB maximum, not encrypted.<\/td>\n<\/tr>\n<tr>\n<td><code>send_email<\/code><\/td>\n<td>no<\/td>\n<td>boolean<\/td>\n<td>Default <code>true<\/code>. With <code>false<\/code>, no email is sent to the recipient nor to the sender: send the <code>signature_link<\/code> and <code>declined_link<\/code> yourself.<\/td>\n<\/tr>\n<tr>\n<td><code>note_html<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td>Message added to the email sent to the recipient.<\/td>\n<\/tr>\n<tr>\n<td><code>signature_redirect<\/code><\/td>\n<td>no<\/td>\n<td>string (URL)<\/td>\n<td>Page shown to the recipient after signing.<\/td>\n<\/tr>\n<tr>\n<td><code>external_reference<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td>Your own identifier (invoice, file\u2026), max 255 characters.<\/td>\n<\/tr>\n<tr>\n<td><code>metadata<\/code><\/td>\n<td>no<\/td>\n<td>object<\/td>\n<td>Free JSON object, max 4 KB, returned as is.<\/td>\n<\/tr>\n<tr>\n<td><code>callback_url<\/code><\/td>\n<td>no<\/td>\n<td>string (URL)<\/td>\n<td>Callback URL for this registered mail only (public HTTPS). Default: the URL of your account.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Cost<\/h3>\n<p>Price of the most expensive method in <code>methods<\/code>, for one recipient. Debited when the registered mail is created.<\/p>\n<h3>Response <code>201 Created<\/code><\/h3>\n<pre><code>{\n  \"success\": true,\n  \"result\": {\n    \"type\": \"regis\",\n    \"id_sign\": 123,\n    \"doc_name\": \"Formal-notice-rent-October\",\n    \"lang\": \"en\",\n    \"sender_email\": \"contact@example.com\",\n    \"status_id\": \"pending\",\n    \"date_added\": \"2026-10-20 11:50:00\",\n    \"date_status\": \"2026-10-20 11:50:00\",\n    \"date_expired\": \"2026-11-03 11:50:00\",\n    \"timezone\": \"Europe\/Brussels\",\n    \"methods\": [\n      \"itsme-qes-signature\",\n      \"evrotrust-signature\"\n    ],\n    \"reminder\": 4,\n    \"last_reminder\": null,\n    \"send_email\": true,\n    \"from_api\": true,\n    \"credits\": 1,\n    \"credits_balance\": 41,\n    \"recipient\": {\n      \"firstname\": \"Ann\",\n      \"lastname\": \"Peeters\",\n      \"email\": \"ann.peeters@example.com\",\n      \"phone\": \"+32475111222\",\n      \"status\": \"pending\",\n      \"signing_time\": \"\",\n      \"signing_method\": \"\",\n      \"verified_firstname\": \"\",\n      \"verified_lastname\": \"\",\n      \"signature_link\": \"https:\/\/www.e-signature.eu\/en\/sign-regis\/?key=\u2026\",\n      \"declined_link\": \"https:\/\/www.e-signature.eu\/en\/sign-regis\/?key=\u2026\"\n    },\n    \"external_reference\": \"INV-2026-0042\",\n    \"metadata\": {\n      \"customer_id\": 311\n    }\n  }\n}<\/code><\/pre>\n<h2 id=\"object\">8. The registered mail object<\/h2>\n<p>Returned by <code>request<\/code>, <code>getRequest<\/code>, <code>modifyRecipient<\/code>, <code>delete<\/code> and sent in the callbacks. The field <code>\"type\": \"regis\"<\/code> distinguishes it from a signature request when both use the same callback URL.<\/p>\n<table>\n<thead>\n<tr>\n<th>Field<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>id_sign<\/code><\/td>\n<td>Identifier of the registered mail<\/td>\n<\/tr>\n<tr>\n<td><code>status_id<\/code><\/td>\n<td><code>pending<\/code> waiting for the recipient \u00b7 <code>finished<\/code> acknowledgement signed \u00b7 <code>declined<\/code> declined by the recipient \u00b7 <code>expired<\/code> not signed after 14 days \u00b7 <code>deleted<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>date_added<\/code>, <code>date_status<\/code>, <code>date_expired<\/code><\/td>\n<td>Creation, last status change, expiry (time zone of the registered mail)<\/td>\n<\/tr>\n<tr>\n<td><code>sender_email<\/code>, <code>lang<\/code>, <code>methods<\/code>, <code>reminder<\/code>, <code>send_email<\/code><\/td>\n<td>As defined at creation<\/td>\n<\/tr>\n<tr>\n<td><code>last_reminder<\/code><\/td>\n<td>Date of the last reminder, or <code>null<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>credits<\/code>, <code>credits_balance<\/code><\/td>\n<td>Credits of the registered mail, current balance of your account<\/td>\n<\/tr>\n<tr>\n<td><code>recipient<\/code><\/td>\n<td><code>firstname<\/code>, <code>lastname<\/code>, <code>email<\/code>, <code>phone<\/code>, <code>status<\/code>; once signed <code>signing_time<\/code>, <code>signing_method<\/code>, <code>verified_firstname<\/code>, <code>verified_lastname<\/code>; while pending <code>signature_link<\/code> and <code>declined_link<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>pdf_file_base64<\/code><\/td>\n<td>Timestamped document, once the registered mail is no longer pending<\/td>\n<\/tr>\n<tr>\n<td><code>receipt_file_base64<\/code><\/td>\n<td>Signed acknowledgement of receipt, when <code>finished<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>external_reference<\/code>, <code>metadata<\/code><\/td>\n<td>As sent at creation<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"endpoints\">9. Other endpoints<\/h2>\n<p>All endpoints take <code>userid<\/code> in the URL and <code>x-api-key<\/code> in the headers. <code>id_sign<\/code> is passed in the URL.<\/p>\n<h3 id=\"list\">List the registered mails<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/regis\/list?userid={userid}&amp;status_id=pending<\/span><\/div>\n<p><code>status_id<\/code> (optional): <code>pending<\/code>, <code>finished<\/code>, <code>declined<\/code> or <code>expired<\/code>. <code>external_reference<\/code> (optional): only the registered mails with this reference.<\/p>\n<pre><code>{\n  \"success\": true,\n  \"result\": [\n    {\n      \"id_sign\": 123,\n      \"status_id\": \"pending\",\n      \"doc_name\": \"Formal-notice-rent-October\",\n      \"date_added\": \"2026-10-20 11:50:00\",\n      \"external_reference\": \"INV-2026-0042\"\n    }\n  ]\n}<\/code><\/pre>\n<h3 id=\"getRequest\">Get a registered mail<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/regis\/getRequest?userid={userid}&amp;id_sign=123<\/span><\/div>\n<h3 id=\"modifyRecipient\">Modify the recipient<\/h3>\n<div class=\"ep\"><span class=\"m PATCH\">PATCH<\/span><span>\/v3\/regis\/modifyRecipient?userid={userid}&amp;id_sign=123<\/span><\/div>\n<pre><code>{ \"email\": \"a.peeters@example.org\", \"phone\": \"+32475333444\" }<\/code><\/pre>\n<p>Registered mail <code>pending<\/code> only. Send only the fields to change among <code>firstname<\/code>, <code>lastname<\/code>, <code>email<\/code>, <code>phone<\/code>. If the email changes, the previous recipient is informed that the registered mail is cancelled for him and the new recipient receives it.<\/p>\n<h3 id=\"delete\">Delete a registered mail<\/h3>\n<div class=\"ep\"><span class=\"m DELETE\">DELETE<\/span><span>\/v3\/regis\/delete?userid={userid}&amp;id_sign=123<\/span><\/div>\n<p>Status <code>finished<\/code>, <code>declined<\/code> or <code>expired<\/code> only. Deletes the files and the history; the response contains the registered mail one last time (<code>status_id: deleted<\/code>): download the documents before deleting.<\/p>\n<h3 id=\"requestAuditTrail\">Download the audit trail<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/regis\/requestAuditTrail?userid={userid}&amp;id_sign=123<\/span><\/div>\n<p>Not available while pending. Returns the registered mail with <code>audit_trail_base64<\/code>: a timestamped PDF with the full history.<\/p>\n<h3 id=\"requestBalance\">Get the credit balance<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/regis\/requestBalance?userid={userid}<\/span><\/div>\n<h3 id=\"getMethods\">List the methods<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/regis\/getMethods?userid={userid}&amp;lang=en<\/span><\/div>\n<p>Methods accepted in <code>methods<\/code> for registered mail, with the price <strong>for your account<\/strong>. The list can differ from the one of the signatures API.<\/p>\n<pre><code>{\n  \"success\": true,\n  \"result\": [\n    {\n      \"id\": \"itsme-qes-signature\",\n      \"label\": \"itsme\u00ae | QES\",\n      \"credits\": 1\n    },\n    {\n      \"id\": \"otp-email-non-qualified\",\n      \"label\": \"OTP by Email\/SMS | SES\",\n      \"credits\": 0.4\n    }\n  ]\n}<\/code><\/pre>\n<h2 id=\"callbacks\">10. Callbacks (webhooks)<\/h2>\n<p>Define your callback URL in <strong>My account &gt; Signatures API<\/strong> (HTTPS, publicly reachable). You can also set a <code>callback_url<\/code> per request. The callback is a <code>POST<\/code> with a JSON body containing the full current state of the request (same format as <code>getRequest<\/code>), sent for requests created through the API.<\/p>\n<h3>Event fields<\/h3>\n<table>\n<thead>\n<tr>\n<th>Field<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>event<\/code><\/td>\n<td>Event type (see below)<\/td>\n<\/tr>\n<tr>\n<td><code>event_id<\/code><\/td>\n<td>Unique identifier of the event (<code>evt_\u2026<\/code>). <strong>Identical on every retry<\/strong> of the same event: use it to ignore duplicates.<\/td>\n<\/tr>\n<tr>\n<td><code>event_at<\/code><\/td>\n<td>Date of the event (UTC, ISO 8601)<\/td>\n<\/tr>\n<tr>\n<td><code>changes<\/code><\/td>\n<td>Recipient status change, e.g. <code>[{\"signer_key\": 1, \"from\": \"pending\", \"to\": \"signed\"}]<\/code> (only when a signer changed)<\/td>\n<\/tr>\n<tr>\n<td><code>changes<\/code> (<code>signer.email_failed<\/code>)<\/td>\n<td>Undelivered email, e.g. <code>[{\"signer_key\": 2, \"email\": \"marc.dubois@example.com\", \"bounce_type\": \"permanent\", \"reason\": \"smtp; 550 5.1.1 user unknown\"}]<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>external_reference<\/code>, <code>metadata<\/code><\/td>\n<td>As sent when the request was created<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Event types<\/h3>\n<table>\n<thead>\n<tr>\n<th>Event<\/th>\n<th>When<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>signer.signed<\/code><\/td>\n<td>A signer signed, the request is still in progress<\/td>\n<\/tr>\n<tr>\n<td><code>signer.declined<\/code>, <code>signer.skipped<\/code>, <code>signer.expired<\/code><\/td>\n<td>A signer declined, was skipped or expired<\/td>\n<\/tr>\n<tr>\n<td><code>request.completed<\/code><\/td>\n<td>All signers signed: the signed PDF is included (<code>pdf_file_base64<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>request.stopped<\/code><\/td>\n<td>The request was stopped: the partially signed PDF is included<\/td>\n<\/tr>\n<tr>\n<td><code>request.cancelled<\/code><\/td>\n<td>The request was cancelled<\/td>\n<\/tr>\n<tr>\n<td><code>request.deleted<\/code><\/td>\n<td>The request was deleted<\/td>\n<\/tr>\n<tr>\n<td><code>request.expired<\/code><\/td>\n<td>The request expired<\/td>\n<\/tr>\n<tr>\n<td><code>request.declined<\/code><\/td>\n<td>Registered mail declined by the recipient<\/td>\n<\/tr>\n<tr>\n<td><code>signer.email_failed<\/code><\/td>\n<td>An email sent to a signer could not be delivered, see <a href=\"#undelivered\">Undelivered emails<\/a><\/td>\n<\/tr>\n<tr>\n<td><code>request.updated<\/code><\/td>\n<td>Any other change: reminder sent, signer modified, new signing links\u2026<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The body always contains the full current state: your integration can rely on <code>status_id<\/code> and on the status of each signer rather than on the event type alone.<\/p>\n<h3 id=\"undelivered\">Undelivered emails<\/h3>\n<p>When an email sent by e-Signature.eu to a signer (or to the recipient of a registered mail) is returned by his mail server (unknown address, mailbox full, server refusing the message\u2026), you receive the callback <code>signer.email_failed<\/code>. The status of the request and of the signer does not change.<\/p>\n<table>\n<thead>\n<tr>\n<th>Field of <code>changes<\/code><\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>signer_key<\/code><\/td>\n<td>Key of the signer in <code>signers<\/code> (always 1 for a registered mail)<\/td>\n<\/tr>\n<tr>\n<td><code>email<\/code><\/td>\n<td>Address in error<\/td>\n<\/tr>\n<tr>\n<td><code>bounce_type<\/code><\/td>\n<td><code>permanent<\/code>: the address does not exist or refuses messages \u00b7 <code>transient<\/code>: temporary problem (mailbox full, server unavailable), delivery abandoned after several attempts \u00b7 <code>undetermined<\/code>: unknown reason<\/td>\n<\/tr>\n<tr>\n<td><code>reason<\/code><\/td>\n<td>Technical message of the recipient&#8217;s mail server, when available<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Correct the address with <code>modifySigner<\/code> (signature request) or <code>modifyRecipient<\/code> (registered mail): the invitation is sent to the new address, and no cancellation email is sent to the address in error. The account owner is also informed by email, and the signer is marked <strong>Email not delivered<\/strong> in the online dashboard.<\/p>\n<p><code>permanent<\/code>: no more emails are sent to this address for this request (reminders included) until it is corrected. <code>transient<\/code> or <code>undetermined<\/code>: emails are not blocked; the next reminder is sent normally and, if it fails again, you receive a new <code>signer.email_failed<\/code> callback.<\/p>\n<p class=\"note\">Only pending requests and signers who have not signed yet are concerned. With <code>send_email: false<\/code>, e-Signature.eu sends no email to the signers, so this event does not occur.<\/p>\n<h3>Headers<\/h3>\n<table>\n<thead>\n<tr>\n<th>Header<\/th>\n<th>Example<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>X-Esig-Api-Version<\/code><\/td>\n<td><code>3<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>X-Esig-Event<\/code><\/td>\n<td><code>signer.signed<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>X-Esig-Event-Id<\/code><\/td>\n<td><code>evt_4f0c2b9e1d7a3c55e8b1a2f0<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>X-Esig-Delivery-Attempt<\/code><\/td>\n<td><code>1<\/code>, <code>2<\/code>, \u2026<\/td>\n<\/tr>\n<tr>\n<td><code>X-Esig-Signature<\/code><\/td>\n<td><code>t=1792407600,v1=5d41402abc4b2a76b9719d911017c592\u2026<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Verifying the signature<\/h3>\n<p>Your signing secret is shown in <strong>My account &gt; Signatures API<\/strong>, where it can also be regenerated. <code>v1<\/code> is the HMAC-SHA256 of <code>\"&lt;t&gt;.&lt;raw request body&gt;\"<\/code> with your secret, hex encoded. Use the <strong>raw<\/strong> body, before any JSON parsing, and reject callbacks older than 5 minutes.<\/p>\n<h4>PHP<\/h4>\n<pre><code>$body   = file_get_contents( 'php:\/\/input' );\n$header = $_SERVER['HTTP_X_ESIG_SIGNATURE'] ?? '';\npreg_match( '\/t=(\\d+),v1=([a-f0-9]{64})\/', $header, $m );\n$valid = $m\n    &amp;&amp; abs( time() - (int) $m[1] ) &lt;= 300\n    &amp;&amp; hash_equals( hash_hmac( 'sha256', $m[1] . '.' . $body, $secret ), $m[2] );<\/code><\/pre>\n<h4>Node.js<\/h4>\n<pre><code>const crypto = require('crypto');\nfunction verify(rawBody, header, secret) {\n  const m = \/t=(\\d+),v1=([a-f0-9]{64})\/.exec(header || '');\n  if (!m || Math.abs(Date.now() \/ 1000 - Number(m[1])) &gt; 300) return false;\n  const expected = crypto.createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex');\n  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));\n}<\/code><\/pre>\n<h4>C# (.NET)<\/h4>\n<pre><code>using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions;\nstatic bool Verify(string rawBody, string header, string secret) {\n    var m = Regex.Match(header ?? \"\", @\"t=(\\d+),v1=([a-f0-9]{64})\");\n    if (!m.Success || Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(m.Groups[1].Value)) &gt; 300) return false;\n    using var h = new HMACSHA256(Encoding.UTF8.GetBytes(secret));\n    var expected = Convert.ToHexString(h.ComputeHash(Encoding.UTF8.GetBytes(m.Groups[1].Value + \".\" + rawBody))).ToLowerInvariant();\n    return CryptographicOperations.FixedTimeEquals(Encoding.ASCII.GetBytes(expected), Encoding.ASCII.GetBytes(m.Groups[2].Value));\n}<\/code><\/pre>\n<h3>Responses and retries<\/h3>\n<ul>\n<li>Reply with <strong>HTTP 2xx<\/strong> as soon as the callback is received, and process it asynchronously if needed.<\/li>\n<li>On network error, timeout (30 s), HTTP 429 or 5xx, the callback is sent again every hour with the same <code>event_id<\/code>, up to 24 attempts. Other 4xx answers are considered final. If the request changes again before a successful delivery, the next callback carries a new event and the full current state. The current state remains available at any time through <code>getRequest<\/code>.<\/li>\n<li>Redirects are followed (the <code>POST<\/code> method is kept). <code>localhost<\/code> and private addresses can not be used.<\/li>\n<\/ul>\n<p>For registered mail, the callback is sent when the acknowledgement is signed, declined or expired, at each automatic reminder and when the recipient is modified (on the website or through the API). The recipient is <code>signer_key<\/code> 1 in <code>changes<\/code>.<\/p>\n<h2 id=\"errors\">11. Errors<\/h2>\n<p>Errors are returned with <code>\"success\": false<\/code> and a readable <code>error<\/code> message. Rely on the HTTP code for your logic: messages may be improved over time.<\/p>\n<table>\n<thead>\n<tr>\n<th>HTTP code<\/th>\n<th>Meaning<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>200 \/ 201 \/ 202<\/td>\n<td>OK \/ registered mail created \/ verification email sent<\/td>\n<\/tr>\n<tr>\n<td>400<\/td>\n<td>Missing or invalid field (the message names the field)<\/td>\n<\/tr>\n<tr>\n<td>401<\/td>\n<td>Invalid <code>userid<\/code> or <code>x-api-key<\/code><\/td>\n<\/tr>\n<tr>\n<td>403<\/td>\n<td>Not enough credits, or request limit reached (10 per minute)<\/td>\n<\/tr>\n<tr>\n<td>404<\/td>\n<td>Missing <code>id_sign<\/code>, or unknown for this account<\/td>\n<\/tr>\n<tr>\n<td>412<\/td>\n<td>Action not possible in the current state (sender address not verified, wrong status)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"retention\">12. Retention<\/h2>\n<p>The timestamped document and the signed acknowledgement of receipt can be downloaded for <strong>30 days<\/strong>, through <code>getRequest<\/code> or the callback. The audit trail is kept for the period defined in our <a href=\"https:\/\/www.e-signature.eu\/en\/dpa\/\">DPA<\/a>. Archive the documents on your side within 30 days.<\/p>\n<\/div>\n<\/div>\n<p><script data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\" data-cfasync=\"false\" nowprocket>\n(function(){\n  var root=document.querySelector('.esig-api'); if(!root) return;\n  var nav=root.querySelector('.esig-api-nav'), box=root.querySelector('.esig-api-nav-in');\n  function headerBottom(){\n    \/* empile les \u00e9l\u00e9ments fixes du haut (barre d'admin WordPress, en-t\u00eate collant\u2026) *\/\n    var b=0, xs=[Math.round(window.innerWidth\/2), 40, window.innerWidth-40];\n    for(var k=0; k<6; k++){\n      var y=b+2, found=0;\n      xs.forEach(function(x){\n        (document.elementsFromPoint?document.elementsFromPoint(x,y):[]).forEach(function(el){\n          for(var n=el; n; n=n.parentElement){\n            if(n===document.body||n===document.documentElement||n===root) break;\n            var p=getComputedStyle(n).position;\n            if(p==='fixed'||p==='sticky'){\n              var r=n.getBoundingClientRect();\n              if(r.top<=y){ if(r.bottom>b){ if(r.bottom<window.innerHeight\/2){ b=r.bottom; found=1; } } }\n              break;\n            }\n          }\n        });\n      });\n      if(!found) break;\n    }\n    return Math.round(b);\n  }\n  \/* section en cours de lecture surlign\u00e9e dans le sommaire *\/\n  var toc=root.querySelector('.esig-api-toc'), links=[].slice.call(root.querySelectorAll('.esig-api-toc a'));\n  var heads=links.map(function(a){ return document.getElementById((a.getAttribute('href')||'').slice(1)); });\n  var current=-1;\n  function spy(top){\n    var cur=0;\n    var line=top+(window.innerHeight-top)*0.3; \/* titre pass\u00e9 au-dessus du premier tiers de l'\u00e9cran *\/\n    heads.forEach(function(h,i){ if(h){ if(h.getBoundingClientRect().top<=line) cur=i; } });\n    if(window.innerHeight+window.scrollY>=document.documentElement.scrollHeight-2) cur=links.length-1;\n    if(cur===current) return;\n    current=cur;\n    links.forEach(function(a,i){ a.classList.toggle('is-active',i===cur); a.parentNode.classList.toggle('is-active',i===cur); });\n    var a=links[cur];\n    if(a){ if(toc.scrollHeight>toc.clientHeight){\n      var y=a.getBoundingClientRect().top-toc.getBoundingClientRect().top+toc.scrollTop;\n      if(y<toc.scrollTop+20) toc.scrollTop=y-20;\n      else if(y>toc.scrollTop+toc.clientHeight-40) toc.scrollTop=y-toc.clientHeight+40;\n    } }\n  }\n  function reset(){box.classList.remove('is-fixed');box.style.left=box.style.width=box.style.top='';nav.style.minHeight='';}\n  var ticking=false;\n  function update(){\n    ticking=false;\n    var mobile=window.innerWidth<=900, gap=mobile?0:20, top=headerBottom()+gap;\n    root.style.setProperty('--esig-top',top+'px');\n    spy(top);\n    reset();\n    var n=nav.getBoundingClientRect(), b=box.getBoundingClientRect(), end=root.getBoundingClientRect().bottom;\n    if(n.top>=top) return;                       \/* pas encore atteint : position normale *\/\n    if(mobile) nav.style.minHeight=b.height+'px'; \/* garde la place du bouton *\/\n    var y=Math.min(top, end-b.height);           \/* s'arr\u00eate en bas de la documentation *\/\n    box.classList.add('is-fixed'); box.style.top=y+'px'; box.style.left=n.left+'px'; box.style.width=n.width+'px';\n    \/* parent avec transform (animations Elementor\u2026) : position:fixed relative \u00e0 ce parent \u2192 correction *\/\n    var f=box.getBoundingClientRect(), dy=f.top-y, dx=f.left-n.left;\n    if(Math.abs(dy)>1||Math.abs(dx)>1){ box.style.top=(y-dy)+'px'; box.style.left=(n.left-dx)+'px'; }\n  }\n  function req(){ if(!ticking){ticking=true;requestAnimationFrame(update);} }\n  window.addEventListener('scroll',req,{passive:true}); window.addEventListener('resize',req);\n  document.addEventListener('change',function(e){ if(e.target){ if(e.target.id==='esig-api-toc') req(); } });\n  update(); window.addEventListener('load',update); setTimeout(update,1500);\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Contents Contents Overview Authentication Conventions Credits How a registered mail works Sender address Send a registered mail The registered mail&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":24184,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-29995","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/29995","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/comments?post=29995"}],"version-history":[{"count":1,"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/29995\/revisions"}],"predecessor-version":[{"id":29996,"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/29995\/revisions\/29996"}],"up":[{"embeddable":true,"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/24184"}],"wp:attachment":[{"href":"https:\/\/www.e-signature.eu\/en\/wp-json\/wp\/v2\/media?parent=29995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}