e-Signature.eu REST API — electronic signatures (SES, AES, QES)

1. Overview

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.

Base URL https://api.e-signature.eu/v3/signature/

This documentation describes API v3. Already using API v2 (https://api.e-signature.eu/v2/signature/)? See the Changelog.

2. Authentication

Your credentials are available in My account > Signatures API once you are logged in on e-signature.eu:

  • User ID: sent in the URL as the userid parameter of every call;
  • API token: sent in the x-api-key HTTP header of every call.
curl -X GET "https://api.e-signature.eu/v3/signature/requestBalance?userid=123" \
  -H "x-api-key: YOUR_API_TOKEN"

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.

3. Conventions

Requests and responses

  • HTTPS only. Request bodies are JSON (Content-Type: application/json).
  • Every response is JSON, in one of these two forms:
{ "success": true,  "result": { ... } }
{ "success": false, "error": "Readable error message" }

Limits

Limit Value
Requests 10 per minute per account and IP address (HTTP 403 beyond, retry after one minute)
Document One PDF per request, 30 MB maximum, not encrypted / not password protected
Download of signed documents 30 days after completion (see Retention)

4. Credits

Requests are paid with your prepaid e-signature.eu credits. The price of a method can be retrieved with getMethods (it takes your specific prices into account). Your balance is returned by requestBalance and in every request object (credits_balance).

Automatic credit recharge

To avoid running out of credits, you can let your account recharge itself automatically. It is set up once in My account > Signatures API, not through the API:

  1. Choose a threshold (in credits) and the credit pack to order.
  2. Save a payment method with our payment provider Mollie (card, or SEPA Direct Debit through Bancontact, iDEAL…). A verification payment of €0.01 is requested once.
  3. 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.
Automatic recharge
Trigger A debit of credits (e.g. a new request) that brings the balance below the threshold
Credits added As soon as the payment is confirmed: immediately by card, after a few working days by SEPA Direct Debit
Recharges in progress One at a time
Safety limit A maximum number of automatic recharges per 30 days
Payment failure The order is marked as failed, automatic recharge is turned off and you are informed by email
The recharge is triggered by a debit. A request that costs more than your current balance is refused (HTTP 403, You do not have enough credits) 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 requestBalance and credits_balance.

5. How a signature request works

  1. You create the request with the PDF, the signers and the accepted signing methods. The credits are debited.
  2. Each signer receives an email with a personal signing link (or you send the signature_link yourself when send_email is false).
  3. The signer verifies his identity with one of the accepted methods (itsme®, Evrotrust, Veriff, OTP…) and signs.
  4. When everybody signed, the request is finished: the signed PDF (PAdES) is available through getRequest and sent in the callback.

Signing order

By default all signers sign in parallel. To define an order, set sign_first: true on the signers of the first group: 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.

Two integration modes

Mode How it works
Email mode (send_email: true, default) We send the signing invitations, reminders and completion emails to the signers on your behalf.
Embedded mode (send_email: false) No email is sent when the request is created: the signature_link of each signer is returned in the response, and you redirect your users to it from your own interface.
Even with send_email: false, a reminder or a cancellation triggered from the online dashboard sends an email to the pending signers.

Do not poll the API

Do not call getRequest repeatedly to follow the status of a request: rely on the callbacks, sent automatically at each change. Excessive calls trigger an automatic throttling that temporarily suspends the processing of your requests.

6. Create a signature request

POST/v3/signature/request?userid={userid}
{
  "title": "Sales agreement 2026-114",
  "lang": "en",
  "methods": [
    "itsme-qes-signature",
    "evrotrust-signature"
  ],
  "signature_place": "position_auto",
  "reminder": 3,
  "send_email": true,
  "email_notification": false,
  "note_html": "Please sign the agreement before Friday.",
  "signature_redirect": "https://www.example.com/thank-you",
  "external_reference": "QUOTE-2026-114",
  "metadata": {
    "crm_deal_id": 8812
  },
  "callback_url": "https://erp.example.com/hooks/esignature",
  "signers": [
    {
      "firstname": "Ann",
      "lastname": "Peeters",
      "email": "[email protected]",
      "phone": "+32475111222",
      "sign_first": true
    },
    {
      "firstname": "Marc",
      "lastname": "Dubois",
      "email": "[email protected]",
      "sign_first": false
    }
  ],
  "pdf_file_base64": "JVBERi0xLjcKJeLjz9MK..."
}

Signing methods

Method Level Coverage Price
itsme-qes-signature — itsme® QES (qualified) 32 European countries 1 credit / signer
evrotrust-signature — Evrotrust QES (qualified) 69 countries 1 credit / signer
veriff-advanced-signature — Veriff AES (advanced) 198 countries 0.7 credit / signer
otp-email-non-qualified — OTP by email or SMS SES (simple) Worldwide 0.4 credit / signer

Prices are the standard prices: getMethods 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. otp-email-non-qualified covers both email and SMS: the code is sent by SMS when the signer has a phone, otherwise by email, at the same price.

Body fields

Field Required Type Description
title yes string Name of the document. Letters, digits and dashes are kept; a suffix -1, -2… is added if the name already exists in your account.
lang yes string Language of the emails and signing pages: fr, nl, en, de, es.
methods yes array Accepted signing methods, see Signing methods. When several are accepted, each signer chooses.
signers yes array Signers, see below.
pdf_file_base64 yes string The PDF, base64 encoded. One file, 30 MB maximum, not encrypted.
signature_place no string position_auto (default) or position_manual, see Signature placement.
reminder no number Automatic reminder every N days, 0 to 14. Default 0 (no reminder).
send_email no boolean Default true (email mode). With false (embedded mode), no invitation nor completion email is sent: send the signature_link yourself. Can not be combined with sign_first: true.
email_notification no boolean Default false. With true, you receive an email at each signature.
note_html no string Message added to the emails sent to the signers (email mode). HTML tags are accepted, e.g. Note with <strong>HTML</strong>.
signature_redirect no string (URL) Page shown to the signer after signing. Must be a valid URL (empty strings are refused). Default: confirmation page on e-signature.eu.
external_reference no string Your own identifier (quote, contract…), max 255 characters. Returned in every response and callback.
metadata no object Free JSON object, max 4 KB, returned as is.
callback_url no string (URL) Callback URL for this request only (public HTTPS). Default: the URL of your account.

Signer fields

Field Required Type Description
lastname yes string
email yes string Valid email address
firstname no string
phone no string International format starting with + and the country code (+32…); 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.
sign_first no boolean Default false. See Signing order.
sign_page, sign_left, sign_bottom with position_manual number See Signature placement.

Cost

Price of the most expensive method in methods × 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.

Response 201 Created

{
  "success": true,
  "result": {
    "id_sign": 4521,
    "lang": "en",
    "doc_name": "Sales-agreement-2026-114",
    "send_email": true,
    "from_api": true,
    "signature_redirect": "https://www.example.com/thank-you",
    "status_id": "pending",
    "date_status": "2026-10-20 10:15:02",
    "last_reminder": null,
    "timezone": "Europe/Brussels",
    "credits": 2,
    "credits_balance": 38.4,
    "signers": {
      "1": {
        "firstname": "Ann",
        "lastname": "Peeters",
        "email": "[email protected]",
        "phone": "+32475111222",
        "sign_first": true,
        "status": "pending",
        "signature_link": "https://www.e-signature.eu/en/sign/?key=…"
      },
      "2": {
        "firstname": "Marc",
        "lastname": "Dubois",
        "email": "[email protected]",
        "sign_first": false,
        "status": "pending",
        "signature_link": "https://www.e-signature.eu/en/sign/?key=…"
      }
    },
    "external_reference": "QUOTE-2026-114",
    "metadata": {
      "crm_deal_id": 8812
    }
  }
}

7. Signature placement

position_auto (default)

Place the markers #SIG01, #SIG02… (also accepted: #SIG01#) as text in your document, where each signer must sign (#SIG01 = first signer of the signers 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.

Tip: write the markers in white text (on a white background) so that they are invisible in the signed PDF. They must remain real text, not an image, to be detected.

Document not signed yet

If the document contains no marker, or if the marker of a signer is missing, a signature page containing the markers 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).

