@talonic/docs 0.20.0 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/content.js +351 -79
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/seo.js +479 -2
- package/dist/tailwind-preset.d.cts +45 -0
- package/dist/tailwind-preset.d.ts +45 -0
- package/openapi.json +519 -44
- package/package.json +1 -1
package/dist/content.js
CHANGED
|
@@ -34,7 +34,9 @@ var API_NAV_SECTIONS = [
|
|
|
34
34
|
{ id: "introduction", label: "Introduction" },
|
|
35
35
|
{ id: "authentication", label: "Authentication" },
|
|
36
36
|
{ id: "base-url", label: "Base URL" },
|
|
37
|
-
{ id: "quick-start", label: "Quick Start" }
|
|
37
|
+
{ id: "quick-start", label: "Quick Start" },
|
|
38
|
+
{ id: "pagination", label: "Pagination" },
|
|
39
|
+
{ id: "idempotency", label: "Idempotency" }
|
|
38
40
|
] },
|
|
39
41
|
{ id: "extract", label: "Extract", children: [
|
|
40
42
|
{ id: "post-extract", label: "POST /v1/extract" },
|
|
@@ -4426,11 +4428,24 @@ var sections17 = [
|
|
|
4426
4428
|
parentSlug: "overview",
|
|
4427
4429
|
title: "Authentication",
|
|
4428
4430
|
seoTitle: "API Authentication \u2014 Talonic Docs",
|
|
4429
|
-
description: "Learn how to authenticate with the Talonic API using Bearer tokens and API keys with the tlnc_ prefix,
|
|
4431
|
+
description: "Learn how to authenticate with the Talonic API using Bearer tokens and API keys with the tlnc_ prefix. Keys carry scopes (extract, read, write) that control access.",
|
|
4430
4432
|
content: [
|
|
4431
|
-
{ type: "paragraph", text: "All API requests require a Bearer token in the `Authorization` header. API keys
|
|
4433
|
+
{ type: "paragraph", text: "All API requests require a Bearer token in the `Authorization` header. API keys carry the `tlnc_` prefix and can be scoped to a source. Create and manage keys from **Settings \u2192 API Keys** in the dashboard." },
|
|
4432
4434
|
{ type: "code", language: "bash", title: "Authorization header", code: `curl https://api.talonic.com/v1/documents \\
|
|
4433
|
-
-H "Authorization: Bearer
|
|
4435
|
+
-H "Authorization: Bearer $TALONIC_API_KEY"` },
|
|
4436
|
+
{ type: "heading", level: 2, id: "api-key-scopes", text: "API Key Scopes" },
|
|
4437
|
+
{ type: "paragraph", text: "Each API key carries one or more scopes that determine which operations it can perform. New keys default to all three scopes." },
|
|
4438
|
+
{
|
|
4439
|
+
type: "param-table",
|
|
4440
|
+
title: "Available scopes",
|
|
4441
|
+
params: [
|
|
4442
|
+
{ name: "extract", type: "scope", description: "Submit documents for extraction (`POST /v1/extract`, `POST /v1/documents/:id/re-extract`)." },
|
|
4443
|
+
{ name: "read", type: "scope", description: "Read operations \u2014 list and retrieve documents, extractions, schemas, jobs, sources, and other resources." },
|
|
4444
|
+
{ name: "write", type: "scope", description: "Write operations \u2014 create, update, and delete schemas, sources, jobs, delivery bindings, and other resources." },
|
|
4445
|
+
{ name: "billing", type: "scope", description: "Billing operations \u2014 trigger credit top-ups (`POST /v1/billing/topup`). Not included by default; add explicitly when creating the key." }
|
|
4446
|
+
]
|
|
4447
|
+
},
|
|
4448
|
+
{ type: "paragraph", text: "New keys default to `extract`, `read`, and `write`. The `billing` scope must be added explicitly. If a request requires a scope your key does not carry, the API returns `403` with error code `insufficient_scope` and lists the required scopes in the response body." },
|
|
4434
4449
|
{ type: "callout", text: "Keep your API key secret. Do not expose it in client-side code or version control. If a key is compromised, revoke it immediately from the dashboard." }
|
|
4435
4450
|
],
|
|
4436
4451
|
related: [
|
|
@@ -4438,10 +4453,11 @@ var sections17 = [
|
|
|
4438
4453
|
{ label: "Error Codes", slug: "error-codes" }
|
|
4439
4454
|
],
|
|
4440
4455
|
faq: [
|
|
4441
|
-
{ question: "How do I authenticate with the Talonic API?", answer: "Include a Bearer token in the Authorization header of every request. API keys use the tlnc_ prefix
|
|
4442
|
-
{ question: "Where do I get an API key?", answer: "Create and manage API keys from Settings
|
|
4456
|
+
{ question: "How do I authenticate with the Talonic API?", answer: "Include a Bearer token in the Authorization header of every request. API keys use the tlnc_ prefix." },
|
|
4457
|
+
{ question: "Where do I get an API key?", answer: "Create and manage API keys from Settings \u2192 API Keys in the Talonic dashboard." },
|
|
4458
|
+
{ question: "What scopes are available?", answer: "Four scopes: extract (submit documents), read (list/retrieve resources), write (create/update/delete resources), and billing (trigger credit top-ups). New keys get extract, read, and write by default; billing must be added explicitly." }
|
|
4443
4459
|
],
|
|
4444
|
-
mentions: ["Bearer token", "API key", "Authorization header"]
|
|
4460
|
+
mentions: ["Bearer token", "API key", "Authorization header", "scopes", "extract", "read", "write"]
|
|
4445
4461
|
},
|
|
4446
4462
|
{
|
|
4447
4463
|
slug: "base-url",
|
|
@@ -4466,55 +4482,246 @@ var sections17 = [
|
|
|
4466
4482
|
parentSlug: "overview",
|
|
4467
4483
|
title: "Quick Start",
|
|
4468
4484
|
seoTitle: "API Quick Start Guide \u2014 Talonic Docs",
|
|
4469
|
-
description: "
|
|
4485
|
+
description: "Three modes, one API. Auto-detect extraction, schema-driven extraction, and document filtering \u2014 all with per-cell confidence and cost transparency.",
|
|
4470
4486
|
content: [
|
|
4471
|
-
{ type: "paragraph", text: "
|
|
4472
|
-
{ type: "heading", level: 3, id: "
|
|
4473
|
-
{ type: "
|
|
4474
|
-
|
|
4487
|
+
{ type: "paragraph", text: "Three modes. One API. Auto-detect what's in the document. Send your own schema and get exactly that shape. Or skip the document entirely and query data you already ingested. Plus per-cell provenance, confidence scores, and cost transparency on every call." },
|
|
4488
|
+
{ type: "heading", level: 3, id: "prerequisites", text: "Prerequisites" },
|
|
4489
|
+
{ type: "list", items: [
|
|
4490
|
+
"A Talonic account \u2014 sign up at [app.talonic.com](https://app.talonic.com)",
|
|
4491
|
+
"An API key from **Settings \u2192 API Keys** (starts with `tlnc_`)",
|
|
4492
|
+
"A PDF or image file to extract (e.g. an invoice)"
|
|
4493
|
+
] },
|
|
4494
|
+
{ type: "code", language: "bash", title: "Set your API key", code: `export TALONIC_API_KEY="tlnc_live_..."` },
|
|
4495
|
+
{ type: "heading", level: 2, id: "mode-1-auto-detect", text: "Mode 1 \u2014 Auto-detect extract" },
|
|
4496
|
+
{ type: "paragraph", text: "Send a document with no schema. Talonic discovers every field automatically." },
|
|
4497
|
+
{ type: "code", language: "bash", title: "curl \u2014 auto-detect all fields", code: `curl -X POST https://api.talonic.com/v1/extract \\
|
|
4498
|
+
-H "Authorization: Bearer $TALONIC_API_KEY" \\
|
|
4499
|
+
-F "file=@invoice.pdf"` },
|
|
4500
|
+
{ type: "paragraph", text: "Returns every field the AI discovers \u2014 vendor, dates, amounts, line items, addresses \u2014 with per-field confidence scores. Use this when you don't know the document structure upfront." },
|
|
4501
|
+
{ type: "heading", level: 2, id: "mode-2-schema-extract", text: "Mode 2 \u2014 Schema-driven extract" },
|
|
4502
|
+
{ type: "paragraph", text: "Send a document AND the shape you want. Get exactly those fields back." },
|
|
4503
|
+
{ type: "code", language: "bash", title: "curl \u2014 extract with inline schema", code: `curl -X POST https://api.talonic.com/v1/extract \\
|
|
4504
|
+
-H "Authorization: Bearer $TALONIC_API_KEY" \\
|
|
4475
4505
|
-F "file=@invoice.pdf" \\
|
|
4476
|
-
-F 'schema={
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
"description": "string",
|
|
4483
|
-
"quantity": "number",
|
|
4484
|
-
"unit_price": "number"
|
|
4485
|
-
}]
|
|
4486
|
-
}'` },
|
|
4487
|
-
{ type: "heading", level: 3, id: "step-2", text: "2. Save the schema for reuse" },
|
|
4488
|
-
{ type: "code", language: "bash", title: "Step 2 \u2014 Save schema", code: `curl -X POST https://api.talonic.com/v1/schemas \\
|
|
4489
|
-
-H "Authorization: Bearer tlnc_sk_live_7f3a...x9k2" \\
|
|
4506
|
+
-F 'schema={"vendor_name":"string","invoice_number":"string","total_amount":"number","due_date":"date"}'` },
|
|
4507
|
+
{ type: "paragraph", text: "The response contains exactly the four fields you asked for \u2014 nothing more. Save the schema with `POST /v1/schemas` for reuse across future extractions." },
|
|
4508
|
+
{ type: "heading", level: 2, id: "mode-3-filter", text: "Mode 3 \u2014 Query ingested data" },
|
|
4509
|
+
{ type: "paragraph", text: "Don't send a document. Query data you already extracted \u2014 across all documents in your workspace." },
|
|
4510
|
+
{ type: "code", language: "bash", title: "curl \u2014 filter previously extracted documents", code: `curl -X POST https://api.talonic.com/v1/documents/filter \\
|
|
4511
|
+
-H "Authorization: Bearer $TALONIC_API_KEY" \\
|
|
4490
4512
|
-H "Content-Type: application/json" \\
|
|
4491
4513
|
-d '{
|
|
4492
|
-
"
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
"total_amount": "number",
|
|
4497
|
-
"due_date": "date",
|
|
4498
|
-
"line_items": [{
|
|
4499
|
-
"description": "string",
|
|
4500
|
-
"quantity": "number",
|
|
4501
|
-
"unit_price": "number"
|
|
4502
|
-
}]
|
|
4503
|
-
}
|
|
4514
|
+
"conditions": [
|
|
4515
|
+
{ "fieldId": "vendor_name", "operator": "eq", "value": "Acme GmbH" }
|
|
4516
|
+
],
|
|
4517
|
+
"limit": 50
|
|
4504
4518
|
}'` },
|
|
4505
|
-
{ type: "
|
|
4506
|
-
{ type: "
|
|
4507
|
-
|
|
4519
|
+
{ type: "paragraph", text: "Returns all documents matching your filter \u2014 no re-extraction, no AI cost. Ingest once, query forever." },
|
|
4520
|
+
{ type: "heading", level: 2, id: "cost-transparency", text: "Cost on every call" },
|
|
4521
|
+
{ type: "paragraph", text: "Every synchronous extraction response includes cost headers so you can track spend per call:" },
|
|
4522
|
+
{ type: "code", language: "bash", title: "Cost headers", code: `X-Talonic-Cost-Credits: 12
|
|
4523
|
+
X-Talonic-Cost-EUR: 0.012
|
|
4524
|
+
X-Talonic-Balance-Credits: 64918
|
|
4525
|
+
X-Talonic-Cells-Resolved-Registry: 3
|
|
4526
|
+
X-Talonic-Cells-Resolved-AI: 5` },
|
|
4527
|
+
{ type: "paragraph", text: "Fields resolved from the registry (`X-Talonic-Cells-Resolved-Registry`) cost nothing. Only AI-resolved fields consume credits." },
|
|
4528
|
+
{ type: "heading", level: 2, id: "example-response", text: "Example response" },
|
|
4529
|
+
{ type: "paragraph", text: "A synchronous extraction returns structured data with confidence scores:" },
|
|
4530
|
+
{ type: "code", language: "json", title: "Response (200 OK)", code: `{
|
|
4531
|
+
"extraction_id": "d1a2b3c4-5678-9abc-def0-1234567890ab",
|
|
4532
|
+
"request_id": "req_x7y8z9a0b1c2d3e4",
|
|
4533
|
+
"status": "complete",
|
|
4534
|
+
"document": {
|
|
4535
|
+
"id": "f0e1d2c3-b4a5-9687-8765-432109876543",
|
|
4536
|
+
"filename": "invoice.pdf",
|
|
4537
|
+
"pages": 2,
|
|
4538
|
+
"type_detected": "Invoice"
|
|
4539
|
+
},
|
|
4540
|
+
"data": {
|
|
4541
|
+
"vendor_name": "Acme GmbH",
|
|
4542
|
+
"invoice_number": "INV-2025-0042",
|
|
4543
|
+
"total_amount": 14250.00,
|
|
4544
|
+
"due_date": "2025-04-15"
|
|
4545
|
+
},
|
|
4546
|
+
"confidence": {
|
|
4547
|
+
"overall": 0.96,
|
|
4548
|
+
"fields": {
|
|
4549
|
+
"vendor_name": 0.97,
|
|
4550
|
+
"invoice_number": 0.99,
|
|
4551
|
+
"total_amount": 0.94,
|
|
4552
|
+
"due_date": 0.99
|
|
4553
|
+
}
|
|
4554
|
+
},
|
|
4555
|
+
"processing": {
|
|
4556
|
+
"duration_ms": 1840,
|
|
4557
|
+
"pages_processed": 2
|
|
4558
|
+
}
|
|
4559
|
+
}` },
|
|
4560
|
+
{ type: "heading", level: 3, id: "next-steps", text: "Next steps" },
|
|
4561
|
+
{ type: "list", items: [
|
|
4562
|
+
"**Reuse schemas** \u2014 save your schema with `POST /v1/schemas`, then pass `schema_id` on future extractions.",
|
|
4563
|
+
"**Large documents** \u2014 files >5 pages return `202 Accepted` with a `poll_url`. See [Processing Modes](extract-processing-mode).",
|
|
4564
|
+
"**Webhooks** \u2014 receive results via `extraction.complete` events instead of polling. See [Webhook Events](webhook-events).",
|
|
4565
|
+
"**Batch mode** \u2014 process at 50% cost with `processing_mode=batch`. See [Batches](batches).",
|
|
4566
|
+
"**Credits** \u2014 check your balance anytime with `GET /v1/credits/balance`. See [Credits](credits-balance)."
|
|
4567
|
+
] }
|
|
4508
4568
|
],
|
|
4509
4569
|
related: [
|
|
4510
4570
|
{ label: "POST /v1/extract", slug: "post-extract" },
|
|
4571
|
+
{ label: "Filter Documents", slug: "filter-documents" },
|
|
4511
4572
|
{ label: "Schema Formats", slug: "extract-schemas" },
|
|
4512
|
-
{ label: "
|
|
4573
|
+
{ label: "Processing Modes", slug: "extract-processing-mode" }
|
|
4574
|
+
],
|
|
4575
|
+
faq: [
|
|
4576
|
+
{ question: "How do I get started with the Talonic API?", answer: "Three modes: (1) send a file with no schema for auto-detect, (2) send a file with a schema for exact extraction, (3) POST /v1/documents/filter to query already-ingested data." },
|
|
4577
|
+
{ question: "Do I need to create a schema first?", answer: "No. Mode 1 auto-detects all fields. Mode 2 accepts an inline schema. Save it with POST /v1/schemas later for reuse." },
|
|
4578
|
+
{ question: "Can I query previously extracted data without re-extracting?", answer: "Yes. POST /v1/documents/filter lets you search across all previously extracted documents by field values. No AI cost \u2014 ingest once, query forever." }
|
|
4579
|
+
],
|
|
4580
|
+
mentions: ["curl", "quick start", "sync mode", "three modes", "auto-detect", "filter", "query", "cost headers"]
|
|
4581
|
+
},
|
|
4582
|
+
{
|
|
4583
|
+
slug: "pagination",
|
|
4584
|
+
parentSlug: "overview",
|
|
4585
|
+
title: "Pagination",
|
|
4586
|
+
seoTitle: "API Pagination \u2014 Talonic Docs",
|
|
4587
|
+
description: "All list endpoints use cursor-based pagination with cursor, limit, and order parameters. Responses include next_cursor and has_more for iteration.",
|
|
4588
|
+
content: [
|
|
4589
|
+
{ type: "paragraph", text: "All list endpoints use cursor-based pagination. Pass a `cursor` token from the previous response to fetch the next page." },
|
|
4590
|
+
{
|
|
4591
|
+
type: "param-table",
|
|
4592
|
+
title: "Request parameters",
|
|
4593
|
+
params: [
|
|
4594
|
+
{ name: "limit", type: "integer", description: "Number of items per page (1\u2013100, default 20).", default: "20" },
|
|
4595
|
+
{ name: "cursor", type: "string", description: "Opaque cursor token from `pagination.next_cursor` of the previous response. Omit for the first page." },
|
|
4596
|
+
{ name: "order", type: "string", description: "Sort direction: `asc` or `desc` (default `desc`, newest first).", default: "desc" }
|
|
4597
|
+
]
|
|
4598
|
+
},
|
|
4599
|
+
{ type: "heading", level: 2, id: "pagination-response", text: "Response shape" },
|
|
4600
|
+
{
|
|
4601
|
+
type: "code",
|
|
4602
|
+
title: "Paginated response",
|
|
4603
|
+
code: `{
|
|
4604
|
+
"data": [
|
|
4605
|
+
{ "id": "doc_x9y8z7w6", "name": "invoice-001.pdf", "..." : "..." },
|
|
4606
|
+
{ "id": "doc_a1b2c3d4", "name": "invoice-002.pdf", "..." : "..." }
|
|
4607
|
+
],
|
|
4608
|
+
"pagination": {
|
|
4609
|
+
"total": 1500,
|
|
4610
|
+
"limit": 20,
|
|
4611
|
+
"has_more": true,
|
|
4612
|
+
"next_cursor": "YWJjMTIzfDIwMjYtMDQtMjVUMTQ6MzA6MDAuMDAwWg"
|
|
4613
|
+
}
|
|
4614
|
+
}`
|
|
4615
|
+
},
|
|
4616
|
+
{
|
|
4617
|
+
type: "param-table",
|
|
4618
|
+
title: "Pagination object",
|
|
4619
|
+
params: [
|
|
4620
|
+
{ name: "total", type: "integer", description: "Total number of items matching the query." },
|
|
4621
|
+
{ name: "limit", type: "integer", description: "Page size used for this request." },
|
|
4622
|
+
{ name: "has_more", type: "boolean", description: "`true` if there are more pages after this one." },
|
|
4623
|
+
{ name: "next_cursor", type: "string | null", description: "Cursor token to pass in the next request. `null` when on the last page." }
|
|
4624
|
+
]
|
|
4625
|
+
},
|
|
4626
|
+
{ type: "heading", level: 2, id: "pagination-example", text: "Iterating through all pages" },
|
|
4627
|
+
{
|
|
4628
|
+
type: "code",
|
|
4629
|
+
language: "bash",
|
|
4630
|
+
title: "Python \u2014 paginate through all documents",
|
|
4631
|
+
code: `import requests
|
|
4632
|
+
|
|
4633
|
+
API_KEY = "tlnc_live_..."
|
|
4634
|
+
BASE = "https://api.talonic.com/v1"
|
|
4635
|
+
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
|
|
4636
|
+
|
|
4637
|
+
cursor = None
|
|
4638
|
+
all_documents = []
|
|
4639
|
+
|
|
4640
|
+
while True:
|
|
4641
|
+
params = {"limit": 100}
|
|
4642
|
+
if cursor:
|
|
4643
|
+
params["cursor"] = cursor
|
|
4644
|
+
|
|
4645
|
+
resp = requests.get(f"{BASE}/documents", headers=HEADERS, params=params)
|
|
4646
|
+
page = resp.json()
|
|
4647
|
+
|
|
4648
|
+
all_documents.extend(page["data"])
|
|
4649
|
+
|
|
4650
|
+
if not page["pagination"]["has_more"]:
|
|
4651
|
+
break
|
|
4652
|
+
cursor = page["pagination"]["next_cursor"]
|
|
4653
|
+
|
|
4654
|
+
print(f"Fetched {len(all_documents)} documents")`
|
|
4655
|
+
},
|
|
4656
|
+
{ type: "callout", text: "Cursors are opaque tokens \u2014 do not parse, modify, or store them long-term. They may change format without notice." }
|
|
4657
|
+
],
|
|
4658
|
+
related: [
|
|
4659
|
+
{ label: "List Documents", slug: "list-documents" },
|
|
4660
|
+
{ label: "List Extractions", slug: "list-extractions" },
|
|
4661
|
+
{ label: "Rate Limits", slug: "rate-limits" }
|
|
4662
|
+
],
|
|
4663
|
+
faq: [
|
|
4664
|
+
{ question: "How does Talonic API pagination work?", answer: "Cursor-based. Pass limit (1-100, default 20) and cursor (from pagination.next_cursor). Response includes data[], pagination.has_more, and pagination.next_cursor." },
|
|
4665
|
+
{ question: "What is the maximum page size?", answer: "100 items per page. Default is 20." }
|
|
4666
|
+
],
|
|
4667
|
+
mentions: ["pagination", "cursor", "next_cursor", "has_more", "limit"]
|
|
4668
|
+
},
|
|
4669
|
+
{
|
|
4670
|
+
slug: "idempotency",
|
|
4671
|
+
parentSlug: "overview",
|
|
4672
|
+
title: "Idempotency",
|
|
4673
|
+
seoTitle: "API Idempotency \u2014 Talonic Docs",
|
|
4674
|
+
description: "Use the Idempotency-Key header to safely retry POST requests without creating duplicate extractions. Keys are valid for 24 hours.",
|
|
4675
|
+
content: [
|
|
4676
|
+
{ type: "paragraph", text: "Pass an `Idempotency-Key` header on POST requests to safely retry without creating duplicate work. If a request with the same key has already been processed, the API returns the cached response." },
|
|
4677
|
+
{
|
|
4678
|
+
type: "param-table",
|
|
4679
|
+
title: "Idempotency details",
|
|
4680
|
+
params: [
|
|
4681
|
+
{ name: "Header", type: "", description: "`Idempotency-Key: <your-unique-key>`" },
|
|
4682
|
+
{ name: "Supported endpoints", type: "", description: "`POST /v1/extract` (primary use case). Other POST endpoints may honor it in the future." },
|
|
4683
|
+
{ name: "Key format", type: "", description: "Any string up to 255 characters. UUIDs recommended." },
|
|
4684
|
+
{ name: "TTL", type: "", description: "24 hours. After expiry, the same key can be reused." },
|
|
4685
|
+
{ name: "Scope", type: "", description: "Per API key (customer). The same idempotency key used by different API keys are independent." }
|
|
4686
|
+
]
|
|
4687
|
+
},
|
|
4688
|
+
{ type: "heading", level: 2, id: "idempotency-behavior", text: "Behavior" },
|
|
4689
|
+
{ type: "list", items: [
|
|
4690
|
+
"**First request** \u2014 processed normally. The response and extraction ID are cached against the key.",
|
|
4691
|
+
"**Duplicate request** (same key within 24h) \u2014 returns the cached response immediately with HTTP 200. No new extraction is created.",
|
|
4692
|
+
"**Expired key** (after 24h) \u2014 treated as a new request."
|
|
4693
|
+
] },
|
|
4694
|
+
{
|
|
4695
|
+
type: "code",
|
|
4696
|
+
language: "bash",
|
|
4697
|
+
title: "Example \u2014 safe retry with idempotency",
|
|
4698
|
+
code: `# Generate a unique key per logical operation
|
|
4699
|
+
IDEMPOTENCY_KEY=$(uuidgen)
|
|
4700
|
+
|
|
4701
|
+
curl -X POST https://api.talonic.com/v1/extract \\
|
|
4702
|
+
-H "Authorization: Bearer $TALONIC_API_KEY" \\
|
|
4703
|
+
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \\
|
|
4704
|
+
-F "file=@invoice.pdf" \\
|
|
4705
|
+
-F 'schema={"vendor_name":"string","total_amount":"number"}'
|
|
4706
|
+
|
|
4707
|
+
# Safe to retry on network timeout \u2014 same key returns cached result
|
|
4708
|
+
curl -X POST https://api.talonic.com/v1/extract \\
|
|
4709
|
+
-H "Authorization: Bearer $TALONIC_API_KEY" \\
|
|
4710
|
+
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \\
|
|
4711
|
+
-F "file=@invoice.pdf" \\
|
|
4712
|
+
-F 'schema={"vendor_name":"string","total_amount":"number"}'`
|
|
4713
|
+
},
|
|
4714
|
+
{ type: "callout", text: "Always use a new idempotency key for each distinct logical operation. Reusing a key with different parameters will return the cached result from the first request, not process the new parameters." }
|
|
4715
|
+
],
|
|
4716
|
+
related: [
|
|
4717
|
+
{ label: "POST /v1/extract", slug: "post-extract" },
|
|
4718
|
+
{ label: "Error Codes", slug: "error-codes" }
|
|
4513
4719
|
],
|
|
4514
4720
|
faq: [
|
|
4515
|
-
{ question: "How do I
|
|
4721
|
+
{ question: "How do I prevent duplicate extractions on retry?", answer: "Pass an Idempotency-Key header with a unique value (e.g. UUID) on POST /v1/extract. Retries with the same key return the cached result." },
|
|
4722
|
+
{ question: "How long are idempotency keys valid?", answer: "24 hours. After that, the same key can be reused and will trigger a new extraction." }
|
|
4516
4723
|
],
|
|
4517
|
-
mentions: ["
|
|
4724
|
+
mentions: ["idempotency", "Idempotency-Key", "retry", "duplicate"]
|
|
4518
4725
|
}
|
|
4519
4726
|
];
|
|
4520
4727
|
|
|
@@ -4665,9 +4872,34 @@ var sections18 = [
|
|
|
4665
4872
|
{ name: "400", type: "invalid_options", description: "The options field is not valid JSON." },
|
|
4666
4873
|
{ name: "401", type: "unauthorized", description: "Missing or invalid API key." },
|
|
4667
4874
|
{ name: "422", type: "extraction_failed", description: "Extraction completed but produced no usable output. Check the document quality or schema definition." },
|
|
4668
|
-
{ name: "429", type: "rate_limited", description: "Too many requests.
|
|
4875
|
+
{ name: "429", type: "rate_limited", description: "Too many requests. Check X-RateLimit-Reset for when the window resets." }
|
|
4669
4876
|
]
|
|
4670
|
-
}
|
|
4877
|
+
},
|
|
4878
|
+
{ type: "heading", level: 2, id: "post-extract-cost-headers", text: "Cost Headers" },
|
|
4879
|
+
{ type: "paragraph", text: "Synchronous 200 responses include cost transparency headers so you can track spend per call without a separate API round-trip:" },
|
|
4880
|
+
{
|
|
4881
|
+
type: "param-table",
|
|
4882
|
+
title: "Cost response headers",
|
|
4883
|
+
params: [
|
|
4884
|
+
{ name: "X-Talonic-Cost-Credits", type: "integer", description: "Credits consumed by this extraction." },
|
|
4885
|
+
{ name: "X-Talonic-Cost-EUR", type: "number", description: "EUR cost of this extraction." },
|
|
4886
|
+
{ name: "X-Talonic-Balance-Credits", type: "integer", description: "Remaining credit balance after this call." },
|
|
4887
|
+
{ name: "X-Talonic-Cells-Resolved-Registry", type: "integer", description: "Fields resolved from the registry (no AI cost)." },
|
|
4888
|
+
{ name: "X-Talonic-Cells-Resolved-AI", type: "integer", description: "Fields resolved by the AI model." }
|
|
4889
|
+
]
|
|
4890
|
+
},
|
|
4891
|
+
{
|
|
4892
|
+
type: "code",
|
|
4893
|
+
language: "bash",
|
|
4894
|
+
title: "Cost headers on a sync response",
|
|
4895
|
+
code: `HTTP/1.1 200 OK
|
|
4896
|
+
X-Talonic-Cost-Credits: 12
|
|
4897
|
+
X-Talonic-Cost-EUR: 0.012
|
|
4898
|
+
X-Talonic-Balance-Credits: 64918
|
|
4899
|
+
X-Talonic-Cells-Resolved-Registry: 3
|
|
4900
|
+
X-Talonic-Cells-Resolved-AI: 5`
|
|
4901
|
+
},
|
|
4902
|
+
{ type: "callout", text: "Cost headers are only present on synchronous (200) responses. For async (202) extractions, check the credits balance endpoint or listen for the `extraction.complete` webhook which includes cost data." }
|
|
4671
4903
|
],
|
|
4672
4904
|
related: [
|
|
4673
4905
|
{ label: "Schema Formats", slug: "extract-schemas" },
|
|
@@ -7601,7 +7833,7 @@ function verifyWebhook(payload, signature, secret) {
|
|
|
7601
7833
|
title: "Test inputs",
|
|
7602
7834
|
code: `Secret: whsec_test_secret_do_not_use_in_production
|
|
7603
7835
|
Payload: {"event":"extraction.complete","delivery_id":"dlv_test123","timestamp":"2026-01-15T10:00:00Z","data":{"extraction_id":"ext_abc","document_id":"doc_xyz","schema_id":"sch_123","status":"complete","confidence":0.95}}
|
|
7604
|
-
Expected signature: sha256=
|
|
7836
|
+
Expected signature: sha256=1e23bdc14b051f268d4fd9544387b51b074186c51c5b6c76ce700956308d168a`
|
|
7605
7837
|
},
|
|
7606
7838
|
{
|
|
7607
7839
|
type: "code",
|
|
@@ -7611,7 +7843,7 @@ Expected signature: sha256=a4f2b8c1d3e5f7a9b0c2d4e6f8a1b3c5d7e9f0a2b4c6d8e0f1a3b
|
|
|
7611
7843
|
echo -n '{"event":"extraction.complete","delivery_id":"dlv_test123","timestamp":"2026-01-15T10:00:00Z","data":{"extraction_id":"ext_abc","document_id":"doc_xyz","schema_id":"sch_123","status":"complete","confidence":0.95}}' \\
|
|
7612
7844
|
| openssl dgst -sha256 -hmac "whsec_test_secret_do_not_use_in_production"
|
|
7613
7845
|
|
|
7614
|
-
# Output:
|
|
7846
|
+
# Output: 1e23bdc14b051f268d4fd9544387b51b074186c51c5b6c76ce700956308d168a`
|
|
7615
7847
|
},
|
|
7616
7848
|
{ type: "callout", text: "The test secret above is for development only. Never use it in production. Your real webhook secret is generated when you configure a webhook in the dashboard." }
|
|
7617
7849
|
],
|
|
@@ -17118,21 +17350,36 @@ var sections44 = [
|
|
|
17118
17350
|
parentSlug: "errors-rate-limits",
|
|
17119
17351
|
title: "Error Format",
|
|
17120
17352
|
seoTitle: "API Error Format \u2014 Talonic Docs",
|
|
17121
|
-
description: "All Talonic API errors return a consistent JSON
|
|
17353
|
+
description: "All Talonic API errors return a consistent JSON envelope with a machine-readable code, human-readable message, HTTP status, retryable flag, request ID, and timestamp.",
|
|
17122
17354
|
content: [
|
|
17123
|
-
{ type: "paragraph", text: "All errors return a consistent JSON
|
|
17355
|
+
{ type: "paragraph", text: "All errors return a consistent JSON envelope. The `retryable` field tells you whether the request can be retried with the same parameters." },
|
|
17124
17356
|
{
|
|
17125
17357
|
type: "code",
|
|
17126
|
-
title: "Error response
|
|
17358
|
+
title: "Error response envelope",
|
|
17127
17359
|
code: `{
|
|
17128
|
-
"
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17360
|
+
"statusCode": 400,
|
|
17361
|
+
"code": "VALIDATION_ERROR",
|
|
17362
|
+
"error": "Bad Request",
|
|
17363
|
+
"message": "Schema definition is missing required 'type' field at path 'line_items.items'.",
|
|
17364
|
+
"retryable": false,
|
|
17365
|
+
"request_id": "req_x7y8z9a0b1c2d3e4",
|
|
17366
|
+
"timestamp": "2026-04-25T14:30:00.000Z",
|
|
17367
|
+
"path": "/v1/schemas"
|
|
17135
17368
|
}`
|
|
17369
|
+
},
|
|
17370
|
+
{
|
|
17371
|
+
type: "param-table",
|
|
17372
|
+
title: "Envelope fields",
|
|
17373
|
+
params: [
|
|
17374
|
+
{ name: "statusCode", type: "integer", description: "HTTP status code (matches the response status)." },
|
|
17375
|
+
{ name: "code", type: "string", description: "Machine-readable error code (e.g. `VALIDATION_ERROR`, `RATE_LIMIT_EXCEEDED`)." },
|
|
17376
|
+
{ name: "error", type: "string", description: 'HTTP status text (e.g. "Bad Request", "Too Many Requests").' },
|
|
17377
|
+
{ name: "message", type: "string", description: "Human-readable explanation of what went wrong." },
|
|
17378
|
+
{ name: "retryable", type: "boolean", description: "`true` if the same request may succeed on retry (e.g. rate limits, timeouts)." },
|
|
17379
|
+
{ name: "request_id", type: "string", description: "Unique request identifier for support debugging. Prefix: `req_`." },
|
|
17380
|
+
{ name: "timestamp", type: "string", description: "ISO 8601 timestamp of when the error occurred." },
|
|
17381
|
+
{ name: "path", type: "string", description: "The request path that produced the error." }
|
|
17382
|
+
]
|
|
17136
17383
|
}
|
|
17137
17384
|
],
|
|
17138
17385
|
related: [
|
|
@@ -17140,41 +17387,66 @@ var sections44 = [
|
|
|
17140
17387
|
{ label: "Rate Limits", slug: "rate-limits" }
|
|
17141
17388
|
],
|
|
17142
17389
|
faq: [
|
|
17143
|
-
{ question: "What does a Talonic API error look like?", answer: "A JSON object with
|
|
17390
|
+
{ question: "What does a Talonic API error look like?", answer: "A JSON object with statusCode, code (machine-readable), message (human-readable), retryable (boolean), request_id, timestamp, and path." },
|
|
17391
|
+
{ question: "How do I know if an error is retryable?", answer: "Check the retryable field in the error response. If true, you can retry with exponential backoff." }
|
|
17144
17392
|
],
|
|
17145
|
-
mentions: ["error format", "JSON error", "request_id"]
|
|
17393
|
+
mentions: ["error format", "JSON error", "request_id", "retryable"]
|
|
17146
17394
|
},
|
|
17147
17395
|
{
|
|
17148
17396
|
slug: "error-codes",
|
|
17149
17397
|
parentSlug: "errors-rate-limits",
|
|
17150
17398
|
title: "Error Codes",
|
|
17151
17399
|
seoTitle: "API Error Codes Reference \u2014 Talonic Docs",
|
|
17152
|
-
description: "Complete reference of Talonic API error codes
|
|
17400
|
+
description: "Complete reference of Talonic API error codes with HTTP status, retryable classification, and recommended handling for each error type.",
|
|
17153
17401
|
content: [
|
|
17154
|
-
{ type: "paragraph", text: "Error codes returned by the Talonic API:" },
|
|
17402
|
+
{ type: "paragraph", text: "Error codes returned by the Talonic API, grouped by whether they are retryable:" },
|
|
17403
|
+
{ type: "heading", level: 2, id: "permanent-errors", text: "Permanent errors (do not retry)" },
|
|
17155
17404
|
{ type: "list", items: [
|
|
17156
|
-
"**400** `
|
|
17405
|
+
"**400** `VALIDATION_ERROR` \u2014 The request body is malformed or missing required fields.",
|
|
17157
17406
|
"**400** `invalid_schema` \u2014 The schema definition is invalid or contains unsupported types.",
|
|
17158
17407
|
"**400** `invalid_file` \u2014 The uploaded file is corrupt, empty, or in an unsupported format.",
|
|
17159
|
-
"**401** `
|
|
17160
|
-
"**
|
|
17161
|
-
"**
|
|
17162
|
-
"**
|
|
17163
|
-
"**
|
|
17164
|
-
"**
|
|
17165
|
-
"**
|
|
17166
|
-
"**
|
|
17408
|
+
"**401** `AUTH_REQUIRED` \u2014 Missing or invalid API key.",
|
|
17409
|
+
"**401** `TOKEN_EXPIRED` \u2014 The API key has expired. Generate a new one from the dashboard.",
|
|
17410
|
+
"**402** `INSUFFICIENT_CREDITS` \u2014 Your workspace has no remaining credits. Top up from Settings \u2192 Billing.",
|
|
17411
|
+
"**403** `INSUFFICIENT_PERMISSIONS` \u2014 The API key does not have the required scope for this operation.",
|
|
17412
|
+
"**404** `RESOURCE_NOT_FOUND` \u2014 The requested resource does not exist.",
|
|
17413
|
+
"**409** `DUPLICATE_RESOURCE` \u2014 A resource with this identifier already exists.",
|
|
17414
|
+
"**413** `FILE_TOO_LARGE` \u2014 The uploaded file exceeds the maximum size limit (500 MB).",
|
|
17415
|
+
"**422** `EXTRACTION_FAILED` \u2014 The document could not be processed. Try a different format or check the file."
|
|
17416
|
+
] },
|
|
17417
|
+
{ type: "heading", level: 2, id: "retryable-errors", text: "Retryable errors (retry with backoff)" },
|
|
17418
|
+
{ type: "list", items: [
|
|
17419
|
+
"**429** `RATE_LIMIT_EXCEEDED` \u2014 Daily rate limit reached. Wait until `X-RateLimit-Reset` before retrying.",
|
|
17420
|
+
"**429** `LLM_RATE_LIMITED` \u2014 Upstream AI provider rate limit. Retry after 30\u201360 seconds.",
|
|
17421
|
+
"**500** `INTERNAL_ERROR` \u2014 An unexpected server error occurred. Retryable with backoff.",
|
|
17422
|
+
"**500** `LLM_TIMEOUT` \u2014 Upstream AI provider timed out. Retryable with backoff.",
|
|
17423
|
+
"**500** `LLM_UNAVAILABLE` \u2014 Upstream AI provider temporarily unavailable.",
|
|
17424
|
+
"**500** `OCR_FAILED` \u2014 Document OCR failed. Retryable \u2014 may succeed on retry.",
|
|
17425
|
+
"**500** `EXTRACTION_TIMEOUT` \u2014 Extraction exceeded the time limit. Retryable for smaller documents.",
|
|
17167
17426
|
"**503** `service_unavailable` \u2014 The service is temporarily unavailable. Retry with backoff."
|
|
17168
|
-
] }
|
|
17427
|
+
] },
|
|
17428
|
+
{ type: "heading", level: 2, id: "backoff-strategy", text: "Recommended backoff strategy" },
|
|
17429
|
+
{ type: "paragraph", text: "For retryable errors, use exponential backoff with jitter:" },
|
|
17430
|
+
{ type: "list", ordered: true, items: [
|
|
17431
|
+
"1st retry \u2014 wait 1 second",
|
|
17432
|
+
"2nd retry \u2014 wait 2 seconds",
|
|
17433
|
+
"3rd retry \u2014 wait 4 seconds",
|
|
17434
|
+
"4th retry \u2014 wait 8 seconds",
|
|
17435
|
+
"5th retry (max) \u2014 wait 16 seconds"
|
|
17436
|
+
] },
|
|
17437
|
+
{ type: "paragraph", text: "Add random jitter (\xB120%) to avoid thundering herd. For `429` errors specifically, respect the `X-RateLimit-Reset` header instead of using fixed backoff \u2014 it tells you exactly when the window resets (ISO 8601 timestamp, midnight UTC)." },
|
|
17438
|
+
{ type: "callout", text: "The API does not send a `Retry-After` header. For rate limits, use `X-RateLimit-Reset` to determine when to retry. For other retryable errors, use exponential backoff." }
|
|
17169
17439
|
],
|
|
17170
17440
|
related: [
|
|
17171
17441
|
{ label: "Error Format", slug: "error-format" },
|
|
17172
17442
|
{ label: "Rate Limits", slug: "rate-limits" }
|
|
17173
17443
|
],
|
|
17174
17444
|
faq: [
|
|
17175
|
-
{ question: "What error codes does the Talonic API return?", answer: "
|
|
17445
|
+
{ question: "What error codes does the Talonic API return?", answer: "Errors use HTTP status codes (400\u2013503) with machine-readable codes like VALIDATION_ERROR, RATE_LIMIT_EXCEEDED, INSUFFICIENT_CREDITS, INTERNAL_ERROR, etc." },
|
|
17446
|
+
{ question: "Which errors should I retry?", answer: "Retry errors with retryable: true \u2014 typically 429 (rate limited), 500 (internal/timeout), and 503 (unavailable). Never retry 400, 401, 402, 403, 404, or 413." },
|
|
17447
|
+
{ question: "Does the API send a Retry-After header?", answer: "No. For rate limits, use X-RateLimit-Reset (ISO 8601 timestamp). For other retryable errors, use exponential backoff starting at 1 second." }
|
|
17176
17448
|
],
|
|
17177
|
-
mentions: ["error codes", "HTTP status", "
|
|
17449
|
+
mentions: ["error codes", "HTTP status", "retryable", "backoff", "RATE_LIMIT_EXCEEDED", "INSUFFICIENT_CREDITS"]
|
|
17178
17450
|
},
|
|
17179
17451
|
{
|
|
17180
17452
|
slug: "rate-limits",
|
|
@@ -17186,15 +17458,15 @@ var sections44 = [
|
|
|
17186
17458
|
{ type: "paragraph", text: "API rate limits depend on your plan tier. Limits are applied per API key on a rolling daily window (UTC midnight reset)." },
|
|
17187
17459
|
{ type: "paragraph", text: "Rate limits by plan:" },
|
|
17188
17460
|
{ type: "list", items: [
|
|
17189
|
-
"**Free** \u2014 50 extractions/day, 5/min burst,
|
|
17190
|
-
"**Pro** \u2014 2,000 extractions/day, 30/min burst,
|
|
17191
|
-
"**Enterprise** \u2014 Unlimited extractions, custom burst rate,
|
|
17461
|
+
"**Free** \u2014 50 extractions/day, 5/min burst, 20 MB max file size",
|
|
17462
|
+
"**Pro** \u2014 2,000 extractions/day, 30/min burst, 100 MB max file size",
|
|
17463
|
+
"**Enterprise** \u2014 Unlimited extractions, custom burst rate, 500 MB max file size"
|
|
17192
17464
|
] },
|
|
17193
17465
|
{ type: "paragraph", text: "Every API response includes rate limit headers:" },
|
|
17194
17466
|
{ type: "list", items: [
|
|
17195
17467
|
"`X-RateLimit-Limit` \u2014 Maximum number of requests allowed in the current window.",
|
|
17196
17468
|
"`X-RateLimit-Remaining` \u2014 Number of requests remaining in the current window.",
|
|
17197
|
-
"`X-RateLimit-Reset` \u2014
|
|
17469
|
+
"`X-RateLimit-Reset` \u2014 ISO 8601 timestamp when the rate limit window resets (midnight UTC)."
|
|
17198
17470
|
] },
|
|
17199
17471
|
{
|
|
17200
17472
|
type: "code",
|
|
@@ -17203,7 +17475,7 @@ var sections44 = [
|
|
|
17203
17475
|
code: `HTTP/1.1 200 OK
|
|
17204
17476
|
X-RateLimit-Limit: 2000
|
|
17205
17477
|
X-RateLimit-Remaining: 1847
|
|
17206
|
-
X-RateLimit-Reset:
|
|
17478
|
+
X-RateLimit-Reset: 2026-04-26T00:00:00.000Z`
|
|
17207
17479
|
},
|
|
17208
17480
|
{ type: "callout", text: "When you receive a `429` response, wait until the `X-RateLimit-Reset` timestamp before retrying. Implement exponential backoff for the best experience." }
|
|
17209
17481
|
],
|
package/dist/index.js
CHANGED
|
@@ -6378,7 +6378,9 @@ var API_NAV_SECTIONS = [
|
|
|
6378
6378
|
{ id: "introduction", label: "Introduction" },
|
|
6379
6379
|
{ id: "authentication", label: "Authentication" },
|
|
6380
6380
|
{ id: "base-url", label: "Base URL" },
|
|
6381
|
-
{ id: "quick-start", label: "Quick Start" }
|
|
6381
|
+
{ id: "quick-start", label: "Quick Start" },
|
|
6382
|
+
{ id: "pagination", label: "Pagination" },
|
|
6383
|
+
{ id: "idempotency", label: "Idempotency" }
|
|
6382
6384
|
] },
|
|
6383
6385
|
{ id: "extract", label: "Extract", children: [
|
|
6384
6386
|
{ id: "post-extract", label: "POST /v1/extract" },
|