Developers
One engine, four ways in.
Every surface runs the same deterministic operations. Pick the one that fits where your documents are allowed to go and where your code runs.
Ways in
The four ways to call it
The connector, in your developer tool
Add the service as a remote MCP server and sign in when it asks. Documents upload to the service.
The local host, on your machine
One install and one command per tool. Documents never leave the machine; templates still live in your account.
REST routes, from a flow
Power Automate, n8n, or your own code call the same operations over HTTP with a connection key.
The engine, in your .NET application
The same deterministic engine as a NuGet package, with a typed template builder and results you switch on.
The connector
Use the service from a developer tool
https://api.docuoria.com/mcp
Add it as a remote MCP server in the tool's settings and sign in with the one-time passcode when it asks. The tool uploads documents from its sandbox to the service, where they are read by no model, refused after 24 hours and gone within 48. Templates (the document types a person sees in the account) and ledgers belong to your organisation and are shared with every assistant and flow on the team. The per-platform steps, written for an agent to follow, are at api.docuoria.com/install.
The local host
Keep documents on the machine
The local host serves the same operations as an MCP server on your machine. Your tool starts it, and documents are read by path and never uploaded.
Install the command line tool
$ dotnet tool install -g Docuoria.Cli # .NET 10 or laterThe package is MIT.
Register it with your tool, in the project folder
Tool Command Claude Code docuoria init --tools claudeCursor docuoria init --tools cursorVS Code with GitHub Copilot docuoria init --tools github-copilotCodex docuoria init --tools codexWindsurf docuoria init --tools windsurfSign in once on this machine
$ docuoria loginCheck
$ docuoria doctor
docuoria init writes the server entry into the tool's own settings
and records where templates live: your organisation's account by default, or the project folder
with --store folder.
docuoria login signs in by device code and stores a seat credential
labelled with the machine's name. The first time, accept the terms in the browser; login
stops until you do, then run it again. The computer then appears under Your computers in your account
(an owner sees every computer on the Team page); revoke it there or run
docuoria logout. docuoria doctor reports the
service, the store, the credential, the licence, and the registered tools.
Documents never leave the machine. Templates go to the account, or stay in the project folder. Licence use goes to Monaiq, aggregated; the host needs Monaiq about once an hour while extracting.
| Command | Does |
|---|---|
docuoria list-tools | Lists the supported tools and which are registered in this project |
docuoria license status | Shows the plan, allowances, and windows of the machine's seat |
docuoria store push | Copies templates from the project folder to the account store |
docuoria logout | Revokes the machine's credential |
REST routes
Calling the routes from Power Automate, n8n or your own code
Every operation is a REST route on the service, described at api.docuoria.com/openapi.json. A flow authenticates with a connection key instead of a sign-in.
An owner creates and revokes keys on the Team page, or from the command line;
a member asks an owner. The key is shown once, starts with dk_, and is sent as
Authorization: Bearer dk_.... A revoked key's next call is refused with 401.
$ docuoria account keys create --label "My flow"
curl -X POST "https://api.docuoria.com/extract?template=vendor-invoice&ledger=vendor-bills&format=json" \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/pdf" \
-H 'Content-Disposition: attachment; filename="vendor-messageId.pdf"' \
--data-binary @invoice.pdf
To send the PDF in two steps, open a ticket with POST /uploads, send the file with
PUT /uploads/{ticket} using the ticket's token and a
Content-Disposition header, then call
POST /extract with JSON
{"document":"<id>","template":"vendor-invoice"},
where the id is the upload receipt's documentId.
Reading the result
A document that does not extract is still HTTP 200. Branch on status
(extracted, partial or
no-match), then on ledger.action: a row was written only when it is
appended, and ledger is null unless
status is extracted. Name the template with
template=<id>; without it, a document extracts only when it strongly matches one of
your saved templates, and a new organisation has none. Add ledger=<id> and
format=json to the query; the first document extracted into it creates the ledger, and until
then GET /ledgers/{id} answers 404. The result carries
output, ledger.rowsAdded and ledger.totalRows.
File names
The file name comes from the Content-Disposition header, as
attachment; filename="vendor-messageId.pdf", and is the ledger's key for a document it has seen.
A second invoice.pdf returns 200 with ledger.action
already-present and no row, although the PDF was read again. Name each file uniquely.
Reading a ledger
GET /ledgers/{id} returns the CSV in content up to 200 KB.
Above that, content is null and downloadUrl is a single-use link,
GET /downloads/{id}, valid for 10 minutes: fetch it at once.
Authoring over REST
Author a template over REST, in this order: GET /reference for the rules,
POST /inspect with the PDF, write the template JSON,
POST /validate-template, POST /dry-run with the PDF,
then POST /templates to save it. Extract with the saved id as template.
Rate limits
On Free, execute and ledger-append calls are limited to 20 a minute. Run a flow one document at a time, and retry after a delay on 429 and 503.
Errors
A refused call returns application/problem+json with code,
title and detail. A 401 means a missing or revoked key; owners manage keys on the
Team page. A 402 means the organisation holds no live plan; see the Plan page in your account.
A 429 means the allowance or the minute window is spent; wait and retry.
| Group | Routes | Purpose |
|---|---|---|
| Documents | POST /uploads, PUT /uploads/{ticket}, GET /documents, DELETE /documents/{id} | Hand PDFs to the account; a ticket lets a sandbox add files for 10 minutes |
| Extraction | POST /extract, POST /classify, POST /batch, GET /jobs/{job}, GET /downloads/{id} | Run a template, pick one, or queue a folder; large results come back as a link that lasts 10 minutes |
| Authoring | POST /inspect, /test-patterns, /validate-template, /evaluate-match, /dry-run, /survey, /regression-check | Everything the assistant uses to write and check a template |
| Templates | GET, POST /templates; GET, PUT, DELETE /templates/{template} | The account store. JSON only; any other body is refused with 415 |
| Ledgers | GET /ledgers, GET /ledgers/{ledger}, POST /ledgers/{ledger}/entries, DELETE /ledgers/{ledger} | Running spreadsheets that append without duplicates |
| Account | GET /account, GET /reference | Organisation and seats, and the guidance the assistant reads |
MCP tools
Twenty-four tools, the same on the service and the local host
One MCP tool and one REST route per operation, with deterministic JSON results.
| Group | Tools |
|---|---|
| Documents | create_upload, list_documents, delete_document |
| Extraction | extract, classify, batch_extract, job_status |
| Authoring | inspect, test_patterns, validate_template, evaluate_match, dry_run, survey, regression_check |
| Templates | save_template, list_templates, load_template, delete_template |
| Ledgers | read_ledger, list_ledgers, append_ledger_rows, delete_ledger |
| Account | account, reference |
The .NET SDK
From the package to the first result
The Docuoria package on NuGet targets .NET 10. A test in the SDK suite,
ReadmeWalkthroughTests, compiles and runs this walkthrough, so it
matches the shipped API.
$ dotnet add package Docuoria
using Microsoft.Extensions.DependencyInjection;
using Docuoria.Configuration;
using Docuoria.Contracts;
using Docuoria.MatchRules;
using Docuoria.Models;
using Docuoria.Output.Csv;
using Docuoria.Pipeline.Extraction;
using Docuoria.Pipeline.Publish;
using Docuoria.Registration;
using Docuoria.Results;
var services = new ServiceCollection();
services.AddDocuoriaEngine(b => b.AddBuiltInMatchRules().AddCsvOutputGenerator());
var engine = services.BuildServiceProvider().GetRequiredService<IDocuoriaEngine>();
var schema = new RecordDefinition("Invoice", new FieldDefinition[]
{
new PrimitiveFieldDefinition("vendor", FieldType.String, isRequired: true),
});
var template = TemplateBuilder.Create("quickstart", new DataModel(schema))
.WithMatchRule<FileNameMatchRule, FileNameMatchRuleConfiguration>(
new FileNameMatchRuleConfiguration { Pattern = "**/*.pdf", Threshold = 1m })
.ExtractWith<ExtractionStep, ExtractionStepConfiguration>(new ExtractionStepConfiguration(new IFieldMapping[]
{
new FieldMapping("vendor", FieldType.String, MetadataFieldExtractionSource.Standard(MetadataField.Title)),
}))
.PublishWith<PublishStep, PublishStepConfiguration>(new PublishStepConfiguration())
.Build();
await using var pdf = File.OpenRead("invoice.pdf");
var result = await engine.ExecuteTemplateAsync<CsvOutputGenerator, CsvGeneratorOptions>(pdf, template, new CsvGeneratorOptions());
if (result is SucceededResult ok)
Console.WriteLine(System.Text.Encoding.UTF8.GetString(ok.Output.Payload.Span));switch (result)
{
case SucceededResult success: // success.Output.Payload, success.Output.ContentType
case FailedResult failure: // failure.StepIdentifier, failure.ErrorMessage
case RejectedResult rejection: // rejection.Reason, rejection.Detail
}Deterministic and stateless
Same PDF, same template, same options produce the same bytes, which
E2E_DeterminismTests proves on every build. The engine holds no
per-call state; register it as a singleton and call it concurrently. No model runs anywhere in it.
Three result types
Succeeded carries the sealed output and its content type.
Failed names the step and the error.
Rejected carries the reason and detail. Each has a dry-run variant.
Your organisation's templates, from your own application
The service keeps each organisation's templates in its account store. On Pro and Pay-as-you-go, the SDK reads and writes that store with a connection key, so an engine in your application shares templates with every assistant and flow in the organisation.
services.AddDocuoriaEngine(b => b.AddApiTemplateStore(
new Uri("https://api.docuoria.com/"),
new ApiTemplateStoreCredentials { BearerToken = "<connection key>" }));
Only template JSON crosses the wire. The template routes refuse any other body with 415, and
PrivacyInvariantTests fails the build if that changes.
Capabilities
What a template is made of
A template names how a document is recognised, where each value is read from, how values are transformed, and how the record is written out.
| Category | Count | Items |
|---|---|---|
| Match rules | 7 | FileName, Metadata, TextPattern, TextAnchor, PageGeometry, Table, Composite |
| Extraction sources | 5 and a fallback | TextPattern, TextAnchor, MetadataField, TableCell, TableRows; Fallback |
| Pipeline steps | 5 | Extraction, Transformation, Retrieval, Python, Publish |
| Field transforms | 6 | Trim, Cast, Format, Rename, Compute, CollectionElement |
| Field types | 6 | String, Number, Integer, Boolean, Date, Timestamp |
| Output formats | 2 | CSV, JSON |
| Engine methods | 9 | EvaluateMatchRule, ExecuteTemplate, Inspect, TestPattern, TestGroups, DryRun, EvaluateMatch, Classify, ClassifyRanked |
| Result types | 3 | Succeeded, Failed, Rejected, each with a dry-run variant |
The Retrieval and Python steps are on no hosted plan; a self-hosted deployment or an SDK host enables them by its own choice. XML output is on the roadmap.
Limits per 60 seconds
Each plan bounds how many calls of an operation go through in a 60-second window. Pay-as-you-go has Pro's windows. A spent window is refused before the work, and nothing is billed past the cap. The monthly allowances are on the pricing page.
| Operation | Free | Pro and Pay-as-you-go |
|---|---|---|
| execute | 20 | 120 |
| classify | 60 | 360 |
| batch-execute | 3 | 30 |
| ledger-append | 20 | 120 |
| survey | 5 | 30 |
| regression-check | 5 | 30 |
| Authoring calls: inspect, test-patterns, evaluate-match, dry-run, validate-template, create-upload | 30 | 300 |
Hosting modes
Four places the same engine runs
| Mode | What it is | Your documents | Status |
|---|---|---|---|
| Multi-tenant | The Docuoria service at api.docuoria.com, operated by Sidub | Uploaded by you or your flow; read by no model; refused after 24 hours and gone within 48; deleted at once on request | Available now. Free, Pro, and Pay-as-you-go |
| On your machine | The local host, started by your developer tool | Never leave the machine | Available now. Any plan |
| Self-hosted | The same service deployed from the same Bicep into your own Azure subscription, operated by you | Never leave your organisation's subscription | By arrangement. Its own offering |
| Single-tenant | One deployment per customer in Sidub's subscription, on your hostname | Processed in your organisation's own deployment; deleted within 48 hours or on request | A later phase. By arrangement |
The three cloud modes run the same code from the same Bicep; the mode sets whose subscription holds it and which hostname the connector carries. Licence validation and aggregated usage counts go to Monaiq in every mode. To arrange a self-hosted or single-tenant service: inquiries@sidub.net.
The account, from the command line
Owner commands
An owner manages the organisation in the account at /manage, or with these commands. Each signs the owner in by device code.
| Command | Does |
|---|---|
docuoria account show | Lists the organisation's purchases and seats |
docuoria account upgrade | Prints the checkout link for Pro; checkout completes in the browser |
docuoria account seats add N | Adds N seats to the organisation |
docuoria account associate CODE | Attaches a purchase code from the Monaiq marketplace to the organisation |
docuoria account keys create --label "..." | Creates a connection key for a flow, shown once |
Licensing
Licence terms
The SDK and the Docuoria service are licensed under the Sidub Proprietary Software License Agreement, published verbatim as the License Agreement and canonical at sidub.ca/licensing. The licence type your organisation holds is the one its purchase names. The command line package on NuGet is MIT. Every plan, including Free, is a licence the service validates on each request. Plans and allowances are on the pricing page, and the limits per 60 seconds are under Capabilities. The account template store from the SDK (the SDK section) is on Pro and Pay-as-you-go, not on Free. Volume and OEM terms: inquiries@sidub.net.
Release status
What is live today
Docuoria 1.3.2 is the current release, on the service and NuGet. Items not yet verified may change.
| Live today | The service and its connector, the local host, the REST routes, the SDK, and the three plans |
| Verified | Six journeys run end to end on real invoices and receipts in CAD and USD and checked against hand-verified values: a first document, the same document type again, a mixed-vendor folder, exactly the fields a system imports, a running ledger, and invoices told apart from receipts |
| Not yet verified | Bank and credit card statements, government and regulatory forms, recurring reports, email attachment automation, ERP and accounting integrations, purchase orders |
| May change on notice | Plan prices and limits (Terms of Service, section 8) |
| Support | support@sidub.net. The software is provided as is (Terms of Service, section 10) |
Shipped in 1.3.2
- The service and the connector
- Organisations and seats
- Account template stores and ledgers
- REST routes with connection keys
- The local host for five developer tools
- The engine and its authoring tooling
- Batch jobs
- The Free, Pro, and Pay-as-you-go plans
Next
- Self-hosted service
- Single-tenant service
- Template improvement suggestions
- Email attachment automation
- ERP and accounting integrations
- XML output
- Additional match rules
Later
- Client SDKs for the REST routes
- Template generation from a sample PDF
Docuoria 1.3.2 is on the service and NuGet.
For questions, or a tool you want supported next, write to support@sidub.net.