Document already signed

No page can be added to a PDF that is already signed electronically: it would invalidate the existing signatures. With position_auto, the signatures are placed on the free markers, i.e. the markers whose signature area does not cover an existing signature. Free markers are assigned to the signers in order (#SIG01, #SIG02…).

If the signed document does not contain enough free markers for all signers, the request is refused (HTTP 400): use position_manual.

position_manual

Give the position of each signature, in centimetres, for each signer:

Field Value
sign_page Page number, starting at 1 (integer)
sign_left Distance from the left edge of the page to the left of the signature, in cm (decimals allowed)
sign_bottom Distance from the bottom edge of the page to the top of the signature, in cm (decimals allowed)
{ "lastname": "Peeters", "email": "[email protected]", "sign_page": 3, "sign_left": 2.5, "sign_bottom": 6 }

sign_left and sign_bottom give the top left corner of the signature. The signature is placed below and to the right of this point.

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.

A signature may not overlap another signature of the request, nor an existing signature when the document is already signed.

8. The signature request object

Returned by request, getRequest, cancel, skip, remind, delete and sent in the callbacks.

Field Description
id_sign Identifier of the request
doc_name Name of the document
status_id pending in progress · finished signed by everybody · skipped stopped, partially signed · cancelled · deleted
signers Object of the signers, by key ("1", "2"…) — see below
lang, send_email, signature_redirect, timezone As defined at creation
from_api true if the request was created through the API
date_status Date of the last status change (time zone of the request)
last_reminder Date of the last reminder, or null
credits Credits of the request (reserved while pending, used once finished)
credits_balance Current balance of your account
pdf_file_base64 Signed PDF, when the request is no longer pending
external_reference, metadata As sent at creation

Signer

Field Description
firstname, lastname, email, phone, sign_first As sent at creation
status pending · signed · skipped
signature_link Personal signing link, while the signer has not signed
signing_time, signing_method Once signed: date and method used
verified_firstname, verified_lastname Once signed: identity verified by the signing method
{
  "1": {
    "firstname": "Ann",
    "lastname": "Peeters",
    "email": "[email protected]",
    "status": "signed",
    "signing_time": "2026-10-20 11:02:47",
    "signing_method": "itsme-qes-signature",
    "verified_firstname": "Ann",
    "verified_lastname": "Peeters"
  }
}

9. Other endpoints

All endpoints take userid in the URL and x-api-key in the headers. id_sign is passed in the URL.

List the requests

GET/v3/signature/list?userid={userid}&status_id=pending

status_id (optional): pending, finished or skipped. external_reference (optional): only the requests with this reference.

{
  "success": true,
  "result": [
    {
      "id_sign": 4521,
      "status_id": "pending",
      "external_reference": "QUOTE-2026-114"
    },
    {
      "id_sign": 4498,
      "status_id": "finished"
    }
  ]
}

Get a request

GET/v3/signature/getRequest?userid={userid}&id_sign=4521

Returns the signature request object, with the signed PDF once the request is finished. To follow the status of a request, use the callbacks rather than repeated calls.

Send a reminder

PATCH/v3/signature/remind?userid={userid}&id_sign=4521

Sends a reminder email to the signers with status: pending of the group currently invited (sign_first group first). Request pending only. Works also for requests created with send_email: false.

Stop a request (keep the signatures already made)

PATCH/v3/signature/skip?userid={userid}&id_sign=4521

Possible when at least one signer has signed and at least one has not. The request becomes skipped, the partially signed PDF is available and the credits of the signers who did not sign are refunded.

Cancel a request

DELETE/v3/signature/cancel?userid={userid}&id_sign=4521

Possible as long as nobody has signed; to end a partially signed request, use skip. The response contains the request with status_id: cancelled; the request and its document are then removed from your dashboard, the signing links stop working and the credits are refunded.

Delete a request

DELETE/v3/signature/delete?userid={userid}&id_sign=4521

Requests finished or skipped only. Deletes the documents and the request. The response contains the request one last time, with status_id: deleted: download the signed PDF before deleting.

Download the audit trail

GET/v3/signature/requestAuditTrail?userid={userid}&id_sign=4521

Not available while the request is pending (HTTP 412). Returns the request object with audit_trail_base64: a PDF with the history of the request (dates, methods, verified identities).

Get the credit balance

GET/v3/signature/requestBalance?userid={userid}
{ "success": true, "result": { "credits_balance": 38.4 } }

List the signing methods

GET/v3/signature/getMethods?userid={userid}&lang=en

Methods accepted in methods, with the price in credits per signer for your account. lang (optional) translates the labels.

{
  "success": true,
  "result": [
    {
      "id": "itsme-qes-signature",
      "label": "itsme® | QES",
      "credits": 1
    },
    {
      "id": "evrotrust-signature",
      "label": "Evrotrust | QES",
      "credits": 1
    },
    {
      "id": "veriff-advanced-signature",
      "label": "Veriff | AES",
      "credits": 0.7
    },
    {
      "id": "otp-email-non-qualified",
      "label": "OTP by Email/SMS | SES",
      "credits": 0.4
    }
  ]
}

10. Callbacks (webhooks)

Define your callback URL in My account > Signatures API (HTTPS, publicly reachable). You can also set a callback_url per request. The callback is a POST with a JSON body containing the full current state of the request (same format as getRequest), sent for requests created through the API.

Event fields

Field Description
event Event type (see below)
event_id Unique identifier of the event (evt_…). Identical on every retry of the same event: use it to ignore duplicates.
event_at Date of the event (UTC, ISO 8601)
changes Signer status changes, e.g. [{"signer_key": 1, "from": "pending", "to": "signed"}] (only when a signer changed)
external_reference, metadata As sent when the request was created

Event types

Event When
signer.signed A signer signed, the request is still in progress
signer.declined, signer.skipped, signer.expired A signer declined, was skipped or expired
request.completed All signers signed: the signed PDF is included (pdf_file_base64)
request.stopped The request was stopped: the partially signed PDF is included
request.cancelled The request was cancelled
request.deleted The request was deleted
request.expired The request expired
request.declined Registered mail declined by the recipient
request.updated Any other change: reminder sent, signer modified, new signing links…

The body always contains the full current state: your integration can rely on status_id and on the status of each signer rather than on the event type alone.

Headers

Header Example
X-Esig-Api-Version 3
X-Esig-Event signer.signed
X-Esig-Event-Id evt_4f0c2b9e1d7a3c55e8b1a2f0
X-Esig-Delivery-Attempt 1, 2, …
X-Esig-Signature t=1792407600,v1=5d41402abc4b2a76b9719d911017c592…

Verifying the signature

Your signing secret is shown in My account > Signatures API, where it can also be regenerated. v1 is the HMAC-SHA256 of "<t>.<raw request body>" with your secret, hex encoded. Use the raw body, before any JSON parsing, and reject callbacks older than 5 minutes.

PHP

$body   = file_get_contents( 'php://input' );
$header = $_SERVER['HTTP_X_ESIG_SIGNATURE'] ?? '';
preg_match( '/t=(\d+),v1=([a-f0-9]{64})/', $header, $m );
$valid = $m
    && abs( time() - (int) $m[1] ) <= 300
    && hash_equals( hash_hmac( 'sha256', $m[1] . '.' . $body, $secret ), $m[2] );

Node.js

const crypto = require('crypto');
function verify(rawBody, header, secret) {
  const m = /t=(\d+),v1=([a-f0-9]{64})/.exec(header || '');
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}

C# (.NET)

using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions;
static bool Verify(string rawBody, string header, string secret) {
    var m = Regex.Match(header ?? "", @"t=(\d+),v1=([a-f0-9]{64})");
    if (!m.Success || Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(m.Groups[1].Value)) > 300) return false;
    using var h = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var expected = Convert.ToHexString(h.ComputeHash(Encoding.UTF8.GetBytes(m.Groups[1].Value + "." + rawBody))).ToLowerInvariant();
    return CryptographicOperations.FixedTimeEquals(Encoding.ASCII.GetBytes(expected), Encoding.ASCII.GetBytes(m.Groups[2].Value));
}

