Skip to content

Asynchronous processing of Smartscan

Logo

The asynchronous processing of Smartscan allows you to submit a document for processing and receive the results at a later time. This feature is particularly useful for large documents that require more time to process.

Getting started

Asynchronous processing workflow

The asynchronous processing of Smartscan is built around Transactions. A Transaction is a request to process a document with a list of features - the data points you want to extract from the document. The transaction can be tagged with a custom ID for easier tracking and deletion. The workflow consists of the following steps:

  1. Create Transaction: Submit a document for processing with a list of features and optional tags and custom ID.
  2. Get Transaction Status: Check the status of the transaction to see if it is completed or failed.
  3. Get Transaction Results: Retrieve the extracted data from the document.
  4. Delete Transaction: Delete the transaction and its data if needed.

Access to the API

  1. Demo Access Token

    For development purposes, you can use the demo access token demo, like in the example below, for access to staging. Use the staging endpoints indicated in the endpoints section. Please note that this token is rate-limited and should only be used for testing. We strongly advise you to not use demo token for any sensitive data as anyone with the token can access the data. The demo token only covers creating a transaction (POST /v1/transactions) and reading its status and results (GET /v1/transactions/...); updating results, deleting transactions and deleting tags require a project token — see Authentication.

  2. Staging Access Token (Recommended)

    For more extensive testing and integration purposes, we recommend generating a staging access token through our Staging portal. Follow the steps in the Quick Start Guide for generating a staging or production access tokens. Refer to the Authentication for more information on the server-to-server token method.

Example requests

Create Transaction Request


POST v1/transactions

https://api.stag.ssn.visma.ai/v1/transactions

Authorization - Bearer Token

Token: demo


Body - raw (json)

Body
{
    "document": {
        "source": {
            "httpUri": "http://storage.googleapis.com/vml-test-data/distributable/pdf5/10.pdf"
        }
    },
    "features": [ "RECEIVER_COUNTRY_CODE", "IBAN" ],
    "tags": ["testing"],
    "customId": "my-first-transaction"
}


Information

customId is optional, but it must be unique within your project. Creating another transaction with a customId that is already in use is rejected with 409 Conflict (ALREADY_EXISTS). Delete the existing transaction first if you need to reuse the identifier.

Create Transaction Response


Body - raw (json)

Body
{
    "id": "<transaction-id>",
    "customId": "my-first-transaction"
}


Get Transaction Status Request

You can get transaction status either by the transaction ID or the custom ID. The transaction ID is unique for each transaction, while the custom ID is optional and can be set by the user.


GET v1/transactions/{transaction_id}/status

https://api.stag.ssn.visma.ai/v1/transactions/<transaction-id>/status

Authorization - Bearer Token

Token: demo


Calling the Get Transaction Status endpoint with the custom ID:


GET v1/transactions/status?custom_id={custom_id}

https://api.stag.ssn.visma.ai/v1/transactions/status?custom_id=my-first-transaction

Authorization - Bearer Token

Token: demo


Get Transaction Status Response

The status of the transaction can be CREATED, RUNNING, PENDING_VERIFICATION, DONE, PARTIAL, or FAILED.

PARTIAL is a terminal state, returned when some of the requested features completed and others failed. The results of the features that completed are returned as usual, together with an errorMessage describing the failure.

PENDING_VERIFICATION only occurs on the HUMAN tier. It means the AI has finished and its results are already readable, while a human reviewer is still working on the document. It is not a terminal state - the transaction moves on to DONE or PARTIAL.


Body - raw (json)

Body
{
    "id": "<transaction-id>",
    "status": "DONE",
    "customId": "my-first-transaction"
}


Get Transaction Results Request

You can get transaction results either by the transaction ID or the custom ID. The transaction ID is unique for each transaction, while the custom ID is optional and can be set by the user.


GET v1/transactions/{transaction_id}/results

https://api.stag.ssn.visma.ai/v1/transactions/<transaction-id>/results

Authorization - Bearer Token

Token: demo


Calling the Get Transaction Results endpoint with the custom ID:


GET v1/transactions/results?custom_id={custom_id}

https://api.stag.ssn.visma.ai/v1/transactions/results?custom_id=my-first-transaction

Authorization - Bearer Token

Token: demo


Filtering the results

Both forms of the endpoint accept two optional query parameters:

Parameter Type Default Description
min_confidence string HIGH Only return candidates whose confidence level is at least this value.
max_results integer 1 Maximum number of candidates to return per feature.

Information

Both parameters default to a narrow result set. Unless you set them, each feature returns at most one candidate, and only if its confidence level is HIGH or better. If a feature returns nothing, lowering min_confidence (for example to VERY_LOW) and raising max_results will surface the remaining candidates.


GET v1/transactions/{transaction_id}/results?min_confidence={level}&max_results={n}

https://api.stag.ssn.visma.ai/v1/transactions/<transaction-id>/results?min_confidence=VERY_LOW&max_results=5

