Constaia
Integrations

Airtable

Validate Airtable attachments with a "Run a script" automation that sends the attachment URL to Constaia and writes the verdict to the record.

In Airtable, an automation can analyze a record's attachment as soon as it is uploaded: the Run a script action sends the attachment URL to Constaia as file_url and writes the verdict and extracted data to fields on the same record.

Prerequisites

  • An Airtable base where you can create automations.
  • A test key ck_test_… from the dashboard. See Authentication.
  • A table, for example Applications, with these fields:
FieldType
DocumentAttachment
VerdictSingle line text
ReasonsLong text
Document numberSingle line text
Analysis IDSingle line text

Create the automation

Choose the trigger

Create an automation with When a record matches conditions (condition: Document is not empty and Verdict is empty) or When a record is updated on the Document field.

Add the Run a script action

Add Run a script and, under Input variables, create recordId with the trigger's Airtable record ID.

Paste the script

Run a script
const API_KEY = "ck_test_..."; // see "Security" below
const table = base.getTable("Applications");
const { recordId } = input.config();

const record = await table.selectRecordAsync(recordId);
const attachments = record?.getCellValue("Document") ?? [];

if (attachments.length === 0) {
  output.set("status", "no_document");
} else {
  const attachment = attachments[0];
  const res = await fetch("https://api.constaia.com/v1/analyze", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      file_url: attachment.url,
      filename: attachment.filename,
      options: {
        expect: ["es_dni", "es_nie", "passport"],
        checks: { min_age_years: 18 },
        language: "en",
        metadata: { airtable_record_id: recordId },
      },
    }),
  });
  const analysis = await res.json();

  if (!res.ok) {
    const e = analysis.error;
    await table.updateRecordAsync(recordId, { Verdict: "error", Reasons: `${e.code}: ${e.message} (${e.request_id})` });
    throw new Error(e.message);
  }

  const verdict = analysis.verdict;
  const number = analysis.fields.document_number ?? analysis.fields.nie_number;
  await table.updateRecordAsync(recordId, {
    Verdict: verdict ? verdict.status : analysis.status,
    Reasons: (verdict?.reasons ?? [])
      .filter((r) => r.severity !== "info")
      .map((r) => r.message)
      .join("\n"),
    "Document number": number?.value ?? "",
    "Analysis ID": analysis.id,
  });
  output.set("status", verdict?.status ?? analysis.status);
}

Airtable attachment URLs are https and downloadable for a limited time, which is enough for Constaia to download them right away (20 MB and 15 s maximum). If you prefer a Single select field for Verdict, write { name: verdict.status } instead of the text.

Act on the verdict

With the script's status output, add conditional actions (Add conditional group):

statusWhat to do
Válido validMark the application as approved
No válido invalidEmail the applicant with the reasons
Revisar reviewAssign the record to a person. See Human review

If the analysis takes longer than 30 s, the API responds 202 and the script writes queued or processing to Verdict (see the next section). What each status means is in Verdicts.

Long documents: async and webhook

Automation scripts have a maximum run time. For PDFs with many pages, send "async": true in the options: the API responds 202 immediately and notifies you by webhook when it finishes.

  1. Create another automation with the When webhook received trigger and register its URL in the dashboard or with POST /v1/webhook-endpoints (see Webhooks).
  2. Airtable can't verify the event's HMAC signature, so don't trust its content: in a Run a script, take data.id from the body, check it starts with an_, read the analysis again with GET https://api.constaia.com/v1/analyses/{id} and your key, and update the record given in that response's metadata.airtable_record_id.
  3. Constaia retries failed deliveries: if the record already has a verdict, do nothing.

Don't use keep_results: false in this flow, or the re-read returns 404.

Test in test mode

With a ck_test_… key no credits are used and the response depends on the file name (filename). Upload any real image as an attachment with one of these names:

AttachmentResult
dni_valid.jpgVálido Document number = 12345678Z
nie.jpgVálido Document number = X1234567L
dni_expired.jpgNo válido reason not_expired with severity error
blurry.jpgRevisar reason low_quality

More scenarios in Test mode.

Security

  • The key is written in the script and anyone with creator permissions on the base can see it. Use ck_live_… keys only in bases with restricted access, not in bases shared with outsiders or in templates. If you can't restrict access, make the script call a backend of yours that holds the key.
  • Build and test the automation with a test key.
  • Airtable keeps the data you write to the record and the original attachment. Write only the fields you need. Constaia deletes its copy of the file when it finishes with storage: "none" (the default); see Storage and privacy.

Limits

  • 20 MB per file; 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 import many records at once and many automations fire, you may get 429 with Retry-After. See Rate limits and, for bulk loads, batches.

Next steps

On this page