Responses and retries

  • Reply with HTTP 2xx as soon as the callback is received, and process it asynchronously if needed.
  • On network error, timeout (30 s), HTTP 429 or 5xx, the callback is sent again every hour with the same event_id, 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 getRequest.
  • Redirects are followed (the POST method is kept). localhost and private addresses can not be used.

11. Errors

Errors are returned with "success": false and a readable error message. Rely on the HTTP code for your logic: messages may be improved over time.

HTTP code Meaning
200 / 201 OK / request created
400 Missing or invalid field (the message names the field)
400 Missing id_sign, or invalid status_id filter
401 Invalid userid or x-api-key
403 Not enough credits, or request limit reached (10 per minute)
404 Unknown id_sign for this account
412 Action not possible in the current state (e.g. cancel after a signature, delete a pending request)

Errors by endpoint

Endpoint HTTP code Message Cause
All endpoints 401 Please provide a valid x-api-key in headers & userid in url parameters. Invalid userid or x-api-key
All endpoints 403 Rate limit exceeded: 10 requests per minute is allowed. Please try again after a minute. More than 10 requests per minute
request 400 See Validation messages Missing or invalid field, PDF or position
request 403 You do not have enough credits Balance lower than the cost of the request
list 400 Incorrect value for status_id. Unknown status_id filter
getRequest, remind, skip, cancel, delete, requestAuditTrail 400 please provide id_sign parameter. id_sign missing
getRequest, remind, skip, cancel, delete, requestAuditTrail 404 invalid id_sign value. Unknown id_sign for this account
remind 412 request can not be remind to user(s): wrong status The request is not pending
skip 412 request can not be skipped: wrong status Nobody has signed yet, everybody has signed, or the request is not pending
cancel 412 request can not be cancelled: someone already signed the PDF At least one signer has signed
delete 412 request can not be deleted: wrong status_id The request is still pending
requestAuditTrail 412 Can not download Audit Trail while the signature request is pending The request is still pending

