Constaia
Integrations

Power Automate

Validate SharePoint or OneDrive documents with the Power Automate HTTP action, read the response with Parse JSON and receive Constaia events.

In Power Automate you call Constaia with the HTTP action, sending the file as base64 inside a JSON body. The response is read with Parse JSON and split with a Switch based on the verdict. To receive asynchronous events you use the When a HTTP request is received trigger.

The HTTP action and the When a HTTP request is received trigger are premium connectors: you need a Power Automate licence that includes them.

Prerequisites

  • Power Automate with access to premium connectors.
  • A test key ck_test_… from the dashboard. See Authentication.
  • A document source. In this guide: SharePoint, with the When a file is created in a folder (properties only) trigger followed by Get file content. With OneDrive or an Outlook attachment it works the same way: only the source of the file content changes.

Analyze a document

Get the file content

After the trigger, add SharePoint → Get file content with File Identifier set to the trigger's Identifier. The action is referenced as Get_file_content in expressions.

Add the HTTP action

FieldValue
MethodPOST
URIhttps://api.constaia.com/v1/analyze
HeadersAuthorization: Bearer ck_test_… · Content-Type: application/json · Idempotency-Key: @{workflow()?['run']?['name']}

And as Body:

Body
{
  "file_base64": "@{base64(body('Get_file_content'))}",
  "filename": "@{triggerOutputs()?['body/{FilenameWithExtension}']}",
  "options": {
    "expect": "invoice",
    "export": ["xlsx"],
    "language": "en",
    "metadata": { "source": "power-automate" }
  }
}

The Idempotency-Key header uses the run identifier: if the HTTP action retries under its retry policy, Constaia returns the stored response without charging twice. More in Idempotency. The options are in POST /v1/analyze.

Check the status code

If the analysis does not finish within 30 s (long PDFs), the API responds 202 with status: "queued" or "processing" and no verdict. Add a Condition with @{outputs('HTTP')?['statusCode']} equal to 200 before continuing, or use "async": true and receive the result by webhook (below).

Errors (4xx, 5xx) make the HTTP action fail. To handle them, add a branch with Configure run after → has failed and read body('HTTP')?['error']?['code'] and body('HTTP')?['error']?['request_id']. The codes are in Errors.

Parse the response with Parse JSON

Add Parse JSON with Content @{body('HTTP')} and this schema (only the part you use; undeclared properties are still available in body('HTTP')):

Schema
{
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "status": { "type": "string" },
    "document": {
      "type": ["object", "null"],
      "properties": {
        "type": { "type": "string" },
        "label": { "type": "string" },
        "confidence": { "type": "number" }
      }
    },
    "verdict": {
      "type": ["object", "null"],
      "properties": {
        "status": { "type": "string" },
        "reasons": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "code": { "type": "string" },
              "severity": { "type": "string" },
              "message": { "type": "string" }
            }
          }
        }
      }
    },
    "fields": { "type": "object" },
    "warnings": { "type": "array", "items": { "type": "string" } },
    "exports": { "type": "object" }
  }
}

Route with a Switch

Add a Switch on @{body('Parse_JSON')?['verdict']?['status']} with three cases:

CaseWhat to do
Válido validStore the data. For example the total: @{body('Parse_JSON')?['fields']?['total']?['value']}; the generated Excel: @{body('Parse_JSON')?['exports']?['xlsx']} (signed URL, valid for 24 h).
No válido invalidNotify via Teams or email with the verdict.reasons messages.
Revisar reviewCreate a task or an approval for a person. See Human review.

Each extracted field is an object with value, confidence, validated and source. More in Verdicts and Exports.

Test in test mode

With a ck_test_… key no credits are used and the response depends on the file name you send in filename (the content must be a real JPEG, PNG, WEBP, HEIC or PDF). Upload files to the folder named:

FileWith expectResult
invoice.pdfinvoiceVálido invoice with base 100, VAT 21 %, total 121 EUR
dni_expired.jpges_dniNo válido not_expired with severity error
blurry.jpges_dniRevisar low_quality with severity warning

While testing you can also set filename by hand in the body. All scenarios in Test mode.

Receive events by webhook

Create the receiving flow

Create a flow with the When a HTTP request is received trigger. Under Who can trigger the flow? choose Anyone (Constaia doesn't authenticate with Microsoft Entra) and use as Request Body JSON Schema:

Request Body JSON Schema
{
  "type": "object",
  "properties": {
    "type": { "type": "string" },
    "created_at": { "type": "string" },
    "data": { "type": "object", "properties": { "id": { "type": "string" } } }
  }
}

Save the flow, copy the generated URL and register it in the dashboard or with POST /v1/webhook-endpoints (see Webhooks). If the flow has no Response action, the trigger answers 202 Accepted right away, which Constaia counts as a successful delivery.

Read the analysis again

Power Automate has no function to compute the HMAC-SHA256 signature, so don't trust the event body:

  1. Condition: @{startsWith(triggerBody()?['data']?['id'], 'an_')} is true.
  2. HTTP GET to https://api.constaia.com/v1/analyses/@{triggerBody()?['data']?['id']} with the Authorization header.
  3. Parse JSON with the schema above and the same Switch.

The API only returns analyses of your account: a forged event can at most make you re-read one of your own analyses. For batch.completed, data.id starts with bat_ and the read is GET /v1/batches/{id}.

Drop duplicates

Constaia retries failed deliveries for about 3 days with the same webhook-id, available in @{triggerOutputs()?['headers']?['webhook-id']}. Store it (for example in a SharePoint list or a Dataverse table) and end the flow if it already exists.

The re-read needs the analysis to still be stored: don't use keep_results: false on analyses you want to receive by webhook.

Security

  • Don't write a ck_live_… key into flows you share or export. If you work with solutions, store the key in an environment variable of type Secret (backed by Azure Key Vault) and use it in the header.
  • Turn on Settings → Secure inputs and Secure outputs on the HTTP actions: that way the key, the base64 document and the extracted data don't show up in the run history.
  • Use a test key while building the flow and the live key only when you turn it on.
  • Constaia deletes the file when it finishes with storage: "none" (the default). More in Storage and privacy.

Limits

  • 20 MB per file (base64 makes the body about 33 % larger); PDFs up to 30 pages synchronously and up to 200 with async: true.
  • 2 requests per second per key on the free plan (10 on paid). If you loop over many files with Apply to each, limit its concurrency in the action settings; on a 429 the API sends Retry-After. See Rate limits.

Next steps

On this page