Authorization - Bearer Token

Token: demo


Get Transaction Results Response

The Get Transaction Results response includes:

  • Transaction ID: A unique identifier for the transaction.
  • Custom ID: The custom ID if provided in the request.
  • Annotations: The extracted data, with one entry per requested feature. Absent while the transaction is still processing.
  • Error message: The errorMessage field, present when the transaction is FAILED or PARTIAL, describing what went wrong.

Information

This endpoint returns 200 OK for any existing transaction - the state of the transaction is not signalled through the HTTP status code:

  • While the transaction is CREATED or RUNNING, the response contains only id and customId, with no annotations. Keep polling until the annotations appear, or poll the status endpoint instead.
  • When the transaction is FAILED, the response contains errorMessage and no annotations.
  • When the transaction is PARTIAL, the response contains the annotations of the features that completed and an errorMessage.
  • When the transaction is PENDING_VERIFICATION, the response contains the AI annotations and no errorMessage. These values are provisional - see human verification.

Body - raw (json)

Body
{
    "id": "<transaction-id>",
    "annotations": [
        {
            "feature": "RECEIVER_COUNTRY_CODE",
            "candidates": [
                {
                    "value": "DK",
                    "confidence": {
                        "level": "VERY_HIGH"
                    },
                    "modelMetadata": {
                        "modelName": "layoutlm-r3",
                        "modelVer": "1"
                    }
                }
            ]
        }
    ],
    "customId": "my-first-transaction"
}


Update Transaction Results (Feedback)

You can provide feedback on the results of a transaction by updating the transaction with the correct values. This is useful for improving the models. You can update the transaction results by the transaction ID.

Information

Feedback can only be submitted once processing has finished, that is when the transaction status is DONE or PARTIAL. Submitting feedback while the transaction is still CREATED, RUNNING or PENDING_VERIFICATION, or after it has FAILED, is rejected with a FAILED_PRECONDITION error.


PUT v1/transactions/{transaction_id}/results

https://api.stag.ssn.visma.ai/v1/transactions/<transaction-id>/results

Authorization - Bearer Token

Token: [API token]


Body - raw (json)

Body
{
  "customId": "YOUR_CUSTOM_ID_12345",
  "annotations": [
    {
      "feature": "TOTAL_INCL_VAT",
      "candidates": [
        {
          "value": "125.50",
          "text": "125,50",
          "confidence": {
            "level": "VERY_HIGH",
            "value": 0.99
          },
          "boundingBox": {
            "vertices": [
              { "x": 100, "y": 50 },
              { "x": 200, "y": 50 },
              { "x": 200, "y": 75 },
              { "x": 100, "y": 75 }
            ]
          },
          "type": "FIELD",
          "pageRef": 1
        }
      ]
    },
    {
      "feature": "PURCHASE_LINES",
      "purchaseLineCandidates": [
        {
          "pageRef": 1,
          "description": "Product A",
          "quantity": "2",
          "totalInclVat": "50.00",
          "totalExclVat": "40.00",
          "totalVat": "10.00",
          "percentageVat": "25"
        },
        {
          "pageRef": 1,
          "description": "Product B",
          "quantity": "1",
          "totalInclVat": "75.50",
          "totalExclVat": "60.40",
          "totalVat": "15.10",
          "percentageVat": "25"
        }
      ]
    }
  ]
}


Update Transaction Results Response


Body - raw (json)

Body
{
    "id": "<transaction-id>",
    "customId": "my-first-transaction"
}


Model tiers

The optional tier field on the Create Transaction request selects which model processes the document:

  • PREMIUM - our proprietary AI. This is the tier used when tier is not set.
  • ULTRA - combines our proprietary AI with reasoning LLMs for the highest available quality. ULTRA is only available through the asynchronous API.
  • HUMAN - runs the ULTRA pipeline and then has a human reviewer complete the result when the AI did not find everything. HUMAN is only available through the asynchronous API. See Human verification below.
{
    "document": {
        "source": {
            "httpUri": "http://storage.googleapis.com/vml-test-data/distributable/pdf5/10.pdf"
        }
    },
    "features": [ "TOTAL_INCL_VAT" ],
    "tier": "PREMIUM"
}

Features marked Premium in the feature list require a Premium or higher tier. See Model Versions for a fuller comparison of the tiers.

Human verification (the HUMAN tier)

On the HUMAN tier a transaction is first processed exactly as on ULTRA. When the AI result is incomplete, the document is then passed to a human reviewer, and the values the reviewer reads from the document fill the fields the AI had no confident answer for.

Information

Human verification adds a review step performed by people, so a HUMAN transaction can take hours rather than seconds to reach a terminal state. Please talk to us before putting HUMAN into production.