Validation messages on creation (request, HTTP 400)

The message names the field or the problem; … stands for a value of your request. Rely on the HTTP code in your code, and show the message to help correct the request.

Show all validation messages

Request body

  • Request body can not be empty

title, lang

  • Field 'title' must be of type string and can not be empty
  • Field 'lang' is an invalid language code

signers

  • field 'signers' is omitted or is empty
  • Firstname, Lastname & email address must be of type string and can not be empty
  • … is not an email address
  • field 'sign_first' is not a boolean value
  • field 'sign_first' can not be 'true' when field 'send_email' is 'false'

methods

  • You must set at least one signing method
  • … is not a valid method

Options

  • Field 'reminder' should be of type numeric between 0 & 14 (days)
  • Field 'send_email' should be of type boolean
  • Field 'email_notification' should be of type boolean
  • Field 'note_html' should be of type string
  • Field 'signature_redirect' is not a valid url

external_reference, metadata, callback_url

  • Field 'external_reference' must be a string
  • Field 'external_reference' can not exceed 255 characters
  • Field 'metadata' must be a JSON object
  • Field 'metadata' can not exceed 4096 bytes
  • Field 'callback_url' must be a publicly reachable HTTPS URL

PDF

  • Field 'pdf_file_base64' should be of type string and not empty
  • Field 'pdf_file_base64' doesn't contains a base64 encoded string
  • Field 'pdf_file_base64' doesn't contains a base64 encoded PDF file
  • Your file is too big > 30 MB
  • Couldn't load your PDF document
  • PDF file is encrypted and password protected. Please unprotected your PDF file.
  • Couldn't get pages from PDF document

