{"id":29094,"date":"2026-10-19T18:56:35","date_gmt":"2026-10-19T16:56:35","guid":{"rendered":"https:\/\/staging.e-signature.eu\/?page_id=29094"},"modified":"2026-10-21T22:21:30","modified_gmt":"2026-10-21T20:21:30","slug":"documentation-v3","status":"publish","type":"page","link":"https:\/\/staging.e-signature.eu\/en\/api-electronic-signature\/documentation-v3\/","title":{"rendered":"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 signature request works<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#request\">Create a signature request<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#placement\">Signature placement<\/a><\/li>\n<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#object\">The signature request 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<li><a onclick=\"var t=document.getElementById('esig-api-toc');if(t)t.checked=false;\" href=\"#changelog\">Changelog<\/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 signatures (SES, AES, QES)<\/p>\n<h2 id=\"overview\">1. Overview<\/h2>\n<p>The e-Signature.eu REST API lets your application send documents for electronic signature (simple SES, advanced AES or qualified QES under eIDAS) without using our website. You send the PDF and the signers; we handle the identity verification, the signature and the follow-up; you get the signed document 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\/signature\/<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This documentation describes API <span class=\"badge\">v3<\/span>. Already using API <span class=\"badge\">v2<\/span> (<code>https:\/\/api.e-signature.eu\/v2\/signature\/<\/code>)? See the <a href=\"#changelog\">Changelog<\/a>.<\/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\/signature\/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 signature request works<\/h2>\n<ol>\n<li>You create the request with the PDF, the signers and the accepted signing methods. The credits are debited.<\/li>\n<li>Each signer receives an email with a personal signing link (or you send the <code>signature_link<\/code> yourself when <code>send_email<\/code> is <code>false<\/code>).<\/li>\n<li>The signer verifies his identity with one of the accepted methods (itsme\u00ae, Evrotrust, Veriff, OTP\u2026) and signs.<\/li>\n<li>When everybody signed, the request is <code>finished<\/code>: the signed PDF (PAdES) is available through <code>getRequest<\/code> and sent in the callback.<\/li>\n<\/ol>\n<h3>Signing order<\/h3>\n<p>By default all signers sign in parallel. To define an order, set <code>sign_first: true<\/code> on the signers of the <strong>first group<\/strong>: they are invited immediately, possibly several of them in parallel. The other signers are invited only when the whole first group has signed. Two groups at most.<\/p>\n<h3>Two integration modes<\/h3>\n<table>\n<thead>\n<tr>\n<th>Mode<\/th>\n<th>How it works<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Email mode<\/strong> (<code>send_email: true<\/code>, default)<\/td>\n<td>We send the signing invitations, reminders and completion emails to the signers on your behalf.<\/td>\n<\/tr>\n<tr>\n<td><strong>Embedded mode<\/strong> (<code>send_email: false<\/code>)<\/td>\n<td>No email is sent when the request is created: the <code>signature_link<\/code> of each signer is returned in the response, and you redirect your users to it from your own interface.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"note\">Even with <code>send_email: false<\/code>, a reminder or a cancellation triggered from the online dashboard sends an email to the pending signers.<\/div>\n<h3>Do not poll the API<\/h3>\n<p>Do not call <code>getRequest<\/code> repeatedly to follow the status of a request: rely on the <a href=\"#callbacks\">callbacks<\/a>, sent automatically at each change. Excessive calls trigger an automatic throttling that temporarily suspends the processing of your requests.<\/p>\n<h2 id=\"request\">6. Create a signature request<\/h2>\n<div class=\"ep\"><span class=\"m POST\">POST<\/span><span>\/v3\/signature\/request?userid={userid}<\/span><\/div>\n<pre><code>{\n  \"title\": \"Sales agreement 2026-114\",\n  \"lang\": \"en\",\n  \"methods\": [\n    \"itsme-qes-signature\",\n    \"evrotrust-signature\"\n  ],\n  \"signature_place\": \"position_auto\",\n  \"reminder\": 3,\n  \"send_email\": true,\n  \"email_notification\": false,\n  \"note_html\": \"Please sign the agreement before Friday.\",\n  \"signature_redirect\": \"https:\/\/www.example.com\/thank-you\",\n  \"external_reference\": \"QUOTE-2026-114\",\n  \"metadata\": {\n    \"crm_deal_id\": 8812\n  },\n  \"callback_url\": \"https:\/\/erp.example.com\/hooks\/esignature\",\n  \"signers\": [\n    {\n      \"firstname\": \"Ann\",\n      \"lastname\": \"Peeters\",\n      \"email\": \"ann.peeters@example.com\",\n      \"phone\": \"+32475111222\",\n      \"sign_first\": true\n    },\n    {\n      \"firstname\": \"Marc\",\n      \"lastname\": \"Dubois\",\n      \"email\": \"marc.dubois@example.com\",\n      \"sign_first\": false\n    }\n  ],\n  \"pdf_file_base64\": \"JVBERi0xLjcKJeLjz9MK...\"\n}<\/code><\/pre>\n<h3 id=\"methods\">Signing methods<\/h3>\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Level<\/th>\n<th>Coverage<\/th>\n<th>Price<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>itsme-qes-signature<\/code> \u2014 itsme\u00ae<\/td>\n<td>QES (qualified)<\/td>\n<td>32 European countries<\/td>\n<td>1 credit \/ signer<\/td>\n<\/tr>\n<tr>\n<td><code>evrotrust-signature<\/code> \u2014 Evrotrust<\/td>\n<td>QES (qualified)<\/td>\n<td>69 countries<\/td>\n<td>1 credit \/ signer<\/td>\n<\/tr>\n<tr>\n<td><code>veriff-advanced-signature<\/code> \u2014 Veriff<\/td>\n<td>AES (advanced)<\/td>\n<td>198 countries<\/td>\n<td>0.7 credit \/ signer<\/td>\n<\/tr>\n<tr>\n<td><code>otp-email-non-qualified<\/code> \u2014 OTP by email or SMS<\/td>\n<td>SES (simple)<\/td>\n<td>Worldwide<\/td>\n<td>0.4 credit \/ signer<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Prices are the standard prices: <a href=\"#getMethods\"><code>getMethods<\/code><\/a> returns the methods available and the prices for your account. Only a qualified electronic signature (QES) is legally equivalent to a handwritten signature under the eIDAS Regulation. <code>otp-email-non-qualified<\/code> covers both email and SMS: the code is sent by SMS when the signer has a <code>phone<\/code>, otherwise by email, at the same price.<\/p>\n<h3>Body fields<\/h3>\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 in your account.<\/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 signing pages: <code>fr<\/code>, <code>nl<\/code>, <code>en<\/code>, <code>de<\/code>, <code>es<\/code>.<\/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>Accepted signing methods, see <a href=\"#methods\">Signing methods<\/a>. When several are accepted, each signer chooses.<\/td>\n<\/tr>\n<tr>\n<td><code>signers<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>array<\/td>\n<td>Signers, see below.<\/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>signature_place<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td><code>position_auto<\/code> (default) or <code>position_manual<\/code>, see <a href=\"#placement\">Signature placement<\/a>.<\/td>\n<\/tr>\n<tr>\n<td><code>reminder<\/code><\/td>\n<td>no<\/td>\n<td>number<\/td>\n<td>Automatic reminder every N days, 0 to 14. Default 0 (no reminder).<\/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> (email mode). With <code>false<\/code> (embedded mode), no invitation nor completion email is sent: send the <code>signature_link<\/code> yourself. Can not be combined with <code>sign_first: true<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>email_notification<\/code><\/td>\n<td>no<\/td>\n<td>boolean<\/td>\n<td>Default <code>false<\/code>. With <code>true<\/code>, you receive an email at each signature.<\/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 emails sent to the signers (email mode). HTML tags are accepted, e.g. <code>Note with &lt;strong&gt;HTML&lt;\/strong&gt;<\/code>.<\/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 signer after signing. Must be a valid URL (empty strings are refused). Default: confirmation page on e-signature.eu.<\/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 (quote, contract\u2026), max 255 characters. Returned in every response and callback.<\/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 request only (public HTTPS). Default: the URL of your account.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Signer fields<\/h3>\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>lastname<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><code>email<\/code><\/td>\n<td><span class=\"req\">yes<\/span><\/td>\n<td>string<\/td>\n<td>Valid email address<\/td>\n<\/tr>\n<tr>\n<td><code>firstname<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><code>phone<\/code><\/td>\n<td>no<\/td>\n<td>string<\/td>\n<td>International format starting with <code>+<\/code> and the country code (<code>+32\u2026<\/code>); spaces are removed. An invalid number is ignored. With the OTP method, the code is sent by SMS when a phone number is given, otherwise by email.<\/td>\n<\/tr>\n<tr>\n<td><code>sign_first<\/code><\/td>\n<td>no<\/td>\n<td>boolean<\/td>\n<td>Default <code>false<\/code>. See <a href=\"#flow\">Signing order<\/a>.<\/td>\n<\/tr>\n<tr>\n<td><code>sign_page<\/code>, <code>sign_left<\/code>, <code>sign_bottom<\/code><\/td>\n<td>with <code>position_manual<\/code><\/td>\n<td>number<\/td>\n<td>See <a href=\"#placement\">Signature placement<\/a>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Cost<\/h3>\n<p>Price of the most expensive method in <code>methods<\/code> \u00d7 number of signers. The credits are debited when the request is created. Credits of signers who did not sign are refunded when the request is cancelled or stopped.<\/p>\n<h3>Response <code>201 Created<\/code><\/h3>\n<pre><code>{\n  \"success\": true,\n  \"result\": {\n    \"id_sign\": 4521,\n    \"lang\": \"en\",\n    \"doc_name\": \"Sales-agreement-2026-114\",\n    \"send_email\": true,\n    \"from_api\": true,\n    \"signature_redirect\": \"https:\/\/www.example.com\/thank-you\",\n    \"status_id\": \"pending\",\n    \"date_status\": \"2026-10-20 10:15:02\",\n    \"last_reminder\": null,\n    \"timezone\": \"Europe\/Brussels\",\n    \"credits\": 2,\n    \"credits_balance\": 38.4,\n    \"signers\": {\n      \"1\": {\n        \"firstname\": \"Ann\",\n        \"lastname\": \"Peeters\",\n        \"email\": \"ann.peeters@example.com\",\n        \"phone\": \"+32475111222\",\n        \"sign_first\": true,\n        \"status\": \"pending\",\n        \"signature_link\": \"https:\/\/www.e-signature.eu\/en\/sign\/?key=\u2026\"\n      },\n      \"2\": {\n        \"firstname\": \"Marc\",\n        \"lastname\": \"Dubois\",\n        \"email\": \"marc.dubois@example.com\",\n        \"sign_first\": false,\n        \"status\": \"pending\",\n        \"signature_link\": \"https:\/\/www.e-signature.eu\/en\/sign\/?key=\u2026\"\n      }\n    },\n    \"external_reference\": \"QUOTE-2026-114\",\n    \"metadata\": {\n      \"crm_deal_id\": 8812\n    }\n  }\n}<\/code><\/pre>\n<h2 id=\"placement\">7. Signature placement<\/h2>\n<h3><code>position_auto<\/code> (default)<\/h3>\n<p>Place the markers <code>#SIG01<\/code>, <code>#SIG02<\/code>\u2026 (also accepted: <code>#SIG01#<\/code>) as text in your document, where each signer must sign (<code>#SIG01<\/code> = first signer of the <code>signers<\/code> array). The signature is placed at the top left of the marker. If the same marker appears several times, its first occurrence is used. A marker is skipped when its signature area would overlap a signature already placed (or an existing signature): the signer then takes the next free marker. A marker so close to the page edge that the signature has to be moved is only used as a last resort.<\/p>\n<div class=\"note\">Tip: write the markers in <strong>white text<\/strong> (on a white background) so that they are invisible in the signed PDF. They must remain real text, not an image, to be detected.<\/div>\n<h4>Document not signed yet<\/h4>\n<p>If the document contains no marker, or if the marker of a signer is missing, a <strong>signature page containing the markers<\/strong> is added at the end of the document and all signatures are placed on this page (6 signers on the first added page, then 10 per additional page).<\/p>\n<h4>Document already signed<\/h4>\n<p>No page can be added to a PDF that is already signed electronically: it would invalidate the existing signatures. With <code>position_auto<\/code>, the signatures are placed on the <strong>free markers<\/strong>, i.e. the markers whose signature area does not cover an existing signature. Free markers are assigned to the signers in order (<code>#SIG01<\/code>, <code>#SIG02<\/code>\u2026).<\/p>\n<div class=\"warn\">If the signed document does not contain enough free markers for all signers, the request is refused (HTTP 400): use <code>position_manual<\/code>.<\/div>\n<h3><code>position_manual<\/code><\/h3>\n<p>Give the position of each signature, in centimetres, for each signer:<\/p>\n<table>\n<thead>\n<tr>\n<th>Field<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>sign_page<\/code><\/td>\n<td>Page number, starting at 1 (integer)<\/td>\n<\/tr>\n<tr>\n<td><code>sign_left<\/code><\/td>\n<td>Distance from the left edge of the page to the left of the signature, in cm (decimals allowed)<\/td>\n<\/tr>\n<tr>\n<td><code>sign_bottom<\/code><\/td>\n<td>Distance from the bottom edge of the page to the top of the signature, in cm (decimals allowed)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre><code>{ \"lastname\": \"Peeters\", \"email\": \"ann.peeters@example.com\", \"sign_page\": 3, \"sign_left\": 2.5, \"sign_bottom\": 6 }<\/code><\/pre>\n<p><code>sign_left<\/code> and <code>sign_bottom<\/code> give the <strong>top left corner<\/strong> of the signature. The signature is placed below and to the right of this point.<\/p>\n<p>The limits depend on the actual size of the page and on the size of the visual stamp: the whole signature must stay at least 2 cm from every edge of the page. When several signing methods are accepted, the largest stamp is used. If a value is out of range, the error message gives the allowed range for that page.<\/p>\n<p>A signature may not overlap another signature of the request, nor an existing signature when the document is already signed.<\/p>\n<h2 id=\"object\">8. The signature request object<\/h2>\n<p>Returned by <code>request<\/code>, <code>getRequest<\/code>, <code>cancel<\/code>, <code>skip<\/code>, <code>remind<\/code>, <code>delete<\/code> and sent in the callbacks.<\/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 request<\/td>\n<\/tr>\n<tr>\n<td><code>doc_name<\/code><\/td>\n<td>Name of the document<\/td>\n<\/tr>\n<tr>\n<td><code>status_id<\/code><\/td>\n<td><code>pending<\/code> in progress \u00b7 <code>finished<\/code> signed by everybody \u00b7 <code>skipped<\/code> stopped, partially signed \u00b7 <code>cancelled<\/code> \u00b7 <code>deleted<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>signers<\/code><\/td>\n<td>Object of the signers, by key (<code>\"1\"<\/code>, <code>\"2\"<\/code>\u2026) \u2014 see below<\/td>\n<\/tr>\n<tr>\n<td><code>lang<\/code>, <code>send_email<\/code>, <code>signature_redirect<\/code>, <code>timezone<\/code><\/td>\n<td>As defined at creation<\/td>\n<\/tr>\n<tr>\n<td><code>from_api<\/code><\/td>\n<td><code>true<\/code> if the request was created through the API<\/td>\n<\/tr>\n<tr>\n<td><code>date_status<\/code><\/td>\n<td>Date of the last status change (time zone of the request)<\/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><\/td>\n<td>Credits of the request (reserved while pending, used once finished)<\/td>\n<\/tr>\n<tr>\n<td><code>credits_balance<\/code><\/td>\n<td>Current balance of your account<\/td>\n<\/tr>\n<tr>\n<td><code>pdf_file_base64<\/code><\/td>\n<td>Signed PDF, when the request is no longer pending<\/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<h3>Signer<\/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>firstname<\/code>, <code>lastname<\/code>, <code>email<\/code>, <code>phone<\/code>, <code>sign_first<\/code><\/td>\n<td>As sent at creation<\/td>\n<\/tr>\n<tr>\n<td><code>status<\/code><\/td>\n<td><code>pending<\/code> \u00b7 <code>signed<\/code> \u00b7 <code>skipped<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>signature_link<\/code><\/td>\n<td>Personal signing link, while the signer has not signed<\/td>\n<\/tr>\n<tr>\n<td><code>signing_time<\/code>, <code>signing_method<\/code><\/td>\n<td>Once signed: date and method used<\/td>\n<\/tr>\n<tr>\n<td><code>verified_firstname<\/code>, <code>verified_lastname<\/code><\/td>\n<td>Once signed: identity verified by the signing method<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre><code>{\n  \"1\": {\n    \"firstname\": \"Ann\",\n    \"lastname\": \"Peeters\",\n    \"email\": \"ann.peeters@example.com\",\n    \"status\": \"signed\",\n    \"signing_time\": \"2026-10-20 11:02:47\",\n    \"signing_method\": \"itsme-qes-signature\",\n    \"verified_firstname\": \"Ann\",\n    \"verified_lastname\": \"Peeters\"\n  }\n}<\/code><\/pre>\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 requests<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/signature\/list?userid={userid}&amp;status_id=pending<\/span><\/div>\n<p><code>status_id<\/code> (optional): <code>pending<\/code>, <code>finished<\/code> or <code>skipped<\/code>. <code>external_reference<\/code> (optional): only the requests with this reference.<\/p>\n<pre><code>{\n  \"success\": true,\n  \"result\": [\n    {\n      \"id_sign\": 4521,\n      \"status_id\": \"pending\",\n      \"external_reference\": \"QUOTE-2026-114\"\n    },\n    {\n      \"id_sign\": 4498,\n      \"status_id\": \"finished\"\n    }\n  ]\n}<\/code><\/pre>\n<h3 id=\"getRequest\">Get a request<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/signature\/getRequest?userid={userid}&amp;id_sign=4521<\/span><\/div>\n<p>Returns the <a href=\"#object\">signature request object<\/a>, with the signed PDF once the request is finished. To follow the status of a request, use the <a href=\"#callbacks\">callbacks<\/a> rather than repeated calls.<\/p>\n<h3 id=\"remind\">Send a reminder<\/h3>\n<div class=\"ep\"><span class=\"m PATCH\">PATCH<\/span><span>\/v3\/signature\/remind?userid={userid}&amp;id_sign=4521<\/span><\/div>\n<p>Sends a reminder email to the signers with <code>status: pending<\/code> of the group currently invited (<code>sign_first<\/code> group first). Request <code>pending<\/code> only. Works also for requests created with <code>send_email: false<\/code>.<\/p>\n<h3 id=\"skip\">Stop a request (keep the signatures already made)<\/h3>\n<div class=\"ep\"><span class=\"m PATCH\">PATCH<\/span><span>\/v3\/signature\/skip?userid={userid}&amp;id_sign=4521<\/span><\/div>\n<p>Possible when at least one signer has signed and at least one has not. The request becomes <code>skipped<\/code>, the partially signed PDF is available and the credits of the signers who did not sign are refunded.<\/p>\n<h3 id=\"cancel\">Cancel a request<\/h3>\n<div class=\"ep\"><span class=\"m DELETE\">DELETE<\/span><span>\/v3\/signature\/cancel?userid={userid}&amp;id_sign=4521<\/span><\/div>\n<p>Possible as long as nobody has signed; to end a partially signed request, use <a href=\"#skip\"><code>skip<\/code><\/a>. The response contains the request with <code>status_id: cancelled<\/code>; the request and its document are then removed from your dashboard, the signing links stop working and the credits are refunded.<\/p>\n<h3 id=\"delete\">Delete a request<\/h3>\n<div class=\"ep\"><span class=\"m DELETE\">DELETE<\/span><span>\/v3\/signature\/delete?userid={userid}&amp;id_sign=4521<\/span><\/div>\n<p>Requests <code>finished<\/code> or <code>skipped<\/code> only. Deletes the documents and the request. The response contains the request one last time, with <code>status_id: deleted<\/code>: download the signed PDF before deleting.<\/p>\n<h3 id=\"requestAuditTrail\">Download the audit trail<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/signature\/requestAuditTrail?userid={userid}&amp;id_sign=4521<\/span><\/div>\n<p>Not available while the request is pending (HTTP 412). Returns the request object with <code>audit_trail_base64<\/code>: a PDF with the history of the request (dates, methods, verified identities).<\/p>\n<h3 id=\"requestBalance\">Get the credit balance<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/signature\/requestBalance?userid={userid}<\/span><\/div>\n<pre><code>{ \"success\": true, \"result\": { \"credits_balance\": 38.4 } }<\/code><\/pre>\n<h3 id=\"getMethods\">List the signing methods<\/h3>\n<div class=\"ep\"><span class=\"m GET\">GET<\/span><span>\/v3\/signature\/getMethods?userid={userid}&amp;lang=en<\/span><\/div>\n<p>Methods accepted in <code>methods<\/code>, with the price in credits per signer <strong>for your account<\/strong>. <code>lang<\/code> (optional) translates the labels.<\/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\": \"evrotrust-signature\",\n      \"label\": \"Evrotrust | QES\",\n      \"credits\": 1\n    },\n    {\n      \"id\": \"veriff-advanced-signature\",\n      \"label\": \"Veriff | AES\",\n      \"credits\": 0.7\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>Signer status changes, e.g. <code>[{\"signer_key\": 1, \"from\": \"pending\", \"to\": \"signed\"}]<\/code> (only when a signer changed)<\/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>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>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<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<\/td>\n<td>OK \/ request created<\/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>400<\/td>\n<td>Missing <code>id_sign<\/code>, or invalid <code>status_id<\/code> filter<\/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>Unknown <code>id_sign<\/code> for this account<\/td>\n<\/tr>\n<tr>\n<td>412<\/td>\n<td>Action not possible in the current state (e.g. cancel after a signature, delete a pending request)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 id=\"errors-by-endpoint\">Errors by endpoint<\/h3>\n<table>\n<thead>\n<tr>\n<th>Endpoint<\/th>\n<th>HTTP code<\/th>\n<th>Message<\/th>\n<th>Cause<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>All endpoints<\/td>\n<td>401<\/td>\n<td><code>Please provide a valid x-api-key in headers &amp; userid in url parameters.<\/code><\/td>\n<td>Invalid <code>userid<\/code> or <code>x-api-key<\/code><\/td>\n<\/tr>\n<tr>\n<td>All endpoints<\/td>\n<td>403<\/td>\n<td><code>Rate limit exceeded: 10 requests per minute is allowed. Please try again after a minute.<\/code><\/td>\n<td>More than 10 requests per minute<\/td>\n<\/tr>\n<tr>\n<td><code>request<\/code><\/td>\n<td>400<\/td>\n<td>See <a href=\"#validation\">Validation messages<\/a><\/td>\n<td>Missing or invalid field, PDF or position<\/td>\n<\/tr>\n<tr>\n<td><code>request<\/code><\/td>\n<td>403<\/td>\n<td><code>You do not have enough credits<\/code><\/td>\n<td>Balance lower than the cost of the request<\/td>\n<\/tr>\n<tr>\n<td><code>list<\/code><\/td>\n<td>400<\/td>\n<td><code>Incorrect value for status_id.<\/code><\/td>\n<td>Unknown <code>status_id<\/code> filter<\/td>\n<\/tr>\n<tr>\n<td><code>getRequest<\/code>, <code>remind<\/code>, <code>skip<\/code>, <code>cancel<\/code>, <code>delete<\/code>, <code>requestAuditTrail<\/code><\/td>\n<td>400<\/td>\n<td><code>please provide id_sign parameter.<\/code><\/td>\n<td><code>id_sign<\/code> missing<\/td>\n<\/tr>\n<tr>\n<td><code>getRequest<\/code>, <code>remind<\/code>, <code>skip<\/code>, <code>cancel<\/code>, <code>delete<\/code>, <code>requestAuditTrail<\/code><\/td>\n<td>404<\/td>\n<td><code>invalid id_sign value.<\/code><\/td>\n<td>Unknown <code>id_sign<\/code> for this account<\/td>\n<\/tr>\n<tr>\n<td><code>remind<\/code><\/td>\n<td>412<\/td>\n<td><code>request can not be remind to user(s): wrong status<\/code><\/td>\n<td>The request is not pending<\/td>\n<\/tr>\n<tr>\n<td><code>skip<\/code><\/td>\n<td>412<\/td>\n<td><code>request can not be skipped: wrong status<\/code><\/td>\n<td>Nobody has signed yet, everybody has signed, or the request is not pending<\/td>\n<\/tr>\n<tr>\n<td><code>cancel<\/code><\/td>\n<td>412<\/td>\n<td><code>request can not be cancelled: someone already signed the PDF<\/code><\/td>\n<td>At least one signer has signed<\/td>\n<\/tr>\n<tr>\n<td><code>delete<\/code><\/td>\n<td>412<\/td>\n<td><code>request can not be deleted: wrong status_id<\/code><\/td>\n<td>The request is still pending<\/td>\n<\/tr>\n<tr>\n<td><code>requestAuditTrail<\/code><\/td>\n<td>412<\/td>\n<td><code>Can not download Audit Trail while the signature request is pending<\/code><\/td>\n<td>The request is still pending<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 id=\"validation\">Validation messages on creation (<code>request<\/code>, HTTP 400)<\/h3>\n<p>The message names the field or the problem; <code>\u2026<\/code> stands for a value of your request. Rely on the HTTP code in your code, and show the message to help correct the request.<\/p>\n<details class=\"esig-api-details\">\n<summary>Show all validation messages<\/summary>\n<h4>Request body<\/h4>\n<ul>\n<li><code>Request body can not be empty<\/code><\/li>\n<\/ul>\n<h4><code>title<\/code>, <code>lang<\/code><\/h4>\n<ul>\n<li><code>Field 'title' must be of type string and can not be empty<\/code><\/li>\n<li><code>Field 'lang' is an invalid language code<\/code><\/li>\n<\/ul>\n<h4><code>signers<\/code><\/h4>\n<ul>\n<li><code>field 'signers' is omitted or is empty<\/code><\/li>\n<li><code>Firstname, Lastname &amp; email address must be of type string and can not be empty<\/code><\/li>\n<li><code>\u2026 is not an email address<\/code><\/li>\n<li><code>field 'sign_first' is not a boolean value<\/code><\/li>\n<li><code>field 'sign_first' can not be 'true' when field 'send_email' is 'false'<\/code><\/li>\n<\/ul>\n<h4><code>methods<\/code><\/h4>\n<ul>\n<li><code>You must set at least one signing method<\/code><\/li>\n<li><code>\u2026 is not a valid method<\/code><\/li>\n<\/ul>\n<h4>Options<\/h4>\n<ul>\n<li><code>Field 'reminder' should be of type numeric between 0 &amp; 14 (days)<\/code><\/li>\n<li><code>Field 'send_email' should be of type boolean<\/code><\/li>\n<li><code>Field 'email_notification' should be of type boolean<\/code><\/li>\n<li><code>Field 'note_html' should be of type string<\/code><\/li>\n<li><code>Field 'signature_redirect' is not a valid url<\/code><\/li>\n<\/ul>\n<h4><code>external_reference<\/code>, <code>metadata<\/code>, <code>callback_url<\/code><\/h4>\n<ul>\n<li><code>Field 'external_reference' must be a string<\/code><\/li>\n<li><code>Field 'external_reference' can not exceed 255 characters<\/code><\/li>\n<li><code>Field 'metadata' must be a JSON object<\/code><\/li>\n<li><code>Field 'metadata' can not exceed 4096 bytes<\/code><\/li>\n<li><code>Field 'callback_url' must be a publicly reachable HTTPS URL<\/code><\/li>\n<\/ul>\n<h4>PDF<\/h4>\n<ul>\n<li><code>Field 'pdf_file_base64' should be of type string and not empty<\/code><\/li>\n<li><code>Field 'pdf_file_base64' doesn't contains a base64 encoded string<\/code><\/li>\n<li><code>Field 'pdf_file_base64' doesn't contains a base64 encoded PDF file<\/code><\/li>\n<li><code>Your file is too big &gt; 30 MB<\/code><\/li>\n<li><code>Couldn't load your PDF document<\/code><\/li>\n<li><code>PDF file is encrypted and password protected. Please unprotected your PDF file.<\/code><\/li>\n<li><code>Couldn't get pages from PDF document<\/code><\/li>\n<\/ul>\n<h4>Signature placement<\/h4>\n<ul>\n<li><code>field 'signature_place' is incorrect<\/code><\/li>\n<li><code>field 'sign_page' is empty or is not an integer<\/code><\/li>\n<li><code>field 'sign_left' is empty or is not a number (cm)<\/code><\/li>\n<li><code>field 'sign_bottom' is empty or is not a number (cm)<\/code><\/li>\n<li><code>Field 'sign_left' for signer \u2026 must be between \u2026 and \u2026 cm (page \u2026 is \u2026 x \u2026 cm, signature \u2026 x \u2026 cm, margin \u2026 cm)<\/code><\/li>\n<li><code>Field 'sign_bottom' for signer \u2026 must be between \u2026 and \u2026 cm (\u2026)<\/code><\/li>\n<li><code>Field 'sign_page' for signer \u2026 is too big: the document has \u2026 page(s)<\/code><\/li>\n<li><code>Page \u2026 is too small for the signature of \u2026 (\u2026)<\/code><\/li>\n<li><code>The signature of \u2026 on page \u2026 overlaps an existing signature of the document (\u2026)<\/code><\/li>\n<li><code>The signatures of \u2026 and \u2026 overlap on page \u2026 (\u2026)<\/code><\/li>\n<li><code>The existing signatures of the document could not be read: the position of the signature of \u2026 can not be checked<\/code><\/li>\n<\/ul>\n<h4>Document already signed (<code>position_auto<\/code>)<\/h4>\n<ul>\n<li><code>Your PDF file is already signed: pages can not be added without invalidating the existing signatures. It contains \u2026 free marker(s) for \u2026 signer(s): place the signatures manually (signature_place: position_manual).<\/code><\/li>\n<li><code>Your PDF file is already signed: pages can not be added without invalidating the existing signatures. The free markers could not be determined: place the signatures manually (signature_place: position_manual).<\/code><\/li>\n<\/ul>\n<h4>Processing<\/h4>\n<ul>\n<li><code>Couldn't extract markers from PDF document: \u2026<\/code><\/li>\n<li><code>Unknown error: Request could not be saved into the Database<\/code><\/li>\n<li>Error message returned by the signature provider (eID Easy)<\/li>\n<\/ul>\n<\/details>\n<h2 id=\"retention\">12. Retention<\/h2>\n<p>Signed documents can be downloaded for <strong>30 days<\/strong> after completion, through <code>getRequest<\/code> or the <code>request.completed<\/code> 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 signed document and the audit trail on your side within 30 days.<\/p>\n<h2 id=\"changelog\">13. Changelog<\/h2>\n<h3>API <span class=\"badge\">v3<\/span> \u2014 differences with API <span class=\"badge\">v2<\/span><\/h3>\n<p>API <span class=\"badge\">v2<\/span> (<code>https:\/\/api.e-signature.eu\/v2\/signature\/<\/code>) remains available and unchanged. Endpoints, parameters and authentication are identical in both versions: to move to API <span class=\"badge\">v3<\/span>, replace the base URL with <code>https:\/\/api.e-signature.eu\/v3\/signature\/<\/code>. You can switch endpoint by endpoint.<\/p>\n<p class=\"note\">The previous URLs (<code>https:\/\/www.e-signature.eu\/wp-json\/signature\/<\/code> for API <span class=\"badge\">v2<\/span> and <code>https:\/\/www.e-signature.eu\/wp-json\/esig\/v3\/signature\/<\/code> for API <span class=\"badge\">v3<\/span>) remain valid. We recommend using the <code>api.e-signature.eu<\/code> URLs.<\/p>\n<table>\n<thead>\n<tr>\n<th>Topic<\/th>\n<th>API <span class=\"badge\">v2<\/span><\/th>\n<th>API <span class=\"badge\">v3<\/span><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Base URL<\/td>\n<td><code>\/v2\/signature\/<\/code><\/td>\n<td><code>\/v3\/signature\/<\/code><\/td>\n<\/tr>\n<tr>\n<td>Your own references<\/td>\n<td>\u2014<\/td>\n<td>New fields <code>external_reference<\/code> and <code>metadata<\/code>, returned in every response and callback; <code>list<\/code> filter by <code>external_reference<\/code><\/td>\n<\/tr>\n<tr>\n<td>Callback URL<\/td>\n<td>One URL per account<\/td>\n<td>Also per request (<code>callback_url<\/code>)<\/td>\n<\/tr>\n<tr>\n<td>Callback content<\/td>\n<td>Full state of the request<\/td>\n<td>Full state of the request + <code>event<\/code>, <code>event_id<\/code>, <code>event_at<\/code>, <code>changes<\/code><\/td>\n<\/tr>\n<tr>\n<td>Callback security<\/td>\n<td>\u2014<\/td>\n<td>HMAC-SHA256 signature in the <code>X-Esig-Signature<\/code> header<\/td>\n<\/tr>\n<tr>\n<td>Callback retries<\/td>\n<td>Every hour on network error, until received<\/td>\n<td>Every hour on network error, timeout, HTTP 429 or 5xx, up to 24 attempts, same <code>event_id<\/code><\/td>\n<\/tr>\n<tr>\n<td>Missing <code>id_sign<\/code>, invalid <code>status_id<\/code> filter<\/td>\n<td>HTTP 401<\/td>\n<td>HTTP 400<\/td>\n<\/tr>\n<tr>\n<td>Unknown <code>id_sign<\/code><\/td>\n<td>HTTP 401<\/td>\n<td>HTTP 404<\/td>\n<\/tr>\n<tr>\n<td>Audit trail of a pending request<\/td>\n<td>HTTP 401<\/td>\n<td>HTTP 412<\/td>\n<\/tr>\n<tr>\n<td>Manual placement: <code>sign_left<\/code> \/ <code>sign_bottom<\/code><\/td>\n<td>Fixed limits for an A4 portrait page (0 to 15 cm \/ 4 to 28.7 cm), signature height 2.5 cm<\/td>\n<td>Limits computed from the actual page size and the stamp size of the accepted methods, 2 cm margin; decimals accepted; the error message gives the allowed range<\/td>\n<\/tr>\n<tr>\n<td>Manual placement: overlaps<\/td>\n<td>Not checked<\/td>\n<td>Refused if a signature overlaps another signature of the request or an existing signature of the document<\/td>\n<\/tr>\n<tr>\n<td>Manual placement: <code>sign_page<\/code><\/td>\n<td>A page number one higher than the last page was not refused<\/td>\n<td>Any page that does not exist is refused<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Callbacks follow the version used to <strong>create<\/strong> the request: a request created with API <span class=\"badge\">v2<\/span> keeps receiving API <span class=\"badge\">v2<\/span> callbacks.<\/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 signature request works Create a signature request Signature placement The signature request&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":21413,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-29094","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/29094","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/comments?post=29094"}],"version-history":[{"count":16,"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/29094\/revisions"}],"predecessor-version":[{"id":29168,"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/29094\/revisions\/29168"}],"up":[{"embeddable":true,"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/pages\/21413"}],"wp:attachment":[{"href":"https:\/\/staging.e-signature.eu\/en\/wp-json\/wp\/v2\/media?parent=29094"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}