# Creating a document

Creating documents differs slightly from other mutations because it involves uploading a file. First, we need to write the *mutation*:

<pre class="language-graphql"><code class="lang-graphql">mutation CreateDocumentMutation(
  $document: DocumentInput!, # Definition of the $document variable
  $signers: [SignerInput!]!, # $signers and $file, with its respective
  $file: Upload!             # types. (The "!" indicate that are
<strong>) {                          # mandatory parameters)      
</strong>  createDocument(
    document: $document,     # Pass the variable values to the mutation parameters
    signers: $signers,       # 
    file: $file,             #
    organization_id: 123,    # OPTIONAL: Creates in other user organizations, otherwise uses the current one
    folder_id: "a1b2c3"      # OPtIONAL: Creates archived in a folder
  ) {
    id
    name
    refusable
    sortable
    created_at
    signatures {
      public_id
      name
      email
      created_at
      action { name }
      link { short_link }
      user { id name email }
    }
  }
}
</code></pre>

Next, we need the values of the variables defined in the mutation in a JSON:

{% code overflow="wrap" %}

```json
/*
 Below, a signer will receive the signature link by email when the "email" field is provided, for a signer added with "name", the "link" attribute will be returned in the document with the signature link.
When using "phone", there are two possible delivery methods defined by the "delivery_method" attribute:
"DELIVERY_METHOD_WHATSAPP" to send via WhatsApp and "DELIVERY_METHOD_SMS" to send via SMS.
*/

{
  "document": {
    "name": "Marketing contract"
  },
  "signers": [{
    "email": "change-this-public-email@tuamaeaquelaursa.com",
    "action": "SIGN"
  }, {
    "name": "Ronaldo Fuzinato",
    "action": "SIGN"
  }, {
    "phone": "+5554999999999",
    "delivery_method": "DELIVERY_METHOD_WHATSAPP",
    "action": "SIGN"
  }, {
    "phone": "+5554999999998",
    "delivery_method": "DELIVERY_METHOD_SMS",
    "action": "SIGN"
  }]
}
```

{% endcode %}

Notice that no value has been provided for the `$file` variable? That's because since the file is being uploaded, the request needs to be sent as `multipart/form-data`, so the file must be handled a bit differently. You can do this directly in  [Altair](https://altair.autentique.com.br/):

<figure><img src="https://1605753490-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIbBzLrA6555E5Ze2GMYf%2Fuploads%2FOwLZxE3VsDiozr3c1iAH%2FCleanShot%202025-10-29%20at%2014.44.45%402x.png?alt=media&#x26;token=a19bdb21-fd23-4c90-b340-a3b2fbc08767" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
If you're unsure how document submission works for your integration, this repository provides more information and examples on how to handle the upload: <https://github.com/jaydenseric/graphql-multipart-request-spec>.
{% endhint %}

### Creating documents on Sandbox

