eSignTools API v2.1.0
Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
This document describes how to send a document for signature to eSignTools. Based on REST principles, our Web API return data in JSON .
See an example of a Java implementation.
A document which will be signed is also called "agreement".
The classic workflow is :
- login : send the API credentials and get a token for the next API calls.
- createAgreement : upload the PDF and set the agreements settings. These settings are : title, callback url and recipients. The callback URL is called when an event occurs (document signed or rejected).
The document is now sent for signature to the recipients.
eSignTools will call the callback each time an event occurs.
Example, if the callback is set to https://mysite.com/event :
- https://mysite.com/event?id=1234&eventType=ESIGNED will be called when the document 1234 is signed by all recipients
- https://mysite.com/event?id=1234&eventType=REJECTED will be called when the document 1234 has been rejected by a recipient
- https://mysite.com/event?id=1234&eventType=OUT_FOR_SIGNATURE will be called when the document 1234 has been signed by a recipient but eSignTools is still waiting for the signature of another recipient.
Version 2.1.0
Version 2.1.0 adds embedded signing for client portals and in-person workflows, with temporary sessions, an iframe/modal integration script and browser events. The API endpoint paths retain their /v1 prefixes.
Downloads: Swagger 2.0 contract, Postman collection, iframe/modal integration script.
About signature fields
There are currently 3 ways to manage signature fields. You can either put it yourself in the PDF before uploading it to eSignTools, or you can add them dynamically at the upload.
Postman Collection detailing the 3 methods to create an agreement
Method 1 : Upload a PDF already containing signature fields :
These fields shall have a name like SignatorySignature_X_Y, where X is the recipent position (set in CreateRecipientDTO) and Y the fields number.
Examples :
- A document with a single field for one recipient :
- SignatorySignature_1_1
- A document with 2 fields for one recipient :
- SignatorySignature_1_1
- SignatorySignature_1_2
- A document for 2 recipients each with 2 fields :
- SignatorySignature_1_1
- SignatorySignature_1_2
- SignatorySignature_2_1
- SignatorySignature_2_2
Method 2 : Using tags
Your PDF can have no signature field, but just text tags. Add anywhere in your document a text #signatureX# to add a signature field linked to the recipient with position=X.
Example :
- Each #signature1# will be replaced by a signature field for the recipient with position=1.
- Each #signature2# will be replaced by a signature field for the recipient with position=2.
The signature fields will have a default size. You can customize the size in the API.
Method 3 : Upload a PDF without signature fields
If your PDF does not contain any signature fields, you must define them in the call to the API. For each recipient, you must have at least one signature field. See CreateSignatureZoneDTO
A signature field is defined by :
- "page" : The number of the page which will contain the field (starting at 1)
- "x" : distance between the top left corner of the field and the left border of the page in points
- "y" : distance between the top left corner of the field and the bottom border of the page in points
- "width" : width of the field in points
- "height" : height of the field in points
About document types
Instead of uploading a PDF file, you can upload any file with one of the following extension : .rtf, .doc, .docx, .xls, .xlsx, .odt, .ods The document will be converted by eSignTools into a PDF.
Base URLs:
- Test Environment: https://rec.esign-tools.fr/api
- Production Environment: https://secure.esign-tools.fr/api
Embedded signing (v2.1.0)
Embed the signing journey in a client portal, an iframe or a modal. The same documents, recipients, signature fields and optional SMS checks are used as for email signing. Signers do not need an EST account or third-party cookies.
Create the document and session
Create the agreement with the existing multipart endpoint. To disable invitation emails, pass "autoSendMailsEnabled": "false" in CreateAgreementDTO (a JSON string, not a boolean). Email signing remains enabled by default. Existing confirmation emails and business callbacks retain their behavior.
Use the recipient id returned in AgreementDTO.recipients; an email address cannot replace it. The host application's server must check that its authenticated user is allowed to access this agreement and sign for this recipient. For a client portal, derive the recipient from the authenticated client session. signatureScalePercent is an optional integer from 1 to 100 (default: 100, including null). A value of 70 scales both dimensions of the complete signature block (name, date and handwriting) to 70%, centered within its field in the final PDF. It applies only to this session, in either mode. Values other than 100 require the BLOCKCHAIN provider; DOCAPOST returns HTTP 400.
For in-person signing, check the operator's assignment to the case. Keep EST credentials and JWT tokens on your server.
Open a session from your server:
curl --request POST \
'https://secure.esign-tools.fr/api/signing/v1/agreements/123/embedded-sessions' \
--header 'Authorization: Bearer <JWT_EST>' \
--header 'Content-Type: application/json' \
--data '{"recipientId":456,"parentOrigin":"https://app.example.com","mode":"CLIENT_SPACE","signatureScalePercent":70}'
For in-person signing, use "mode": "IN_PERSON" and include "operatorReference": "technician-789". This identifies the authenticated professional; recipientId still identifies the customer who signs. EST stores these references with the calling EST user and the session expiration.
parentOrigin must match the host application's exact origin, including its port if applicable, without a path or trailing slash. HTTPS is required; HTTP is accepted for localhost and 127.0.0.1 during development.
201 Created — Cache-Control: no-store
{
"signingUrl": "https://secure.esign-tools.fr/fr/signature/embedded-00000000-0000-4000-8000-000000000000",
"expiresAt": "2026-10-16T15:30:00+02:00",
"agreementId": 123,
"recipientId": 456
}
Always use the returned signingUrl; its language prefix depends on the EST deployment. Treat it as confidential access to the document. Forward the response to the signer's browser without exposing your EST JWT.
The session lasts up to 30 minutes and never exceeds the agreement's expiration. The agreement must be accessible to the API caller, OPEN, and the recipient must be WAITING at the current signing step. An incompatible state or expired agreement returns 409 Conflict when creating a session. An unknown agreement or recipient returns 404 Not Found. Invalid input returns 400 Bad Request. When using a session, an expired access returns 410 Gone, and an unknown access returns 404 Not Found. Request a new session from your server to resume after expiration.
Display an iframe or modal
Download the ESTSigning integration script and host it with your application, or load /assets/est-embedded.js from your EST client deployment (including its language prefix when needed). The signer needs network access to both the EST client and API.
The following native HTML modal receives session from your own server:
<dialog id="signature-dialog" aria-label="Sign document"
style="width:96vw;max-width:1100px;height:92vh;height:92dvh;padding:0;border:0">
<div id="signature-container" style="width:100%;height:100%"></div>
</dialog>
<script src="/assets/est-embedded.js"></script>
<script>
function openSignature(session) {
const dialog = document.getElementById('signature-dialog');
const container = document.getElementById('signature-container');
let integration;
function close() {
if (integration) integration.destroy();
dialog.close();
dialog.removeEventListener('cancel', cancel);
}
function cancel(event) {
event.preventDefault();
close();
}
dialog.addEventListener('cancel', cancel);
integration = ESTSigning.mount({
...session,
container,
onEvent(message) {
if (message.event === 'signed' || message.event === 'refused') {
// Refresh the status through your server / the EST business callback.
close();
} else if (message.event === 'cancelled') {
close();
} else if (message.event === 'error') {
// Show an error and offer a new session through your server.
console.error('Signing unavailable', message.code);
close();
}
}
});
dialog.showModal();
}
</script>
For an iframe within a page, call ESTSigning.mount with a container of a defined height, for example height: 85vh. Call destroy() when closing or unmounting the host component. It removes the iframe, message listener and readiness timer.
If your proxy adds a Content Security Policy, allow the host origin in EST's frame-ancestors and the EST origin in the host application's frame-src. X-Frame-Options: DENY or SAMEORIGIN on the EST client prevents embedding across origins.
Browser events
EST sends postMessage events only to parentOrigin. The integration script checks the EST origin, iframe window, message version, agreement and recipient before invoking onEvent.
interface ESTSigningMessage {
source: 'est-signing';
version: 1;
event: 'ready' | 'signed' | 'refused' | 'error' | 'cancelled';
agreementId: number;
recipientId: number;
code?: string;
}
| Event / code | Meaning |
|---|---|
| ready | The document and recipient have loaded. |
| signed | This recipient has signed; other recipients may still be pending. |
| refused | This recipient has refused the document. |
| cancelled | Close the display; this does not refuse the document. |
| error / session_unavailable | No valid event arrived within 30 seconds: access may have expired, the network may be unavailable, or loading may be blocked. Customize the timeout with readyTimeout in milliseconds. |
| error / signature_failed | The signing action failed; EST retains its existing error handling. |
Browser notifications update the interface. Your server's agreement status and the existing EST callback remain the business reference; do not use a browser event alone as proof that an agreement is fully signed.
Authentication
- API Key (JWT)
- Parameter Name: Authorization, in: header.
Authentication
Authenticate
POST /v1/authenticate
Authenticate with eSignTools API and returns a JWT Token. This token must be sent to every other request in the Authorization bearer header. Example : "Authorization: Bearer XXX" where XXX is the token returned by this method.
Body parameter
{
"password": "string",
"rememberMe": true,
"username": "string"
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| body | body | Credentials | true | eSignTools Credentials |
Example responses
200 Response
{
"authorities": [
"string"
],
"id_token": "string"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | JWTToken |
| 201 | Created | Created | None |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
| 404 | Not Found | Not Found | None |
Agreement Resource
Basic interactions necessarry to handle the agreement through it's lifetime
Create a new agreement
POST /signing/v1/agreements
Body is a FormData composed of a document (sent in binary) and a CreateAgreementDTO object (serialized as a JSON) to create an agreement.
For examples, see the Postman collection in the introduction.
Body : composed of two multipart/form-data fields
pdf: binary data
agreement: JSON format data
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| body | body | object | true | Body with the format multipart/form-data |
| body | binary | true | The source document | |
| » agreement | body | string | true | String containing a CreateAgreementDTO in json format |
Example responses
200 Response
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | AgreementDTO |
| 201 | Created | Created | None |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
| 404 | Not Found | Not Found | None |
Open an embedded signing session
POST /signing/v1/agreements/{id}/embedded-sessions
Call from your application's server using Authorization: Bearer <JWT_EST>. See Embedded signing for the full integration workflow.
Body parameter
{"recipientId":456,"parentOrigin":"https://app.example.com","mode":"CLIENT_SPACE","signatureScalePercent":70}
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | integer(int64) | true | Agreement ID |
| body | body | CreateEmbeddedSigningSessionDTO | true | Session settings |
201 Created
{"signingUrl":"https://secure.esign-tools.fr/fr/signature/embedded-00000000-0000-4000-8000-000000000000","expiresAt":"2026-10-16T15:30:00+02:00","agreementId":123,"recipientId":456}
| Status | Description | Schema |
|---|---|---|
| 201 | Session created; Cache-Control: no-store |
EmbeddedSigningSessionDTO |
| 400 | Invalid input or origin; missing operatorReference for IN_PERSON | None |
| 401 | Missing or invalid JWT | None |
| 403 | Access forbidden | None |
| 404 | Agreement or recipient not found | None |
| 409 | Agreement not open or expired; recipient not waiting at current step | None |
This operation requires JWT authentication. An expired session returns 410 Gone when used; an unknown session returns 404 Not Found.
Re-send the mail to the recipient
GET /signing/v1/agreements/{agreementId}/send-mails
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| agreementId | path | integer(int64) | true | ID of the document |
Example responses
200 Response
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | boolean |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
| 404 | Not Found | Not Found | None |
Agreements settings
GET /signing/v1/agreements/{id}
Get information about the agreement in JSON format.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | integer(int64) | true | ID of the eSignTools agreement to get the settings. |
Example responses
200 Response
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | AgreementDTO |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
| 404 | Not Found | Not Found | None |
Delete an agreement
DELETE /signing/v1/agreements/{id}
The agreement must not be signed. It will be deleted and the recipient(s) will not be able to sign it.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | integer(int64) | true | ID of the eSignTools agreement to delete. |
Example responses
200 Response
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | string |
| 204 | No Content | No Content | None |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
Download the document
GET /signing/v1/agreements/{id}/current-file
The document can be downloaded at any point of the process. (Unsigned, Partially Signed, Signed)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | integer(int64) | true | ID of the eSignTools document |
Example responses
200 Response
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | byte |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
| 404 | Not Found | Not Found | None |
Downloads the proof PDF
GET /signing/v1/agreements/{id}/proof
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | integer(int64) | true | ID of the eSignTools document |
Example responses
200 Response
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | byte |
| 401 | Unauthorized | Unauthorized | None |
| 403 | Forbidden | Forbidden | None |
| 404 | Not Found | Not Found | None |
Schemas
Credentials
{
"password": "string",
"rememberMe": true,
"username": "string"
}
Credentials
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| password | string | true | none | Password of the API user |
| rememberMe | boolean | false | none | none |
| username | string | true | none | Username of the API user |
JWTToken
{
"authorities": [
"string"
],
"id_token": "string"
}
JWTToken
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| authorities | [string] | false | none | none |
| id_token | string | false | none | JWT Token to pass to next API calls. |
CreateAgreementDTO
{
"autoSendMailsEnabled": "false",
"durationUntilExpirationSeconds": 3600,
"callbackUrl": "https://mysite.com/event",
"defaultFieldHeight": 0,
"defaultFieldWidth": 0,
"name": "Contract123",
"recipients": [
{
"canRenew": true,
"email": "string",
"fields": [
{
"height": 0,
"page": 0,
"width": 0,
"x": 0,
"y": 0
}
],
"firstname": "string",
"lastname": "string",
"phone": "string",
"position": 0,
"step": 0
}
],
"reminderDelay": "86 400",
"textTemplateName": "default"
}
CreateAgreementDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| autoSendMailsEnabled | string | false | none | Set the string "false" to disable invitation emails for embedded signing. Defaults to "true". |
| durationUntilExpirationSeconds | integer(int64) | false | minimum: 600 | Agreement lifetime in seconds; account default if omitted. |
| callbackUrl | string | false | none | URL which will be called when an event occurs. See the Introduction to know how callback events works. |
| defaultFieldHeight | integer(int32) | false | none | Set the default height of signature fields when using tags. |
| defaultFieldWidth | integer(int32) | false | none | Set the default width of signature fields when using tags. |
| name | string | true | none | Name of the agreement |
| recipients | [CreateRecipientDTO] | true | none | none |
| reminderDelay | integer(int32) | false | none | Set the delay of reminders in minutes. A reminder is sent when a recipient has not signed the document. If this parameter is not set, no reminder will be sent. |
| textTemplateName | string | false | none | Template to use when a mail is sent to the recipient. If this parameter is not set, the default template is used. |
CreateRecipientDTO
{
"canRenew": true,
"email": "string",
"fields": [
{
"height": 0,
"page": 0,
"width": 0,
"x": 0,
"y": 0
}
],
"firstname": "string",
"lastname": "string",
"phone": "string",
"position": 0,
"step": 0
}
CreateRecipientDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| canRenew | boolean | false | none | none |
| string | true | none | none | |
| fields | [CreateSignatureZoneDTO] | false | none | List of the signature fields to add for this recipient. This list is mandatory if the PDF does not contain any signature fields. |
| firstname | string | true | none | none |
| lastname | string | true | none | none |
| phone | string | false | none | Phone number of the recipient. If this propery is set, a SMS with a code will be sent to the recipient to validate its signature. |
| position | integer(int32) | false | none | Position of the concerned Signature Form in the PDF. Example : if the position is 1, every Signature Form with the name SignatorySignature_1_x will be bound to this recipient. This property is optional if you set the signature fields via the API. Default is 1 |
| step | integer(int32) | false | none | Step of this recipient in the signature workflow. If every recipient has step=1, the document will be sent for signature simultaneously to every recipient. If step=1 for recipient A and step=2 for recipient B, eSignTools will wait A to sign before sending it to B. Default is 1 |
CreateSignatureZoneDTO
{
"height": 0,
"page": 0,
"width": 0,
"x": 0,
"y": 0
}
CreateSignatureZoneDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| height | integer(int32) | false | none | Height of the field in points |
| page | integer(int32) | false | none | Number of the page which will contain the field (starts with 1) |
| width | integer(int32) | false | none | Width of the field in points |
| x | integer(int32) | false | none | Horizontal position of the field, from the left of the page, in points |
| y | integer(int32) | false | none | Vertical position of the field, from the bottom of the page, in points |
AgreementDTO
{
"currentStep": 0,
"estClientUrlAccess": "string",
"id": 0,
"name": "string",
"pages": 0,
"recipients": [
{
"canRenew": true,
"email": "string",
"firstname": "string",
"id": 0,
"lastname": "string",
"status": "WAITING",
"step": 0
}
],
"renewedDate": "2019-08-24T14:15:22Z",
"status": "OPEN"
}
AgreementDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| currentStep | integer(int32) | false | none | Current step of the document. See CreateAgreementDTO::step |
| estClientUrlAccess | string | false | none | none |
| id | integer(int64) | false | none | Agreement ID generated by eSignTools |
| name | string | false | none | Name of the agreement (ex : "Contract") |
| pages | integer(int32) | false | none | Number of pages of the document |
| recipients | [RecipientStatusDTO] | false | none | [Information about the recipient and its status in the signature workflow.] |
| renewedDate | string(date-time) | false | none | none |
| status | string | false | none | Current status of the agreement. - OPEN : the document has not been signed by all recipients - CLOSED : the document is signed by every recipient and is archived - ABORTED : the document has been rejected by a recipient - DELETED : the document has been deleted with a DELETE API call - ABANDONED : the document is expired |
Enumerated Values
| Property | Value |
|---|---|
| status | OPEN |
| status | CLOSED |
| status | ABORTED |
| status | DELETED |
| status | ABANDONED |
RecipientStatusDTO
{
"canRenew": true,
"email": "string",
"firstname": "string",
"id": 0,
"lastname": "string",
"status": "WAITING",
"step": 0
}
RecipientStatusDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| canRenew | boolean | false | none | none |
| string | false | none | none | |
| firstname | string | false | none | none |
| id | integer(int64) | false | none | ID of the recipient, generated by eSignTools |
| lastname | string | false | none | none |
| status | string | false | none | none |
| step | integer(int32) | false | none | See CreateRecipientDTO:step for more details. |
Enumerated Values
| Property | Value |
|---|---|
| status | WAITING |
| status | SIGNED |
| status | REFUSED |
CreateEmbeddedSigningSessionDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| recipientId | integer(int64) | true | none | Recipient ID from AgreementDTO.recipients; must be WAITING at the current signing step. |
| parentOrigin | string | true | maxLength: 255 | Exact HTTPS origin of the host application, without path or trailing slash. HTTP allowed only for localhost and 127.0.0.1. |
| mode | string | true | CLIENT_SPACE, IN_PERSON | Client portal or in-person signing. IN_PERSON requires operatorReference. |
| operatorReference | string | false | maxLength: 255 | Required and non-blank for IN_PERSON. Reference of the authenticated professional, not the signer. |
| signatureScalePercent | integer(int32) | false | 1–100, default: 100 | Proportional scale of the complete signature block in the final PDF, centered in its field. Values other than 100 require BLOCKCHAIN. |
EmbeddedSigningSessionDTO
Properties
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| signingUrl | string(uri) | false | none | Confidential temporary signing URL. Use the returned URL, including its deployment-specific language prefix. |
| expiresAt | string(date-time) | false | none | Up to 30 minutes from creation, capped at the agreement expiration. |
| agreementId | integer(int64) | false | none | none |
| recipientId | integer(int64) | false | none | none |