Manual QI Sign
QI Tech webhooks should not be mapped strictly. Additional fields may be included in the webhook payloads returned by our APIs.
Introduction
Welcome to the QiTech Signatures API! This API provides access to the electronic document signature service.
Problems?
If you encounter any issues, please contact our support team (suporte@qitech.com.br), and we will respond as quickly as possible.
Environments
We provide two environments for our clients. The base API URLs are:
- Production -
https://api.sign.qitech.com.br/ - Sandbox -
https://api.sandbox.sign.qitech.com.br/
HTTPS Only
For security reasons, all communication with QI Tech APIs must be conducted via HTTPS. To prevent HTTP calls—whether due to oversight or other reasons—this server only provides port 443 with TLS 1.2 communication. Calls made using other protocols will be automatically denied.
Authentication
To authenticate a request, use the following code:
# In the shell, you only need to add the appropriate header to each request
curl "api_endpoint_here"
-H "Authorization: EXAMPLE_API_KEY"
Replace the API key 'EXAMPLE_API_KEY' with your key acquired from our support.
We use an API Key to allow access to our API. It has likely already been sent to you via email. If you haven't received your key yet, send an email to suporte@qitech.com.br.
Our API expects to receive the API Key in all requests to our server in a header like the one below:
Authorization: EXAMPLE_API_KEY
Envelopes are the objects containing documents to be electronically signed. They are created from one or more files and can be sent for signature via email, SMS, or WhatsApp. To create an envelope, you must send a file or a set of files to the API. The envelope will be created, and you will receive a unique identifier for it.
Creating an Envelope
To create an Envelope, make a POST call to the /sign/envelope endpoint with the signer(s) data..
curl -X POST \
https://api.sign.qitech.com.br/sign/envelope \
-H 'Content-Type: application/json' \
-H "Authorization: EXAMPLE_API_KEY" \
-d '{
"id": "814e7ed3-4080-4cae-a853-8e12812817ea",
"subject": "CCB QiTech",
"expiration_date": "2023-09-20",
"signers": [
{
"id": "1",
"name": "John Sample",
"email": "johnsample@test.com",
"birthdate": "1992-09-15",
"document_number": "111.111.111-11",
"phone": {
"international_dial_code": "55",
"area_code": "11",
"number": "988878722"
},
"document_submission_method": "email",
"authentication_submission_method": "sms"
}
]
}'
Envelope Object Definition
All information exchanges for an envelope use the following definition for this object. In some cases, to facilitate implementation and reduce data flow between parties, some information may be omitted.
| Name | Type | Description |
|---|---|---|
| id | string | Unique identifier for the envelope. It is essential that this number is unique |
| subject | string | Envelope title. Appears in the email subject. |
| expiration_date | string | Envelope expiration date in YYYY-MM-DD format. |
| signers | list | List of Signer-type objects describing the envelope's signers. |
Signer Object Definition
| Name | Type | Description |
|---|---|---|
| id | string | Signer transaction identifier. It is essential that this number is unique per envelope |
| string | Signer's email address. | |
| name | string | Signer's full name. |
| birthdate | string | Signer's birthdate in YYYY-MM-DD format. |
| document_number | string | Signer's document number. |
| phone | object | Object describing the signer's phone.. |
| phone.international_dial_code | string | Country code for the signer's phone. |
| phone.area_code | string | Area code for the signer's phone. |
| phone.number | string | Signer's phone number. |
| document_submission_method | enum | Method for sending documents for signature. Available methods: _email, sms e whatsapp _ |
| authentication_submission_method | enum | Method for sending the authentication token for signature. Available methods: _email, sms e whatsapp _ |
- The email and phone fields can be sent together or separately, but at least one must be provided.
- All fields are mandatory.
Envelope Creation Response
After successful envelope creation, the response will be a JSON containing the envelope's id and status, as shown in the example:
Example response
{
"id": "814e7ed3-4080-4cae-a853-8e12812817ea",
"status": "created"
}
Adding Identification Documents to the Signer
To add identification documents to a signer, make a POST call to the /sign/envelope/\{envelope_id\}/signer/\{signer_id\}/personal_document endpoint for each document to be added. The file must be sent in the request body following this format:
{
"document_b64": "Q5YACgAAAABDlgAbAAAAAEOWAC0AAAAAQ5YAPwAAAABDlgdN...",
"template": "cnh_front",
"file_type": "jpeg"
}
Available Templates
For each type of identification document, the corresponding template must be informed. The available templates are:
| Template | Description |
|---|---|
| cnh_front | Brazilian National Driver's License (CNH) front (photo side). |
| cnh_back | Brazilian National Driver's License (CNH) back (signature side). |
| rg_front | Brazilian ID Card (RG) front (photo side). |
| rg_back | Brazilian ID Card (RG) back (data side). |
Submission Attribute Description
| Attribute | Description |
|---|---|
| document_b64 | Base64 encoded identification document. |
| template | Declares the template to be applied for image analysis. |
| file_type | Identifies the format of the sent file, jpeg. If not sent, jpeg is assumed. |
- The maximum size for the identification document is 10 MB
- All fields are mandatory except for
file_type.
Identification Document Addition Response
After successfully adding identification documents, the response will be a JSON containing the created_at timestamp, as shown in the example:
Example response
{
"created_at": "2023-01-01T00:00:00.000Z"
}
Identification Document Collection
If an identification document is not sent for the signer, it will be requested for collection at the time of signature.
Adding Documents to the Envelope
To add documents for signature to an envelope, make a POST call to the /sign/envelope/\{envelope_id\}/document endpoint for each document to be added. The file must be sent in the request body following this format:
{
"id": "3dfc5526-ee47-4b63-ad97-ddaf5b1c9110",
"document_b64": "Q5YACgAAAABDlgAbAAAAAEOWAC0AAAAAQ5YAPwAAAABDlgdN...",
"name": "Laudo de vistoria de entrada",
"document_type": "pdf"
}
- The maximum document size is 10 MB
Document Object Definition
| Name | Type | Description |
|---|---|---|
| id | string | Document identifier. It is essential that this number is unique within the envelope Optional CIf not provided, we will generate a 36-character UUID4 standard GUID. |
| document_b64 | string | Documento codificado em base64. |
| Name | string | Document name. |
| document_type | enum | Document type. Available type: pdf |
Document Addition Response
After successfully adding documents to the envelope, the response will be a JSON containing the document identifier and the creation date, as shown in the example below:
Example response
{
"id": "3dfc5526-ee47-4b63-ad97-ddaf5b1c9110",
"created_at": "2023-01-01T00:00:00.000Z"
}
Sending the Envelope for Signature
To send the envelope for signature, make a PATCH call to the /sign/envelope/\{envelope_id\} endpoint.
curl -X PATCH \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\} \
-H "Authorization: EXAMPLE_API_KEY" \
-d '{
"status": "submitted"
}'
Envelope Submission Response
After successfully sending the envelope for signature, the response will be a JSON containing the envelope status, as shown in the example below:
Example response
{
"status": "submitted"
}
After sending the envelope for signature, signers will receive an email or a message with the link to sign the documents.
Upon accessing the link, the signer must fill in their CPF, sign the document, and undergo the facial and/or document validation flow depending on the partner's workflow. After signing, the signer will be redirected to the success page.
Querying Envelope Data
To check envelope data, such as status and signers, make a GET call to the /sign/envelope/\{envelope_id\} endpoint.
curl -X GET \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\} \
-H "Authorization: EXAMPLE_API_KEY"
If the request is successful, the response will be a JSON containing the envelope status and information about the signers, as shown in the example below:
Example response
{
"id": "814e7ed3-4080-4cae-a853-8e12812817ea",
"subject": "Laudo de vistoria de entrada",
"expiration_date": "2023-09-20T02:59:59Z",
"status": "completed",
"signers": [
{
"id": "1",
"name": "John Sample",
"email": "johnsample@test.com",
"birthdate": "1992-09-15",
"document_number": "111.111.111-11",
"phone": {
"international_dial_code": "55",
"area_code": "11",
"number": "988878722"
},
"document_submission_method": "email",
"authentication_submission_method": "email",
"status": "signed",
"signed_at": "2023-03-21T15:30:00.000Z",
"signature_url": "https://sign.qitech.com.br/s/s2S33dD",
"documents": [
{
"id": "8d3c3f1a-1a1a-1a1a-1a1a-1a1a1a1a1a1a",
"name": "Laudo de vistoria de entrada",
"document_type": "pdf"
}
]
}
]
}
- The envelope status can be
created,submitted,completed,canceledouexpired.
| Enumerators | Description |
|---|---|
| created | Envelope created |
| submitted | Envelope sent for signature |
| completed | When all signatures for the envelope have been successfully completed |
| canceled | Envelope canceled at the partner's request |
| expired | Envelope expired due to signature time limit |
| Name | Type | Description |
|---|---|---|
| id | string | Unique identifier for the envelope. |
| status | string | Envelope status. |
| expiration_date | string | Envelope expiration date. |
| signers | Signer | List of Signer-type objects describing the envelope's signers. |
| documents | Document | List of Document-type objects describing the envelope's documents. |
Webhook
When all signers finish signing and the dossier is generated, a Webhook call will be triggered. To enable this, it is necessary to configure—via the support team (suporte@qitech.com.br)—an endpoint address where we will notify updates, as well as a signature_key that will be used to sign the request.
Clients may also—though it is not recommended—use the polling technique. In this case, simply do not configure the webhook endpoint and use the registration recovery endpoints to proceed with polling.
Signature
Example of signature calculation in Python
hmac_obj = hmac.new(signature_key.encode('utf-8'), (endpoint + method + payload).encode('utf-8'), hashlib.sha1)
return hmac_obj.hexdigest()
To ensure that the request received at the webhook endpoint originates from our servers, an HMAC signature is sent in the Signature Header, similar to the authentication process.
After calculating the expected signature value on the server side, you must compare the calculated signature with the sent one. If the signatures match, it means the request originated from our servers and is trustworthy.
Example webhook call:
{
"id": "479f8e5a-75e1-4a33-9d75-e0083e3c8e9c",
"status": "completed",
"webhook_type": "envelope_completed",
"signers": [
{
"id": "c15392dd-7859-4eae-a2b6-bf0f760a6d9b",
"biometry": {
"face_validation_available": true,
"fraud_base_flag": false,
"face_validation_score": 90
},
"liveness": {
"result": "live"
},
"document": {
"face_match_score": 85
}
}
]
}
| Name | Type | Description |
|---|---|---|
| id | string | Unique identifier for the envelope. |
| status | string | Envelope status. |
| signer.id | string | Unique identifier for the signer. |
| signer.biometry.face_validation_available | boolean | Indicates if the face was found and validated. |
| signer.biometry.fraud_base_flag | boolean | Indicates if the signer's face was found in the fraud database. |
| signer.biometry.face_validation_score | integer | Indicates the facial validation score. |
| signer.liveness.result | string | Indicates the result of the liveness validation. Possible values: live or spoof |
| signer.document.face_match_score | integer | Indicates the face match validation score. |
Downloading Signed Dossiers
If all signers have signed all documents in the envelope, the envelope status will be completed, and a dossier for each document, with signatures and signer data, will be available for download. To do this, make a GET call to the /sign/envelope/\{envelope_id\}/report endpoint.
curl -X GET \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\}/report \
-H "Authorization: EXAMPLE_API_KEY"
If the request is successful, the response will be a JSON containing the envelope id and status, plus a list with the document id and the generated dossier URL, as shown in the example below:
Example response
{
"id": "479f8e5a-75e1-4a33-9d75-e0083e3c8e9c",
"status": "available",
"documents_reports": [
{
"id": "a50ef632-842e-4622-8075-684b8c83a99e",
"url": "https://qisign-dossiers.com/06abda52-5bd1-46a1-8fa2-f616ba44b395.pdf"
}
]
}
- The report link for each document will be valid for 24 hours.
- The status of reports for the envelope can be
availableorunavailable. - The property
documents_reportscontains the list of envelope documents, identified by document id and their report link.
Downloading Dossier by Signed Document
If all signers have signed all documents in the envelope, the envelope status will be completed and a dossier for each signed document, with signatures and signer data, will be available for download. To do this, make a GET to the endpoint /sign/envelope/\{envelope_id\}/document/{document_id}/report
curl -X GET \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\}/document/{document_id}/report \
-H "Authorization: EXAMPLE_API_KEY"
If the request is successful, the response will be a JSON containing the id, status, url, and the base64 of the document dossier, as shown in the example below:
Example response
{
"id": "5b930d3d-3713-4c42-85d5-f8e9e44e30ce",
"status": "available",
"document_report_url": "https://qisign-dossiers.com/7bcf5868-784a-4356-85fb-dd72fd53cd4a.pdf",
"document_report": "vAsXDdsaGUsdIMIGxhIG1GU=..."
}
- The link for the document report will be valid for 24 hours.
- The status for the document report can be
availableorunavailable. - The property
document_reportis the document report in PDF format encoded in base64.
Downloading Signer Face Photos
It is possible to retrieve images of the signers' faces. To do this, simply make a GET call to the endpoint /sign/envelope/\{envelope_id\}/signer/\{signer_id\}/face
curl -X GET \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\}/signer/\{signer_id\}/face \
-H "Authorization: EXAMPLE_API_KEY"
If the request is successful, the response will be a JSON containing the base64 encoded image, as shown in the example below:
Example response
{
"face_image_url": "https://qisign-face-image.com/4fd09dab-6f3e-4ff5-bfed-6f7debfcde71.jpeg"
}
Canceling an Envelope
To cancel an envelope, make a PATCH call to the endpoint /sign/envelope/\{envelope_id\}
curl -X PATCH \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\} \
-H "Authorization: EXAMPLE_API_KEY" \
-d '{
"status": "canceled"
}'
If the request is successful, the response will be a JSON containing the envelope status, as shown in the example below:
Example response
{
"status": "canceled"
}
Downloading Signer Document Photos
It is possible to retrieve images of the signers' documents. To do this, simply make a GET call to the endpoint /sign/envelope/\{envelope_id\}/signer/\{signer_id\}/personal_document
curl -X GET \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\}/signer/\{signer_id\}/personal_document \
-H "Authorization: EXAMPLE_API_KEY"
If the request is successful, the response will be a JSON containing the base64 encoded image, as shown in the example below:
Example response
{
"document_front_url": "https://qisign-personal-documents.com/bee17d70-b029-41e2-b76b-86f64a8f9213.jpeg",
"document_back_url": "https://qisign-personal-documents.com/faf38378-daa2-47b2-9d87-0bbc1f7c744c.jpeg"
}
Checking Signer Status
To check a signer's status, make a GET call to the endpoint /sign/envelope/\{envelope_id\}/signer/\{signer_id\}
curl -X GET \
https://api.sign.qitech.com.br/sign/envelope/\{envelope_id\}/signer/\{signer_id\} \
-H "Authorization: EXAMPLE_API_KEY"
If the request is successful, the response will be a JSON containing the signer's status, as shown in the example below:
Example response
{
"name": "John Sample",
"email": "johnsample@test.com",
"status": "signed",
"signed_at": "2023-03-21T15:30:00.000Z"
}
| Name | Type | Description |
|---|---|---|
| name | string | Signer's name. |
| string | Signer's email. | |
| status | string | Signer's signature status. |
| signed_at | string | Date and time of the last signature in YYYY-MM-DDTHH:MM:SS.000Z format. |
HTTP Status Codes
A API de assinatura utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231:
| Status HTTP | Significado | Descrição |
|---|---|---|
| 400 | Bad Request | The sent request has a formatting error. In most cases, we return an explanation of where the error is in the message body. |
| 401 | Unauthorized | There was an issue with authentication; verify if the API Key is correct and in the proper header, as per the Authentication. |
| 403 | Forbidden | The accessed endpoint is for internal use and is not available for this API Key. |
| 404 | Not Found | The requested data was not found using the provided key. This status is also returned when an invalid endpoint is requested. |
| 405 | Method Not Allowed | The HTTP method used does not apply to the used endpoint. |
| 406 | Not Acceptable | The data sent in the request body is invalid. Generally, this means the data sent is not valid JSON. |
| 409 | Conflict | The request ID corresponds to an ID already processed. This status is returned for duplicate requests sent to the server. |
| 500 | Internal Server Error | We encountered an issue processing this request; when this error occurs, our specialists are automatically notified and immediately begin analysis and resolution. |
| 503 | Service Unavailable | You have encountered an infrastructure unavailability—planned or unplanned—of our servers. |