Signature placement

  • field 'signature_place' is incorrect
  • field 'sign_page' is empty or is not an integer
  • field 'sign_left' is empty or is not a number (cm)
  • field 'sign_bottom' is empty or is not a number (cm)
  • Field 'sign_left' for signer … must be between … and … cm (page … is … x … cm, signature … x … cm, margin … cm)
  • Field 'sign_bottom' for signer … must be between … and … cm (…)
  • Field 'sign_page' for signer … is too big: the document has … page(s)
  • Page … is too small for the signature of … (…)
  • The signature of … on page … overlaps an existing signature of the document (…)
  • The signatures of … and … overlap on page … (…)
  • The existing signatures of the document could not be read: the position of the signature of … can not be checked

Document already signed (position_auto)

  • Your PDF file is already signed: pages can not be added without invalidating the existing signatures. It contains … free marker(s) for … signer(s): place the signatures manually (signature_place: position_manual).
  • 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).

Processing

  • Couldn't extract markers from PDF document: …
  • Unknown error: Request could not be saved into the Database
  • Error message returned by the signature provider (eID Easy)

12. Retention

Signed documents can be downloaded for 30 days after completion, through getRequest or the request.completed callback. The audit trail is kept for the period defined in our DPA. Archive the signed document and the audit trail on your side within 30 days.

