> For the complete documentation index, see [llms.txt](https://docs.mindee.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mindee.com/v1/apis-overview/endpoints/prediction-asynchronous.md).

# Asynchronous Prediction

## 1. Send a Document

### URL

{% hint style="info" %}
`POST` /predict\_async

**<https://api.mindee.net/v1/products/**_`><account>`_**/**_`<name>`_**/**_`<version>\`\_**/predict\_async\*\*
{% endhint %}

To make asynchronous predictions, make sure your document parsing API supports asynchronous mode, then select:

* `<account>` refers to the account name that owns the API:\
  \- For [docTI APIs](doc:docti-overview), this is your user name or organization name.\
  \- For [Off-the-shelf APIs](doc:what-is-off-the-shelf-api), use **`mindee`** as the account name.
* `<name>/<version>` refers to the API name and preferred version as described in your [API Documentation](doc:platform-tour#api---documentation). For Off-the-shelf APIs, a new version may not be fully backward compatible and bring new features and better performance.

### Prepare payload

The Prediction endpoint can handle three types of payload in order to send your document:

* a binary file
* a base64 encoded file
* a URL

\_See [Document inputs](doc:document-inputs) for more information on supported files. \_

#### Binary File

Use a `multipart/form-data` encoding to send your document:

```curl
curl -X POST 
  https://api.mindee.net/v1/products/<account>/<name>/<version>/predict_async 
  -H 'Authorization: Token <my-api-key-here>' 
  -F document=@/path/to/your/file.png
```

#### Base64 Encoded File

Prepare a JSON payload:

```json
{
  "document": "/9j......"
}
```

Send your request with an `application/json` encoding:

```shell
curl -X POST \
  https://api.mindee.net/v1/products/<account>/<name>/<version>/predict_async \
  -H 'Authorization: Token <my-api-key-here>' \
  -H 'Content-Type: application/json' \
  -d 'document="/9j..."'
```

#### Public URL

Prepare a JSON payload with the URL included. Only valid public HTTPS links are accepted:

```json
{
  "document": "https://mydomain.com/my_file.pdf"
}
```

Send your request with an `application/json` encoding:

```shell
curl -X POST \
  https://api.mindee.net/v1/products/<account>/<name>/<version>/predict_async \
  -H 'Authorization: Token <my-api-key-here>' \
  -H 'Content-Type: application/json' \
  -d '{"document":"https://mydomain.com/my_file.pdf"}'
```

### JSON Response

*See* [*Endpoints*](doc:endpoints-new) *for general description of Mindee's REST API response format.*

Here is an example JSON Response from the asynchronous prediction endpoint, in case your document passes all the validation checks performed by Mindee API. (see [Document Inputs](doc:document-inputs) for more information)

```json
{
    "api_request": {
        "error": {},
        "resources": ["job"],
        "status": "success",
        "status_code": 202,
        "url": "https://api.mindee.net/v1/products/<account>/<name>/<version>/predict_async"
    },
    "job": {
        "available_at": null,
        "id": "072c509b-ea8e-491e-99e0-795c0be8c59c",
        "issued_at": "2024-02-23T16:35:50.364723",
        "status": "waiting",
        "error": {},
        "polling_url": "https://api.mindee.net/v1/documents/queue/072c509b-ea8e-491e-99e0-795c0be8c59c"
    }
}
```

Otherwise, see [Error Management](doc:error-management).

## 2. Get Prediction with Webhooks

*See* [*Webhooks*](doc:webhooks) *to learn how to setup your webhook.*

Once your webhook is correctly setup, you will start to receive your prediction directly on your endpoint as a POST request, with a JSON payload. You must return a successful request status\_code (`2xx`). Any complex or time-consuming logic happening in your endpoint may cause a timeout.

### JSON Response

When calling the prediction endpoint, the parsed information from your documents can be found in the `document` key.

When receiving the JSON payload on your webhook endpoint, the parsed information from your documents can be found in the `document` key. The `job` key contains some information about your asynchronous job.

```json
{
    "document": {
        "id": "bb47bbab-8c97-4e83-a793-e401bdde3685",
        "inference": {
            "extras": {},
            "finished_at": "2024-02-23T16:35:54.909000",
            "is_rotation_applied": null,
            "prediction": { .. },
            "pages": [
              {
                "id": 0,
          	    "orientation": {"value": null},
          	    "extras": {},
          	    "prediction": { .. }
             },
              {
                "id": 1,
                "orientation": {"value": null},
                "extras": {},
                "prediction": { .. }
              }
            ],
            "processing_time": 2.623,
            "product": { .. },
            "started_at": "2024-02-23T16:35:50.364723"
        },
        "n_pages": 2,
        "name": "myfile.pdf"
    },
    "job": {
        "available_at": "2024-02-23T16:35:54.931372",
        "id": "072c509b-ea8e-491e-99e0-795c0be8c59c",
        "issued_at": "2024-02-23T16:35:50.364723",
        "status": "completed",
        "error": {}
    }
}
```

If the processing of your document has failed:

```json
{
  "job": {
    "available_at": "2024-02-23T16:35:54.931372",
    "error": {
      "code": "ServerError",
      "details": "An error occurred",
      "message": "An error occurred"
    },
    "id": "072c509b-ea8e-491e-99e0-795c0be8c59c",
    "issued_at": "2024-02-23T16:35:50.364723",
    "status": "failed"
  }
}
```

#### Document

*Describes the uploaded document*

| key         | type     | description                                                   |
| ----------- | -------- | ------------------------------------------------------------- |
| `id`        | *string* | a unique identifier                                           |
| `name`      | *string* | the filename                                                  |
| `n_pages`   | *number* | the number of pages                                           |
| `inference` | *object* | a JSON object with the content of your inference (prediction) |

#### Document > Inference

*Contains the whole inference data (predictions)*

\[block:parameters] { "data": { "h-0": "key", "h-1": "type", "h-2": "description", "0-0": "`started_at`", "0-1": "*string*", "0-2": "the date & time the inference has started in ISO 8601 format", "1-0": "`finished_at`", "1-1": "*string*", "1-2": "the date & time the inference was finished in ISO 8601 format", "2-0": "`processing_time`", "2-1": "*number*", "2-2": "the request processing time in seconds", "3-0": "`is_rotation_applied`", "3-1": "*boolean* or *null*", "3-2": "**true**: polygons are *already* rotated given the page orientation \n**false**: polygons are *never* rotated \n**null**: the API has no orientation information", "4-0": "`prediction`", "4-1": "*object*", "4-2": "a JSON object with the document-level API prediction", "5-0": "`pages`", "5-1": "*list\[object]*", "5-2": "a JSON object with the page-level inference data" }, "cols": 3, "rows": 6, "align": \[ "left", "left", "left" ] } \[/block]

#### Document > Inference > Pages\[ ]

*Contains the page-level specific inference data (predictions)*

\[block:parameters] { "data": { "h-0": "key", "h-1": "type", "h-2": "description", "0-0": "`id`", "0-1": "*number*", "0-2": "the page index", "1-0": "`orientation.value`", "1-1": "*number*", "1-2": "the clockwise rotation to apply to get the page upright \nExamples: **0**, **90**, **180**, **270** ", "2-0": "`prediction`", "2-1": "*object*", "2-2": "a JSON object with the page-level API prediction" }, "cols": 3, "rows": 3, "align": \[ "left", "left", "left" ] } \[/block]

#### Job

\[block:parameters] { "data": { "h-0": "key", "h-1": "type", "h-2": "description", "0-0": "`id`", "0-1": "*string*", "0-2": "a unique identifier", "1-0": "`available_at`", "1-1": "*string*", "1-2": "the date & time your predictions were available in ISO 8601 format", "2-0": "`issued_at`", "2-1": "*string*", "2-2": "the date & time your document was enqueued in ISO 8601 format", "3-0": "`status`", "3-1": "*string*", "3-2": "the status of your document inference \nCan be one of: **completed**, **failed**, **processing**, **waiting**", "4-0": "`error`", "4-1": "*object*", "4-2": "a JSON object error information" }, "cols": 3, "rows": 5, "align": \[ "left", "left", "left" ] } \[/block]

### Prediction example

Each API can describe several fields within its `prediction` object.

```json
{
  "prediction": {
    "total_amount": {
      "value": 16.50,
    },
    "taxes": [
      {"value": 2.75, "rate": 20},
    ],
  }
}
```

### Validate the HMAC Signature (Optional)

Mindee webhooks use a basic HMAC signature to ensure the integrity and authenticity of the data being transmitted. It is optional, but strongly recommended to verify this signature when receiving data, to secure your webhook endpoint by ensuring that all incoming requests are generated by Mindee.

To find the generated signature, look for the `X-Mindee-Hmac-Signature`header. You will also need your own `Signing Secret` from Mindee's Platform.

\_In the following code examples, `my_secret_key` is your `Signing Secret`.

```python
from mindee.client import LocalResponse

my_secret_key = ""

# Load from string
local_response = LocalResponse(request.body())

# You can also load the json from a local path.
# local_response = LocalResponse("path/to/my/file.ext")

# You'll need to get the "X-Mindee-Hmac-Signature" custom HTTP header.
hmac_signature = request.headers.get("X-Mindee-Hmac-Signature")

if not local_response.is_valid_hmac_signature(my_secret_key, hmac_signature):
    raise Error("Bad HMAC signature! Is someone trying to do evil?")
 
```

```java
import com.mindee.input.LocalResponse;

String jsonData = myHttpServer.getPostBodyAsString();
LocalResponse localResponse = new LocalResponse(jsonData);

// You can also use a File object as the input.
//LocalResponse localResponse = new LocalResponse(new File("/path/to/file.json"));

// You'll need to get the "X-Mindee-Hmac-Signature" custom HTTP header.
String hmacSignature = myHttpServer.getHeader("X-Mindee-Hmac-Signature");

boolean isValid = localResponse.isValidHmacSignature(
  "obviously-fake-secret-key", hmacSignature
);
if (!isValid) {
  throw new MyException("Bad HMAC signature! Is someone trying to do evil?");
}
```

```javascript

function try_verif() {
    const hash = crypto.createHmac(
        'sha256', SECRET
    ).update(PAYLOAD).digest('hex')

    console.log(hash === SIGNATURE)
}
// should log true if the calculated hash equals to the received signature,  false otherwise.
```

## 3. Get my prediction with polling

If for any reason, you need to retrieve your document prediction manually, an alternative method is to use our polling endpoint.

### Retrieve your job status

{% hint style="info" %}
`GET` /documents/queue/*\<job\_id>*

\*\*<https://api.mindee.net/v1/products/**_`><account>`_**/**_`<name>`_**/**_`<version>`_**/documents/queue/**_`\<job\_id>\`\_
{% endhint %}

While your job is still in `waiting` or `processing` status, you will receive a simple JSON response with information on your enqueued job, with a `200` status code.

```json
{
    "api_request": { .. },
    "job": {
        "available_at": null,
        "id": "072c509b-ea8e-491e-99e0-795c0be8c59c",
        "issued_at": "2024-02-23T16:35:50.364723",
        "status": "processing",
        "error": {}
    }
}
```

### Retrieve your document predictions

Once your job is `completed`, the endpoint will return a `302 Found` redirect status code, redirecting you on `https://api.mindee.net/v1/products/<account>/<name>/<version>/documents/<document_id>`, with the final `document_id` provided.

The JSON response of this endpoint is exactly the same as what you would have received on your endpoint with a webhook enabled.

{% hint style="success" %}
👍 **Success**

To know more about your document parsing API response, especially the prediction object's structure, you can access the [Documentation part of your API](/v1/platform-ui-tour/api-documentation.md) on Mindee's platform.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.mindee.com/v1/apis-overview/endpoints/prediction-asynchronous.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