What happens to the transaction

  1. The AI pipeline runs. If it already found the currency, supplier VAT number, total VAT, a total amount and the document number, the document is not sent for review and the transaction goes straight to DONE.
  2. Otherwise the document is sent for review and the transaction becomes PENDING_VERIFICATION. The AI annotations are readable from the results endpoint for the whole of this period, but they are provisional - a reviewer may still fill the fields the AI had no confident answer for. Feedback cannot be submitted yet.
  3. When the review comes back, the reviewed values fill those fields and the transaction becomes DONE.

When no review happens

A document is not reviewed if it is not a PDF or a TIFF, if it is larger than 5 MB, if the AI result is judged unsuitable for review, or if no reviewed result comes back within 24 hours of submission. In all of these cases the transaction settles as PARTIAL: the AI annotations are returned as usual, with errorMessage set to human verification was not completed, or to document not eligible for completion when the AI result was judged unsuitable for review. Deleting the transaction while a review is outstanding cancels the review.

How reviewed values look

A reviewed value is only used for a field where the AI had no candidate at confidence HIGH or above, so the field would otherwise come back empty with the default min_confidence. A field the AI answered confidently keeps the AI's answer. The reviewed candidate is placed in front of the AI's candidates for its field and is returned with confidence level VERIFIED and the corrected attribute, on the same terms as the VERIFIED feature. If a reviewed total differs from the AI's, cross-checked VERIFIED values that were derived from the old totals are removed from VAT_DISTRIBUTION and PURCHASE_LINES.

Features on the HUMAN tier

Requesting tier: "HUMAN" automatically enables HUMAN_VERIFIED plus every field a reviewer can supply, so these are returned even if you did not request them individually:

BANK_ACCOUNT_NUMBER, BIC, CURRENCY, DOCUMENT_DATE, DOCUMENT_NUMBER, IBAN, OCR_LINE_SE_BANKGIRO_CREDITOR_ID, OCR_LINE_SE_PLUSGIRO_CREDITOR_ID, PAYMENT_DUE_DATE, SUPPLIER_NAME, SUPPLIER_ORGANISATION_NUMBER, SUPPLIER_VAT_NUMBER, TOTAL_EXCL_VAT, TOTAL_INCL_VAT, TOTAL_VAT

HUMAN_VERIFIED carries the state of the review and never returns candidates of its own, so it produces no entry in annotations. Listing HUMAN_VERIFIED in features without also setting tier to HUMAN is rejected with 400 Bad Request (INVALID_ARGUMENT, Invalid feature requested).

{
    "document": {
        "source": {
            "httpUri": "http://storage.googleapis.com/vml-test-data/distributable/pdf5/10.pdf"
        }
    },
    "features": [ "TOTAL_INCL_VAT" ],
    "tier": "HUMAN"
}

Document Data Sources

You can provide the document in one of two ways:

  1. By URI: Provide a URL to the file (as shown in the Create Transaction request)
  2. By Content: Send the file directly in the request body using the content field

Proper Base64 Encoding for content Field

The content field requires the raw binary bytes of the file, Base64 encoded.

  • Read the file in binary mode (e.g., rb in Python, FileInputStream in Java)
  • Base64 encode those raw bytes directly
  • Send the Base64-encoded binary data in the content field

Example request


POST v1/transactions

https://api.stag.ssn.visma.ai/v1/transactions

Authorization - Bearer Token

Token: demo


Body - raw (json)

Body
{
    "document": {
        "content": "Vl00oANHjF3gxaYT4fQ0PSDJwwZIuMLl0GdNlgyKhF4KYOtcH3r... -- this is unfinished base64 enconding --"
    },
   "features": [ "RECEIVER_COUNTRY_CODE", "IBAN" ],
    "tags": ["testing"],
    "customId": "my-first-transaction"
}


Smartscan Response

Individual candidates carry the same meaning as in the synchronous Smartscan: values, confidence levels, bounding boxes and page references all behave identically.

The response envelope differs. Asynchronous results are returned as an annotations array, with one entry per requested feature identified by its feature name, rather than one named field per feature. The asynchronous response does not include feedbackId or documentMetadata.

Data Deletion Policy

You can either delete the data by deleting the transaction either by transaction_id or custom_id, or you can delete multiple transactions via tag, if provided in the Create Transaction request.

Deletion is processed asynchronously: the 200 OK confirms that the deletion request has been accepted, and the data is removed shortly afterwards.

Delete Transaction Request


DELETE v1/transactions/{transaction_id}

https://api.stag.ssn.visma.ai/v1/transactions/<transaction-id>

Authorization

Bearer Token

Token: [API token]


Response

200 OK

Calling the Delete Transaction endpoint with the custom ID:


DELETE v1/transactions?custom_id={custom_id}

https://api.stag.ssn.visma.ai/v1/transactions?custom_id=my-first-transaction

Authorization

Bearer Token

Token: [API token]


Response

200 OK

Delete Tag Request

Delete transaction by tag will delete all transactions with the provided tag.


DELETE v1/tags/{tag}

https://api.stag.ssn.visma.ai/v1/tags/testing

Authorization

Bearer Token

Token: [API token]


Response

200 OK