Our API also supports sending test documents, which do not consume document credits, making integration easier for those who have not yet acquired a plan with unlimited documents. To learn how to do this, visit our [sandbox page](https://docs.autentique.com.br/api/integration-basics/sandbox-testes).

### More options:

```json
// IMPORTANT:
// - If you copy this JSON, remove the comments before using it
// - Some of the attributes below will not work without a corporate plan
// - Some of the attributes below will consume additional verification credits

{
  "document": {
    "name": "Marketing contract",
    "message": "Custom message sent to the signer's email",
    "reminder": "WEEKLY", // Weekly signature reminder. DAILY to daily reminder
    "whatsapp_template": "STANDARD", //Selects WhatsApp template. Also accepts the values FORMAL, CASUAL and DIRECT 
    "sortable": true, // Signers sign on the array order "signers"
    "footer": "BOTTOM", // Adds footer. Also accepts the values LEFT and RIGHT
    "refusable": true, // Allows document rejection
    "qualified": true, // Enables qualified signature using certificates
    "scrolling_required": true, // Only allows document signing if the signer has scrolled through the entire page
    "stop_on_rejected": true, // Prevents others from signing when rejected
    "new_signature_style": true, // Enables new signature fields
    "show_audit_page": false, // Prevents creating the last audit page in documents with "new_signature_style": true
    "ignore_cpf": true, // Removes the requirement to fill in CPF to sign and removes any reference to CPF in the platform interface
    "ignore_birthdate": true // Removes the requirement to fill in the date of birth and removes any reference to the date of birth in the platform interface
    "email_template_id": 1234, // Uses a specific email template by its ID
    "deadline_at": "2023-11-24T02:59:59.999Z", // Blocks signatures after date
    "cc": [
      // Sends emails when the document is signed by all signers
      { "email": "email-cc-1@tuamaeaquelaursa.com" },
      { "email": "email-cc-2@tuamaeaquelaursa.com" }
    ],
    "expiration": {
      // Sends a reminder "days_before" days before the document’s due date specified in "notify_at"
      "days_before": 7,
      "notify_at": "20/01/2026"
    },
    "configs": {
      "notification_finished": true, // Sends an email notifying all signers that the document has been signed by all parties
      "notification_signed": true, // Sends an email to the signer notifying that they signed the document
      "signature_appearance": "ELETRONIC", // Forces the signature appearance, can be: DRAW, HANDWRITING, ELECTRONIC, IMAGE
      "keep_metadata": true, // Keeps PDF metadata in qualified signature
      "lock_user_data": true // Keeps outdated user data, showing the information used at the time of signing
    },
    "locale": {
      "country": "BR", // Any country in ISO3166 format, if not provided, defaults to BR
// IMPORTANT The creation of non-Brazilian documents has the following points:
// - Signers with SMS delivery method are not supported. In these cases,
// the request returns the error: sms_delivery_not_allowed_on_foreign_documents;
// - The fields new_signature_style and ignore_cpf are set to true;
// - CPF elements placed on the document pages are ignored;
// - Additional verifications from SERPRO and via SMS are ignored.
      "language": "pt-BR", // Can be: pt-BR or en-US, if not provided, defaults to pt-BR
      "timezone": "America/Sao_Paulo", // DateTimeZone with all time zones, if not provided, defaults to America/Sao_Paulo
// A complete list can be found at: https://www.php.net/manual/en/datetimezone.listidentifiers.php
      "date_format": "DD_MM_YYYY", // Enum, can be: DD_MM_YYYY or MM_DD_YYYY, if not provided, defaults to DD_MM_YYYY
    } 
  },
  "signers": [{
    "email": "change-this-public-email@tuamaeaquelaursa.com", // Envia email
    "action": "SIGN", // Sign
    "configs": { "cpf": "12345678900" }, // Validates the cpf of the signer
    "security_verifications": [
      // Require SMS verification ("verify_phone" is optional):
      { "type": "SMS", "verify_phone": "+5554999999999" },
      // Require photo ID (Manual approval)
      { "type": "MANUAL" }
    ],
    //Positions signature fields:
    "positions": [{"x": "5.0", "y": "90.0", "z": 1, "element": "SIGNATURE"}]
  }, {
    "name": "Ronaldo Fuzinato", // Receives signature links to send
    "action": "SIGN_AS_A_WITNESS", // Sign as a witness
    // Require photo ID (Photo ID)
    "security_verifications": [{ "type": "UPLOAD" }],
    // Position fields for name of the signer
    "positions": [{"x": "75.0", "y": "90.0", "z": 1, "element": "NAME"}]
  }, {
    "email": "change-this-public-email-2@tuamaeaquelaursa.com", // Send email
    "action": "APPROVE", // Approve
    // Require photo ID (Document, selfie, and liveness check)
    "security_verifications": [{ "type": "LIVE" }],
    // Positions initials fields
    "positions": [{"x": "25.0", "y": "90.0", "z": 1, "element": "INITIALS"}]
  }, {
    "phone": "+5521999999999",
    "delivery_method": "DELIVERY_METHOD_SMS", // Send SMS to "phone"
    "action": "RECOGNIZE", // Acknowledge
    // Demand Photo ID (SERPRO biometrics):
    "security_verifications": [{ "type": "PF_FACIAL" }],
    // Position fields of signature date:
    "positions": [{"x": "55.0", "y": "90.0", "z": 1, "element": "DATE"}]
  }, {
    "phone": "+5521999999998",
    "delivery_method": "DELIVERY_METHOD_WHATSAPP", // Sends whatsapp to "phone"
    "action": "SIGN", // Sign
    // Position CPF fields:
    "positions": [{"x": "55.0", "y": "90.0", "z": 1, "element": "CPF"}]
  }]
}
```

### &#x20;Additional Validations

You can implement additional validations in your documents. These configurations must be included in the `security_verifications` list of the signer object, using the `type` field to define the desired challenge modality. In addition to the types, fields such as `verify_phone` and `cpf` assist in the delivery of security codes and in the precise identification of the signer.

| Field / Verification Type       | How it works                                                                                                                                                                                                             |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `verify_phone`                  | The signer must validate a mobile number through a code sent via SMS. You can pre-fill the number or leave it blank so the signer can provide it themselves.                                                             |
| `cpf`                           | Configuration that ensures only the signer with the specified CPF can sign the document. If defined, the system forces the entry or validation of this data in the signer's account                                      |
| `MANUAL`                        | The signer will attach a photo ID and take a selfie. You or a member of your organization can then approve or reject the submitted documents and selfie                                                                  |
| `UPLOAD`                        | The signer must attach the front and back of a photo ID using their smartphone or computer                                                                                                                               |
| `LIVE`                          | The signer will need to attach a photo ID, take a selfie with their smartphone, and perform a liveness check (video). The document photo will be automatically compared to the selfie to verify the degree of similarity |
| `PF_FACIAL`                     | The signer takes a selfie which is validated by SERPRO, comparing it to Brazilian government registration photos linked to the informed CPF                                                                              |
| `BIOMETRIC_AND_TEXT_EXTRACTION` | The signer will need to photograph an ID document and take a selfie, the document photo will be compared with the selfie to determine the similarity score.                                                              |
| `LIVENESS_AND_TEXT_EXTRACTION`  | The signer will need to perform a liveness check and photograph a photo ID. Document information will be automatically extracted and compared to verify the similarity score.                                            |

<details>

<summary><strong>Positioning signature fields "positions"</strong></summary>

As shown in the example above, to add signature fields when creating the document, you need to include the "positions" attribute.

```json
{
  ...
  "signers": [
    {
      ...
      "positions": [
        { "x": "100.0", "y": "100.0", "z": 1, "element": "SIGNATURE" }
      ]﻿
    }
  ]﻿
}
```

The “x” value represents the horizontal position, ranging from 0% to 100%.\
The “y” value represents the vertical position, also ranging from 0% to 100%.\
The “z” value indicates the page number, starting at 1.

\
﻿O `"element"` It's the type of signature\
﻿`"SIGNATURE"`: Signature\
`"NAME"`: Signer's name\
`"INITIALS"`: Initials\
`"DATE"`: Signature date\
`"CPF"`: Signer CPF

To know what positions to pass for x and y, you can create a sample document in the Autentique dashboard and retrieve the positions by fetching the document using "positions":

```graphql
query {
  document(id: "DOCUMENT_ID") {
    id
    signatures {
      public_id
      positions {
        element
        x
        y
        z
      }
    }
  }
}
```

</details>

<details>

<summary><strong>Require SMS verification and/or photo document verification "security_verifications"</strong></summary>

To require signers to verify via SMS and/or photo document, you need to add the "security\_verifications" attribute to the signer for whom these verifications should be required. Remember to check in the dashboard for the cost of additional verification credits needed.

```json
{
  ...
  "signers": [
    {
      ...
      "security_verifications": [
        { "type": "SMS", "verify_phone": "+5554999999999" },
        { "type": "MANUAL" }
      ]﻿
    },
    {
      ...
      "security_verifications": [
        { "type": "BIOMETRIC_AND_TEXT_EXTRACTION" }
      ]﻿
    },
    {
      ...
      "security_verifications": [
        { "type": "BIOMETRIC_AND_TEXT_EXTRACTION", "fallback_behavior": "DISABLE_FALLBACK" }
      ]﻿
    }
  ]﻿
}

```

The "type" is the type of verification:

* **"`SMS`"**: SMS validation ("verify\_phone" is optional and requires a specified phone number)
* **"`MANUAL`"**: Require a photo document (manual approval)
* **"`UPLOAD`"**: Require a photo document (photo document)
* **"`LIVE`"**: Require a photo document (document, selfie, and proof of life)
* **"`PF_FACIAL`"**: Require a photo document (SERPRO biometric verification)
* "**`BIOMETRIC_AND_TEXT_EXTRACTION`**": Require a photo document (photo document and facematch)

While it's possible to have multiple verifications for the same signer, you can only choose one of the following options per signer: **`MANUAL`**, **`UPLOAD`**, **`LIVE`**, and **`PF_FACIAL`**.

\
When the types **`UPLOAD`**, **`LIVE`**, **`PF_FACIAL`** and **`BIOMETRIC_AND_TEXT_EXTRACTION`** are used, there is a default behavior where they are changed to `MANUAL` when the signer exceeds the maximum number of attempts in the document validation process. \
To disable this behavior, you must use the `fallback_behavior` parameter, which will flag the document as failed and automatically reject it.

</details>

<details>

<summary><strong>Create a document from a template</strong></summary>

There is no way in the API to directly use the panel templates to create documents. However, you can achieve something similar through your code:

1. **Create a fixed HTML template** on your machine, marking the places with variables to be replaced by values. (e.g., "I, $NomeSignatario$, accept this contract")
2. **Programmatically duplicate this HTML** and in the duplicate, replace the variable fields with the actual values. (e.g., `$NomeSignatario$` → Jorge Silva)
3. **Send this HTML file** with the replaced values to our API through the `createDocument` mutation, just like it works for other types of files.

</details>

<details>

<summary><strong>Example of document creation with NodeJS</strong></summary>

If you use Postman, you can generate these examples from the Postman collection provided here in the [documentation](https://app.gitbook.com/o/-LXffZ8CxVTA5RCf4Vxb/s/IbBzLrA6555E5Ze2GMYf/).

```javascript
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
data.append('operations', '{"query":"mutation CreateDocumentMutation($document: DocumentInput!, $signers: [SignerInput!]!, $file: Upload!) {createDocument(document: $document, signers: $signers, file: $file) {id name refusable sortable created_at signatures { public_id name email created_at action { name } link { short_link } user { id name email }}}}", "variables":{"document": {"name": "Test contract"},"signers": [{"email": "change-this-public-email@tuamaeaquelaursa.com","action": "SIGN"}],"file":null}}');
data.append('map', '{"file": ["variables.file"]}');
data.append('file', fs.createReadStream('/path/to/file'));
var config = {
  method: 'post',
  url: 'https://api.autentique.com.br/v2/graphql',
  headers: {
    'Authorization': 'Bearer API_TOKEN',
    ...data.getHeaders()
  },
  data : data
};
axios(config)
  .then(function(response) { console.log(JSON.stringify(response.data)); })
  .catch(function(error) { console.log(error); });
```

For this example, just replace the API token, the signer's email, and the file path.

</details>

<details>

<summary><strong>Example of document creation with PHP</strong></summary>

If you use Postman, you can generate these examples from the Postman collection provided here in the documentation [documentation](https://app.gitbook.com/o/-LXffZ8CxVTA5RCf4Vxb/s/IbBzLrA6555E5Ze2GMYf/).

```php
<?php

$curl = curl_init();
curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.autentique.com.br/v2/graphql',
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array('operations' => '{"query":"mutation CreateDocumentMutation($document: DocumentInput!, $signers: [SignerInput!]!, $file: Upload!) {createDocument(document: $document, signers: $signers, file: $file) {id name refusable sortable created_at signatures { public_id name email created_at action { name } link { short_link } user { id name email }}}}", "variables":{"document": {"name": "Contrato de teste"},"signers": [{"email": "change-this-public-email@tuamaeaquelaursa.com","action": "SIGN"}],"file":null}}','map' => '{"file": ["variables.file"]}','file'=> new CURLFILE('/path/to/file')),
  CURLOPT_HTTPHEADER => array('Authorization: Bearer API_TOKEN'),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
```

In this example, you just need to replace the API token, the signer's email, and the file path.

</details>

<details>

<summary><strong>Example of document creation with Python3</strong></summary>

If you use Postman, you can generate these examples from the Postman collection provided here in the documentation [documentation](https://app.gitbook.com/o/-LXffZ8CxVTA5RCf4Vxb/s/IbBzLrA6555E5Ze2GMYf/).

```python
import requests

url = "https://api.autentique.com.br/v2/graphql"
payload = {
  'operations': '{"query":"mutation CreateDocumentMutation($document: DocumentInput!, $signers: [SignerInput!]!, $file: Upload!) {createDocument(document: $document, signers: $signers, file: $file) {id name refusable sortable created_at signatures { public_id name email created_at action { name } link { short_link } user { id name email }}}}", "variables":{"document": {"name": "Test contract"},"signers": [{"email": "change-this-public-email@tuamaeaquelaursa.com","action": "SIGN"}],"file":null}}',
  'map': '{"file": ["variables.file"]}'
}
files = [
  ('file',open('/path/to/file.pdf','rb'))
]
headers = {
  'Authorization': 'Bearer API_TOKEN'
}

response = requests.request("POST", url, headers=headers, data=payload, files=files)
print(response.text)
```

In this example, you just need to replace the API token, the signer's email, and the file path.

</details>

<details>

<summary><strong>Example of document creation with C#</strong></summary>

If you use Postman, you can generate these examples from the Postman collection provided here in the documentation [documentation](https://app.gitbook.com/o/-LXffZ8CxVTA5RCf4Vxb/s/IbBzLrA6555E5Ze2GMYf/).

```csharp
var client = new RestClient("https://api.autentique.com.br/v2/graphql");
var request = new RestRequest(Method.POST);

request.AddHeader("Authorization", "Bearer API_TOKEN");
request.AddParameter("operations", "{\"query\":\"mutation CreateDocumentMutation($document: DocumentInput!, $signers: [SignerInput!]!, $file: Upload!) {createDocument(document: $document, signers: $signers, file: $file) {id name refusable sortable created_at signatures { public_id name email created_at action { name } link { short_link } user { id name email }}}}\", \"variables\":{\"document\": {\"name\": \"Contrato de teste\"},\"signers\": [{\"email\": \"change-this-public-email@tuamaeaquelaursa.com\",\"action\": \"SIGN\"}],\"file\":null}}");
request.AddParameter("map", "{\"file\": [\"variables.file\"]}");
request.AddFile("file", "/path/to/file");
IRestResponse response = client.Execute(request);

Console.WriteLine(response.Content);
```

In this example, you just need to replace the API token, the signer's email, and the file path.

</details>

{% hint style="info" %}
You can check what each of these parameters means directly in the full GraphQL API documentation, in the Docs menu of [Altair](https://altair.autentique.com.br/). If you're not sure how to do that, check out our tutorial on [**Using Altair**](https://docs.autentique.com.br/api/integration-basics/altair).
{% endhint %}

{% file src="<https://content.gitbook.com/content/IbBzLrA6555E5Ze2GMYf/blobs/UYhF3Z8hbSdJj5dx0FvZ/Autentique%20v2.postman_collection.json>" %}
Para importar e usar no Postman
{% endfile %}
