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
| Field | Value |
|---|---|
| Method | POST |
| URI | https://api.constaia.com/v1/analyze |
| Headers | Authorization: Bearer ck_test_… · Content-Type: application/json · Idempotency-Key: @{workflow()?['run']?['name']} |
And as 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')):
{
"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:
| Case | What to do |
|---|---|
Válido valid | Store 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 invalid | Notify via Teams or email with the verdict.reasons messages. |
Revisar review | Create 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:
| File | With expect | Result |
|---|---|---|
invoice.pdf | invoice | Válido invoice with base 100, VAT 21 %, total 121 EUR |
dni_expired.jpg | es_dni | No válido not_expired with severity error |
blurry.jpg | es_dni | Revisar 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:
{
"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:
- Condition:
@{startsWith(triggerBody()?['data']?['id'], 'an_')}istrue. - HTTP
GETtohttps://api.constaia.com/v1/analyses/@{triggerBody()?['data']?['id']}with theAuthorizationheader. - 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
Zapier
Validate documents in Zapier with Webhooks by Zapier (JSON with file_url) or Code by Zapier (base64), filter by verdict and receive events with Catch Hook.
Google Apps Script
Validate Google Drive documents from Google Sheets with Apps Script and UrlFetchApp, keep the key in Script Properties and write the verdict to the sheet.