Prompt cookbook
With the MCP server connected, you build a Cogneris integration by describing it. These prompts work as written in the agent chat of VS Code, Visual Studio, Cursor and Claude Code — paste one, adjust the names and paths to your project, and review what the assistant proposes before you accept it.
This video shows the whole flow in VS Code: an API key, Python extraction and classification, and a webhook with a verified signature.
In VS Code and Visual Studio, the Cogneris tools are only available when Copilot Chat is in Agent mode.
How to write a prompt that works the first time
- Say "Cogneris". It tells the assistant to use the Cogneris tools instead of guessing the API.
- Name the language and framework if the project does not make it obvious — ".NET 8 minimal API", "Node with TypeScript", "Python with FastAPI".
- Say where secrets live. "Read the key from
COGNERIS_API_KEY" keeps it out of the code. - Say sandbox or production. Sandbox keys (
xtkt_test_…) cover the asynchronous job flow (/api/v1/artifactsand/api/v1/document-jobs); the synchronous/Document/*routes and classifiers need a production key (xtkt_live_…). - Ask for a test. "…and run it against
samples/invoice.pdf" makes the assistant prove the integration instead of just writing it.
Integrate extraction
Send a document to Cogneris and get its fields back as JSON.
- C# · Visual Studio
- TypeScript · VS Code
- Python
Using Cogneris, add an
InvoiceExtractorservice to this .NET solution. It receives a PDF path, sends the file to the Cogneris extraction API and returns the extracted fields as a strongly typedInvoicerecord (supplier, invoice number, issue date, total, currency). Read the API key fromCOGNERIS_API_KEYand the base URL fromCOGNERIS_API_BASE_URL. HandlehasErrorsand the429rate limit with a retry. Add an xUnit test that runs it againstsamples/invoice.pdf.
Using Cogneris, write
src/cogneris/extract.ts: a functionextractDocument(path)that sends the file to the Cogneris extraction API and returns the fields. Then watch theinbox/folder and, for every new PDF, save the result next to it as<name>.json. Read the key fromCOGNERIS_API_KEY. Usefetch, no SDK.
Using Cogneris, add a
cogneris_client.pymodule withextract(path) -> dictthat calls the Cogneris extraction API withhttpx, raises a clear error whenhasErrorsis true, and a CLI that extracts every PDF in a folder into a CSV. Read the key fromCOGNERIS_API_KEY.
What the assistant does
cogneris_whoami— confirms your tenant, environment and the API base URL to use.cogneris_docs_searchandcogneris_api_referenceforPOST /Document/extraction— reads the request (multipart/form-data, fieldfile, optionalComplementaryPrompt), the response envelope, the errors and the limits (10 MB per file, 50 requests per minute per key).- Writes the code in your project, following the reference snippet for your language.
- Runs the test, if you asked for one — after checking you have a key in
COGNERIS_API_KEY(create one if not).
The kind of code you get back (C#, abbreviated):
using System.Net.Http.Headers;
using System.Text.Json;
public sealed class InvoiceExtractor(HttpClient http)
{
public async Task<JsonElement> ExtractAsync(string path, CancellationToken ct = default)
{
await using var file = File.OpenRead(path);
using var form = new MultipartFormDataContent();
var part = new StreamContent(file);
part.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
form.Add(part, "file", Path.GetFileName(path));
using var response = await http.PostAsync("/Document/extraction", form, ct);
// The body is JSON even when Content-Type says text/plain.
using var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync(ct));
var root = body.RootElement;
if (!response.IsSuccessStatusCode || root.GetProperty("hasErrors").GetBoolean())
throw new InvalidOperationException($"Cogneris extraction failed: {root}");
return root.GetProperty("data").GetProperty("metadata").GetProperty("fields").Clone();
}
}
// Program.cs
builder.Services.AddHttpClient<InvoiceExtractor>(c =>
{
c.BaseAddress = new Uri(builder.Configuration["COGNERIS_API_BASE_URL"] ?? "https://api-eu.cogneris.ai");
c.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", builder.Configuration["COGNERIS_API_KEY"]);
});
For high volumes: the asynchronous flow
Using Cogneris, change the extractor to the asynchronous job flow: upload the file as an artifact, submit an
Extractiondocument job with anIdempotency-Keyderived from the file hash, and wait for the result. It must work with a sandbox key.
The assistant switches to POST /api/v1/artifacts → POST /api/v1/document-jobs →
GET /api/v1/document-jobs/{jobId}, and reads the result from the job's output artifact. A retried submit with
the same Idempotency-Key returns the original job instead of processing the document twice. Pair it with a
webhook to stop polling.
Create an API key
Create a sandbox Cogneris API key called
invoice-importer-devwith only the scopes this project needs, and put it in.envasCOGNERIS_API_KEY. Make sure.envis in.gitignore.
What the assistant does
cogneris_apikeys_create— a sandbox key, with the minimum scopes for the code it has seen.- Checks that
.envis git-ignored, writes the value there, and does not repeat it in the chat. The value is returned once; Cogneris shows only its last four characters afterwards.
For production, say so explicitly — "create a production key…" — and the assistant asks you to confirm before creating it. To clean up later:
List my Cogneris API keys and revoke the ones not used in the last 90 days. Show me the list before revoking.
This needs a developer token with the apikeys.manage scope. Prefer the screen?
Generate an API key in the platform.
Generate your own API on top of Cogneris
Expose extraction to the rest of your company through an API you own, with your own auth and your own response shape.
- C# · Visual Studio
- TypeScript · VS Code
Using Cogneris, create a new ASP.NET Core minimal API project
DocumentGatewaywithPOST /invoices/extract: it receives a PDF upload (max 10 MB), sends it to Cogneris extraction and returns{ supplier, invoiceNumber, issueDate, total, currency }. Return422when Cogneris reports errors and503withRetry-Afteron rate limiting. Add OpenAPI, a health check, a Dockerfile, and read the Cogneris key from configuration — never from code. Create a sandbox Cogneris API key for local development.
Using Cogneris, scaffold an Express + TypeScript service with
POST /documents/classify-and-extract: it classifies the upload with the Cogneris classifier API and, for invoices and receipts, also extracts the fields. Validate the upload withmulter(PDF, PNG, JPG, max 10 MB), add an OpenAPI document, a Vitest test that mocks Cogneris, and read the key fromCOGNERIS_API_KEY.
The assistant reads both Cogneris routes with cogneris_api_reference, scaffolds the project, wires the client,
creates the sandbox key into .env and, if you ask, runs the service and calls it with a sample file.
Create a webhook
Get told when Cogneris finishes a document instead of polling.
Using Cogneris, register a webhook at
https://api.example.com/hooks/cognerisfor processed documents. Write the receiver in this project as an ASP.NET Core endpoint that verifies the Cogneris signature on the raw body, ignores deliveries it has already seen, and enqueues the job id. Store the signing secret in.envasCOGNERIS_WEBHOOK_SECRET. Then send a test delivery and show me the result.
What the assistant does
cogneris_webhooks_event_types— finds the event,com.cogneris.document.processed.v1, and checks it is live (sent today) rather than only planned.cogneris_webhooks_create— registers the endpoint. The signing secret comes back once, together with receiver code in Node, Python and C#; the assistant writes the secret to.env.- Writes the receiver: verifies
Cogneris-Webhook-Signature, rejects timestamps older than 300 seconds, and usesCogneris-Webhook-Id(the same on every retry) as the idempotency key. cogneris_webhooks_test, thencogneris_webhooks_deliveries_get— sends a signed test delivery and shows the status code your receiver answered.
The signature is t=<unix seconds>,v1=<hex>: an HMAC-SHA256 of "<t>." + raw body, keyed with the signing
secret base64url-decoded — keying with the secret's text never matches. This is the check the assistant
writes:
- C#
- Node
- Python
static bool VerifyCogneris(byte[] rawBody, string? signatureHeader, string secret)
{
string? ts = null, v1 = null;
foreach (var part in (signatureHeader ?? "").Split(',', StringSplitOptions.TrimEntries))
{
if (part.StartsWith("t=")) ts = part[2..];
else if (part.StartsWith("v1=")) v1 = part[3..];
}
if (!long.TryParse(ts, out var t) || v1 is null) return false;
if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return false;
byte[] supplied;
try { supplied = Convert.FromHexString(v1); } catch (FormatException) { return false; }
var key = Base64Url.DecodeFromChars(secret);
var signed = Encoding.UTF8.GetBytes($"{t}.").Concat(rawBody).ToArray();
return CryptographicOperations.FixedTimeEquals(HMACSHA256.HashData(key, signed), supplied);
}
import crypto from 'node:crypto';
// Express: mount the route with express.raw({ type: 'application/json' }) to keep the raw body.
export function verifyCogneris(rawBody, signatureHeader, secret = process.env.COGNERIS_WEBHOOK_SECRET) {
const parts = Object.fromEntries(String(signatureHeader ?? '').split(',').map((p) => p.trim().split('=', 2)));
const t = Number(parts.t);
if (!Number.isInteger(t) || !/^[0-9a-f]{64}$/.test(parts.v1 ?? '')) return false;
if (Math.abs(Date.now() / 1000 - t) > 300) return false;
const key = Buffer.from(secret, 'base64url');
const expected = crypto.createHmac('sha256', key).update(`${t}.`).update(rawBody).digest();
return crypto.timingSafeEqual(expected, Buffer.from(parts.v1, 'hex'));
}
import base64, hashlib, hmac, os, time
def verify_cogneris(raw_body: bytes, signature_header: str | None, secret: str | None = None) -> bool:
secret = secret or os.environ["COGNERIS_WEBHOOK_SECRET"]
parts = dict(p.strip().split("=", 1) for p in (signature_header or "").split(",") if "=" in p)
try:
t = int(parts["t"])
supplied = bytes.fromhex(parts["v1"])
except (KeyError, ValueError):
return False
if abs(time.time() - t) > 300:
return False
key = base64.urlsafe_b64decode(secret + "=" * (-len(secret) % 4))
expected = hmac.new(key, f"{t}.".encode() + raw_body, hashlib.sha256).digest()
return hmac.compare_digest(expected, supplied)
The endpoint must be public HTTPS on port 443 — for a receiver on your machine, expose it through a tunnel first.
This needs a developer token with the webhooks.manage scope.
When a delivery fails:
Why did the last Cogneris webhook deliveries fail? Show the status codes my endpoint answered and replay the failed ones once the receiver is fixed.
Create your own document type
The server ships this flow as a ready-made prompt — in VS Code, type / in the chat and pick Create and train
a Cogneris classifier. Or write it:
Using Cogneris, create a classifier called "Supplier invoice" from the PDFs in
samples/invoices/, train it and tell me when it is ready.
The assistant uploads the samples (up to 10 files of 10 MB each per call), starts training and follows the
status until it is Finished. A finished classifier drives classification and extraction for your tenant.
Ask about your account
How many documents and pages did we process on Cogneris in the last 7 days, per document type?
Which Cogneris API routes handle face match? Show me the request with curl.