13. Changelog

API v3 — differences with API v2

API v2 (https://api.e-signature.eu/v2/signature/) remains available and unchanged. Endpoints, parameters and authentication are identical in both versions: to move to API v3, replace the base URL with https://api.e-signature.eu/v3/signature/. You can switch endpoint by endpoint.

The previous URLs (https://www.e-signature.eu/wp-json/signature/ for API v2 and https://www.e-signature.eu/wp-json/esig/v3/signature/ for API v3) remain valid. We recommend using the api.e-signature.eu URLs.

Topic API v2 API v3
Base URL /v2/signature/ /v3/signature/
Your own references — New fields external_reference and metadata, returned in every response and callback; list filter by external_reference
Callback URL One URL per account Also per request (callback_url)
Callback content Full state of the request Full state of the request + event, event_id, event_at, changes
Callback security — HMAC-SHA256 signature in the X-Esig-Signature header
Callback retries Every hour on network error, until received Every hour on network error, timeout, HTTP 429 or 5xx, up to 24 attempts, same event_id
Missing id_sign, invalid status_id filter HTTP 401 HTTP 400
Unknown id_sign HTTP 401 HTTP 404
Audit trail of a pending request HTTP 401 HTTP 412
Manual placement: sign_left / sign_bottom Fixed limits for an A4 portrait page (0 to 15 cm / 4 to 28.7 cm), signature height 2.5 cm 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
Manual placement: overlaps Not checked Refused if a signature overlaps another signature of the request or an existing signature of the document
Manual placement: sign_page A page number one higher than the last page was not refused Any page that does not exist is refused

Callbacks follow the version used to create the request: a request created with API v2 keeps receiving API v2 callbacks.

Shopping cart

0
image/svg+xml

No products in the cart.

Continue Shopping
This site is registered on wpml.org as a development site. Switch to a production site key to remove this banner.