AgilePixelAgile's sovereign eyesight

Read a document and return its fields, not an essay.

AgilePixel is the eyesight service: give it a document, a utility bill, a scan or a photo taken with a phone, and it returns the fields as JSON, each with its own confidence. It runs on our own machines, in Europe: no document is forwarded to third parties.

What it does

Three capabilities, one contract:

Formats: PDFs with a text layer, scanned PDFs, scanner images and phone photos (perspective, shadows, folds, compression). The photo is the hard exam, and it is the one we measure ourselves against.

The rule that sets us apart: never an invented value

Every field goes through a deterministic validator before it leaves: POD and PDR energy identifiers, Italian tax code and VAT number with their check digit, IBAN with mod 97, coherent billing period dates, the sum of bands F1+F2+F3 equal to the total, taxable amount plus VAT equal to the amount due. A field that fails comes back as null, its name goes into the da_verificare list (to be checked) and motivi (reasons) says which check it failed: it never comes back as a plausible wrong value. In an automated process, the error that costs most is the one reported as certain.

Sovereignty, concretely

Who it is for

Callers need not know where the engine runs, nor change anything when the engines become two or ten.

Plans

One licence per tenant, with plan, scopes, monthly quota, per-minute limit and expiry. API keys live under the licence: they are issued, rotated and revoked from the tenant console without touching the licence.

Trial

price on request

Quota
500 pages per month
Limit
10 requests per minute
Term
30 days
Scopes
leggi, estrai, descrivi (read, extract, describe)

Standard

price on request

Quota
20,000 pages per month
Limit
60 requests per minute
Term
365 days
Scopes
leggi, estrai, descrivi (read, extract, describe)

Enterprise

price on request

Quota
500,000 pages per month
Limit
300 requests per minute
Term
365 days
Scopes
leggi, estrai, descrivi (read, extract, describe)

The quotas and limits above are the ones the service actually enforces, not a brochure. Price on request applies to all three plans: it is agreed with Agile together with the expected volume and the service level. Past the quota the licence does not break: it answers quota_superata, with the month's count in dettaglio. The per-minute limit is counted per clock minute, not over a sliding window: across a minute boundary up to twice the stated number can go through within a few seconds.

The per-minute limit is a ceiling on you, not a reserved seat. The work seats — how many documents the service keeps in progress and how many it keeps waiting — belong to the service and are shared with every other customer: the queue does not know whose job it is. So coda_piena (503) can reach you because of another customer's traffic, with your quota untouched and on your first request of the minute. It is not a fault and it costs you no quota: it is a 503 and you retry, with a doubling wait. Measured live on 3/10/2026 with two real customers: the second one, which had made a single request, got coda_piena in 55 ms without consuming quota, and the door stayed shut for 18.6 seconds, the time of the jobs ahead of it. How much queue each customer is entitled to is still an open choice: when there is a number, this line will say it. Details in API.md, limits and rules.

API documentation

The contract is versioned and published: /openapi.json (OpenAPI), the integrator's guide is in API.md, and the interactive pages live at /documentazione. Errors carry a stable name (for instance chiave_sconosciuta, quota_superata, nessun_motore_disponibile): you program against the name, not against the prose.

One call

curl -X POST https://api.agilepixel.agile.software/v1/documenti/estrai \
  -H "Authorization: Bearer <key>" \
  -F "documento=@bill.pdf" \
  -F "tipo=bolletta_luce"

The response

{
  "lavoro": "lav_9f2c41d7a3b05e62",
  "motore": "motore-1",
  "pagine": 2,
  "ms": 1840,
  "ms_fronte": 1902,
  "campi": {
    "pod":                  "IT001E12345678",
    "periodo_dal":          "2026-07-01",
    "periodo_al":           "2026-08-31",
    "consumo_totale":       412.0,
    "totale_da_pagare":     118.34,
    "potenza_impegnata_kw": null
  },
  "confidenze": {
    "pod":                  0.99,
    "periodo_dal":          0.98,
    "periodo_al":           0.98,
    "consumo_totale":       0.97,
    "totale_da_pagare":     0.96,
    "potenza_impegnata_kw": null
  },
  "da_verificare": ["potenza_impegnata_kw"],
  "motivi": { "potenza_impegnata_kw": ["potenza_implausibile"] }
}

The last field is the point: the engine had read a contracted power impossible for a domestic supply, so the service zeroes it and says so instead of handing over a plausible wrong number. The same call on /v1/documenti/leggi returns the text, on /v1/immagini/descrivi the description.

Keys and usage

The tenant governs its own keys at /console/licenze: issue, rotation with a 24-hour grace period on the old key (time to update your systems without a minute of downtime) and immediate revocation. Consumption is read from /console/licenze/{id}/uso, month by month, in pages and images.

Comparison with the leader

We measure ourselves on a two-arm bench: the same pages go through our engine and through the market leader, and the fields are compared against ground truth. The cells below are filled by the bench: no quality figure is hand-written on this page, and while a measurement does not exist the cell says «not measured yet». The yardstick and the targets are public in our target document; figures published by third-party vendors are not passed off as our own measurements.

Critical fields of the Italian utility bill, same page set, same ground truth.
MetricAgilePixelLeader
Critical fields exact — digital PDFs not measured yet not measured yet
Critical fields exact — scans and photos not measured yet not measured yet
«Confidently wrong» errors not measured yet not measured yet
Fields returned as to be checked not measured yet not measured yet
POD, PDR, tax code, VAT number (check digit) not measured yet not measured yet
Character error rate — PDFs not measured yet not measured yet
Character error rate — photos not measured yet not measured yet
F1 F2 F3 band table reconstructed not measured yet not measured yet
Latency per page, ninety-fifth percentile not measured yet not measured yet
Cost per thousand pages not measured yet not measured yet

How to read it: synthetic pages only, never customer documents; ground truth is generated together with the pages, so it is exact to the cent; zero tolerance on amounts; the leader's arm runs on the same pages in the same round. When a row changes, it changes because the bench ran again.

Service status

The service is answering, at reduced capacity.

Engine
none
Engines ready
0/0
Queue
0 in flight, 0 waiting
Contract
1.1
Up for
7500.4 s
Why
nessun_motore_pronto

The status above is the real one, read at the moment this page was composed, from the very same /health our own systems use. When no engine is ready the service says so: there is no courtesy «all good» here.

Request a licence

Leave us two lines: we answer at the address you give, with the plan that fits your volume and the price. We ask only for what is needed to answer.

The form works without JavaScript. The service answers with a request number: keep it, it is the reference for your case. There is a per-network-address rate limit, to keep the bots out.