@talonic/docs 0.13.0 → 0.15.0

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/seo.js CHANGED
@@ -4,7 +4,7 @@ var openapi_default = {
4
4
  info: {
5
5
  title: "Talonic API",
6
6
  version: "1.0.0",
7
- description: 'Structure any document into schema-validated data.\n\nThe Talonic API lets you extract structured data from documents (PDFs, images,\nDOCX, CSV, plain text), manage reusable extraction schemas, track async jobs,\nand organise documents through sources.\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header.\nAPI keys are prefixed with `tlnc_` and scoped per customer.\n\n```\nAuthorization: Bearer tlnc_live_abc123...\n```\n\n## Async Extraction Pattern\n\nSmall documents (\u22645 pages) are processed synchronously and return a `200`\nwith the extracted data immediately. Larger documents return a `202 Accepted`\nwith a `poll_url` \u2014 poll `GET /v1/documents/{id}` until `status` transitions\nto `completed`, then fetch results via `GET /v1/documents/{id}/extractions`.\n\nYou can force async processing by passing `options: {"async": true}` on\nany extraction request. Combine with webhooks for a fully event-driven flow:\nconfigure a webhook destination under Delivery and listen for the\n`extraction.complete` event.\n\n**Job status lifecycle:** `pending` \u2192 `processing` \u2192 `complete` | `failed`\n\n## Rate Limits\n\nRequests are metered per calendar day (UTC). Limits depend on your plan tier:\n\n| Tier | Extract | Platform | Ingest |\n|------------|---------|----------|--------|\n| Free | 50/day | 500/day | 50/day |\n| Pro | 2,000 | 10,000 | 2,000 |\n| Enterprise | Unlimited | Unlimited | Unlimited |\n\nEvery response includes rate-limit headers:\n- `X-RateLimit-Limit` \u2014 daily cap for the namespace\n- `X-RateLimit-Remaining` \u2014 requests left today\n- `X-RateLimit-Reset` \u2014 ISO 8601 timestamp when the window resets (midnight UTC)\n\n## Pagination\n\nList endpoints use cursor-based pagination. Pass `limit` (1\u2013100, default 20),\n`cursor` (opaque token from `pagination.next_cursor`), and `order` (`asc` or `desc`, default `desc`).\n\n## Errors\n\nAll errors return a JSON body with `error` (machine-readable code) and `message`\n(human-readable explanation). Additional fields vary by error type.\n\n| Code | Error | Description |\n|------|--------------------|------------------------------------------|\n| 400 | validation_error | Request body is malformed or invalid |\n| 401 | unauthorized | Missing or invalid API key |\n| 403 | insufficient_scope | API key lacks the required scope |\n| 404 | not_found | Resource does not exist |\n| 409 | conflict | Resource state conflict |\n| 413 | payload_too_large | File exceeds 500 MB limit |\n| 422 | extraction_failed | Document could not be processed |\n| 429 | rate_limit_exceeded| Daily rate limit reached |\n| 500 | internal_error | Unexpected server error (retryable) |\n\nEvery error response follows this envelope:\n\n```json\n{\n "statusCode": 400,\n "code": "VALIDATION_ERROR",\n "error": "Bad Request",\n "message": "name is required.",\n "retryable": false,\n "timestamp": "2026-04-25T14:30:00.000Z",\n "path": "/v1/schemas"\n}\n```\n\nThe `code` field is one of: `VALIDATION_ERROR`, `AUTH_REQUIRED`, `TOKEN_EXPIRED`,\n`INSUFFICIENT_PERMISSIONS`, `RESOURCE_NOT_FOUND`, `QUOTA_EXCEEDED`,\n`INSUFFICIENT_CREDITS`, `LLM_RATE_LIMITED`, `LLM_TIMEOUT`, `LLM_UNAVAILABLE`,\n`OCR_FAILED`, `EXTRACTION_FAILED`, `EXTRACTION_TIMEOUT`, `FILE_TOO_LARGE`,\n`DUPLICATE_RESOURCE`, `DATASPACE_RUN_FAILED`, `INTERNAL_ERROR`.\n\n## Async Extraction Flow\n\nDocuments \u22645 pages return results synchronously (`200`). Larger documents\n\u2014 or any request with `options: {"async": true}` \u2014 return `202 Accepted`.\n\n**1. Submit extraction:**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n -H "Authorization: Bearer tlnc_live_abc123" \\\n -F "file=@contract.pdf" \\\n -F \'options={"async": true}\'\n```\n\nResponse `202`:\n```json\n{\n "request_id": "req_x7y8z9a0",\n "status": "processing",\n "document": { "id": "f0e1d2c3-b4a5-9687-8765-432109876543" },\n "poll_url": "/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543"\n}\n```\n\n**2. Poll until complete:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543 \\\n -H "Authorization: Bearer tlnc_live_abc123"\n```\n\nWhile processing: `{ "status": "processing" }`\nWhen done: `{ "status": "completed" }`\n\n**3. Retrieve results:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543/extractions \\\n -H "Authorization: Bearer tlnc_live_abc123"\n```\n\n**Python polling example:**\n\n```python\nimport time, requests\n\nresp = requests.post("https://api.talonic.com/v1/extract",\n headers={"Authorization": "Bearer tlnc_live_abc123"},\n files={"file": open("contract.pdf", "rb")},\n data={"options": \'{"async": true}\'})\ndoc_id = resp.json()["document"]["id"]\n\ndelay = 2\nfor _ in range(15):\n time.sleep(delay)\n doc = requests.get(f"https://api.talonic.com/v1/documents/{doc_id}",\n headers={"Authorization": "Bearer tlnc_live_abc123"}).json()\n if doc["status"] == "completed":\n break\n delay = min(delay * 2, 30) # 2s, 4s, 8s, 16s, 30s cap\n\nextractions = requests.get(\n f"https://api.talonic.com/v1/documents/{doc_id}/extractions",\n headers={"Authorization": "Bearer tlnc_live_abc123"}).json()\nprint(extractions["data"][0]["data"])\n```\n\nRecommended polling: 2s initial, exponential backoff (2\u21924\u21928\u219216\u219230s cap),\ntimeout after 5 minutes.\n\n**Alternative \u2014 Webhooks:** Configure a delivery destination and listen for\n`document.extracted` events. See the Delivery tag.\n\n**Job status state machine:**\n`pending` \u2192 `queued` \u2192 `processing` \u2192 `complete` | `failed`\n\n## Performance\n\n| Document size | Expected latency | Max timeout |\n|---------------|------------------|-------------|\n| 1\u20135 pages | Sync, <3s | 30s |\n| 6\u201350 pages | <30s average | 5 min |\n| 50+ pages | <5 min average | 30 min |\n\n**Uptime SLA:** 99.5% (Build), 99.9% (Scale), custom (Enterprise).\n\n**Max file size:** 500 MB. JSON request bodies (schemas, jobs): 1 MB.\n\n**Idempotency:** Pass `Idempotency-Key` header on POST requests. Keys are\nvalid for 24 hours and scoped per API key. Duplicates return the cached\nresponse with `cached: true`.\n',
7
+ description: 'Structure any document into schema-validated data.\n\nThe Talonic API lets you extract structured data from documents (PDFs, images,\nDOCX, CSV, plain text), manage reusable extraction schemas, track async jobs,\nand organise documents through sources.\n\n## Quick Start\n\n**1. Get your API key**\n\nSign up at [app.talonic.com](https://app.talonic.com) \u2192 Settings \u2192 API Keys \u2192 Create key.\nKeys start with `tlnc_live_` (production) or `tlnc_test_` (sandbox).\nAll examples below use `tlnc_live_abc123` as a placeholder.\n\n**2. Extract your first document**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n -H "Authorization: Bearer tlnc_live_abc123" \\\n -F "file=@invoice.pdf" \\\n -F \'schema={"properties":{"vendor_name":{"type":"string"},"total_amount":{"type":"number"},"invoice_date":{"type":"string"}}}\'\n```\n\n**Python:**\n```python\nimport requests\nresp = requests.post("https://api.talonic.com/v1/extract",\n headers={"Authorization": "Bearer tlnc_live_abc123"},\n files={"file": open("invoice.pdf", "rb")},\n data={"schema": \'{"properties":{"vendor_name":{"type":"string"},"total_amount":{"type":"number"},"invoice_date":{"type":"string"}}}\'})\nprint(resp.json()["data"])\n```\n\n**TypeScript:**\n```typescript\nconst form = new FormData();\nform.append("file", fs.createReadStream("invoice.pdf"));\nform.append("schema", \'{"properties":{"vendor_name":{"type":"string"},"total_amount":{"type":"number"},"invoice_date":{"type":"string"}}}\');\nconst res = await fetch("https://api.talonic.com/v1/extract", {\n method: "POST",\n headers: { Authorization: "Bearer tlnc_live_abc123" },\n body: form,\n}).then(r => r.json());\nconsole.log(res.data);\n```\n\n**3. What you get back**\n\n```json\n{\n "extraction_id": "d1a2b3c4-5678-9abc-def0-1234567890ab",\n "request_id": "req_x7y8z9a0b1c2d3e4",\n "status": "complete",\n "document": {\n "id": "f0e1d2c3-b4a5-9687-8765-432109876543",\n "filename": "invoice.pdf",\n "pages": 2,\n "size_bytes": 184320,\n "type_detected": "Invoice",\n "language_detected": "en"\n },\n "data": {\n "vendor_name": "Acme GmbH",\n "total_amount": 14250.00,\n "invoice_date": "2025-03-15"\n },\n "confidence": {\n "overall": 0.96,\n "fields": {\n "vendor_name": 0.97,\n "total_amount": 0.94,\n "invoice_date": 0.99\n }\n },\n "processing": {\n "duration_ms": 1840,\n "pages_processed": 2,\n "region": "eu-west"\n },\n "links": {\n "self": "/v1/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab",\n "document": "/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543"\n }\n}\n```\n\n- **`data`** \u2014 extracted fields as key-value pairs matching your schema.\n- **`confidence.fields`** \u2014 per-field score from 0 to 1. Above 0.9 is high confidence; below 0.7 flags for review.\n- **`extraction_id`** \u2014 use this to retrieve, correct, or deliver results later.\n- Full response schema: [ExtractSyncResponse](#/components/schemas/ExtractSyncResponse)\n\n**4. Next steps**\n\n- **50+ pages?** Use async mode \u2014 see [Async Extraction Flow](#section/Async-Extraction-Flow) below.\n- **Reusable schemas** \u2014 save field definitions with `POST /v1/schemas`, then pass `schema_id` on future extractions.\n- **Receive results via webhook** \u2014 configure a delivery destination and listen for `document.extracted` events. See the [Delivery](#tag/Delivery) tag.\n\n---\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header.\nAPI keys are prefixed with `tlnc_` and scoped per customer.\n\n```\nAuthorization: Bearer tlnc_live_abc123...\n```\n\n## Async Extraction Pattern\n\nSmall documents (\u22645 pages) are processed synchronously and return a `200`\nwith the extracted data immediately. Larger documents return a `202 Accepted`\nwith a `poll_url` \u2014 poll `GET /v1/documents/{id}` until `status` transitions\nto `completed`, then fetch results via `GET /v1/documents/{id}/extractions`.\n\nYou can force async processing by passing `options: {"async": true}` on\nany extraction request. Combine with webhooks for a fully event-driven flow:\nconfigure a webhook destination under Delivery and listen for the\n`extraction.complete` event.\n\n**Job status lifecycle:** `pending` \u2192 `processing` \u2192 `complete` | `failed`\n\n## Rate Limits\n\nRequests are metered per calendar day (UTC). Limits depend on your plan tier:\n\n| Tier | Extract | Platform | Ingest |\n|------------|---------|----------|--------|\n| Free | 50/day | 500/day | 50/day |\n| Pro | 2,000 | 10,000 | 2,000 |\n| Enterprise | Unlimited | Unlimited | Unlimited |\n\nEvery response includes rate-limit headers:\n- `X-RateLimit-Limit` \u2014 daily cap for the namespace\n- `X-RateLimit-Remaining` \u2014 requests left today\n- `X-RateLimit-Reset` \u2014 ISO 8601 timestamp when the window resets (midnight UTC)\n\n## Pagination\n\nList endpoints use cursor-based pagination. Pass `limit` (1\u2013100, default 20),\n`cursor` (opaque token from `pagination.next_cursor`), and `order` (`asc` or `desc`, default `desc`).\n\n## Errors\n\nAll errors return a JSON body with `error` (machine-readable code) and `message`\n(human-readable explanation). Additional fields vary by error type.\n\n| Code | Error | Description |\n|------|--------------------|------------------------------------------|\n| 400 | validation_error | Request body is malformed or invalid |\n| 401 | unauthorized | Missing or invalid API key |\n| 403 | insufficient_scope | API key lacks the required scope |\n| 404 | not_found | Resource does not exist |\n| 409 | conflict | Resource state conflict |\n| 413 | payload_too_large | File exceeds 500 MB limit |\n| 422 | extraction_failed | Document could not be processed |\n| 429 | rate_limit_exceeded| Daily rate limit reached |\n| 500 | internal_error | Unexpected server error (retryable) |\n\nEvery error response follows this envelope:\n\n```json\n{\n "statusCode": 400,\n "code": "VALIDATION_ERROR",\n "error": "Bad Request",\n "message": "name is required.",\n "retryable": false,\n "timestamp": "2026-04-25T14:30:00.000Z",\n "path": "/v1/schemas"\n}\n```\n\nThe `code` field is one of: `VALIDATION_ERROR`, `AUTH_REQUIRED`, `TOKEN_EXPIRED`,\n`INSUFFICIENT_PERMISSIONS`, `RESOURCE_NOT_FOUND`, `QUOTA_EXCEEDED`,\n`INSUFFICIENT_CREDITS`, `LLM_RATE_LIMITED`, `LLM_TIMEOUT`, `LLM_UNAVAILABLE`,\n`OCR_FAILED`, `EXTRACTION_FAILED`, `EXTRACTION_TIMEOUT`, `FILE_TOO_LARGE`,\n`DUPLICATE_RESOURCE`, `DATASPACE_RUN_FAILED`, `INTERNAL_ERROR`.\n\n## Async Extraction Flow\n\nDocuments \u22645 pages return results synchronously (`200`). Larger documents\n\u2014 or any request with `options: {"async": true}` \u2014 return `202 Accepted`.\n\n**1. Submit extraction:**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n -H "Authorization: Bearer tlnc_live_abc123" \\\n -F "file=@contract.pdf" \\\n -F \'options={"async": true}\'\n```\n\nResponse `202`:\n```json\n{\n "request_id": "req_x7y8z9a0",\n "status": "processing",\n "document": { "id": "f0e1d2c3-b4a5-9687-8765-432109876543" },\n "poll_url": "/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543"\n}\n```\n\n**2. Poll until complete:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543 \\\n -H "Authorization: Bearer tlnc_live_abc123"\n```\n\nWhile processing: `{ "status": "processing" }`\nWhen done: `{ "status": "completed" }`\n\n**3. Retrieve results:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543/extractions \\\n -H "Authorization: Bearer tlnc_live_abc123"\n```\n\n**Python \u2014 complete async flow with exponential backoff:**\n\n```python\nimport time\nimport requests\n\nAPI_KEY = "tlnc_live_..."\nBASE = "https://api.talonic.com/v1"\nHEADERS = {"Authorization": f"Bearer {API_KEY}"}\n\n# Step 1: Submit async extraction\nresp = requests.post(f"{BASE}/extract",\n headers=HEADERS,\n files={"file": open("contract.pdf", "rb")},\n data={"options": \'{"async": true}\'})\ndoc_id = resp.json()["document"]["id"]\n\n# Step 2: Poll with exponential backoff (2s \u2192 4s \u2192 8s \u2192 16s \u2192 30s cap)\ndelay = 2\nfor _ in range(20):\n time.sleep(delay)\n doc = requests.get(f"{BASE}/documents/{doc_id}", headers=HEADERS).json()\n if doc["status"] == "completed":\n break\n if doc["status"] == "error":\n raise Exception(f"Extraction failed: {doc.get(\'error\')}")\n delay = min(delay * 2, 30)\n\n# Step 3: Retrieve extracted data\nextractions = requests.get(\n f"{BASE}/documents/{doc_id}/extractions", headers=HEADERS).json()\ndata = extractions["data"][0]["data"]\nconfidence = extractions["data"][0]["confidence"]["overall"]\nprint(f"Extracted {len(data)} fields (confidence: {confidence})")\nprint(data)\n# \u2192 {"vendor_name": "Acme Corp", "total_amount": 1250.00, ...}\n```\n\n**TypeScript \u2014 same flow:**\n\n```typescript\nconst API_KEY = "tlnc_live_...";\nconst BASE = "https://api.talonic.com/v1";\nconst headers = { Authorization: `Bearer ${API_KEY}` };\n\n// Step 1: Submit async extraction\nconst form = new FormData();\nform.append("file", fs.createReadStream("contract.pdf"));\nform.append("options", \'{"async": true}\');\nconst { document } = await fetch(`${BASE}/extract`, {\n method: "POST", headers, body: form,\n}).then((r) => r.json());\n\n// Step 2: Poll with exponential backoff\nlet delay = 2000;\nlet doc: any;\nfor (let i = 0; i < 20; i++) {\n await new Promise((r) => setTimeout(r, delay));\n doc = await fetch(`${BASE}/documents/${document.id}`, { headers }).then((r) => r.json());\n if (doc.status === "completed") break;\n if (doc.status === "error") throw new Error(`Extraction failed: ${doc.error}`);\n delay = Math.min(delay * 2, 30_000);\n}\n\n// Step 3: Retrieve extracted data\nconst { data: extractions } = await fetch(\n `${BASE}/documents/${document.id}/extractions`, { headers }\n).then((r) => r.json());\nconsole.log(extractions[0].data);\n// \u2192 { vendor_name: "Acme Corp", total_amount: 1250.00, ... }\n```\n\nRecommended polling: 2s initial, exponential backoff (2\u21924\u21928\u219216\u219230s cap),\ntimeout after 5 minutes.\n\n**Alternative \u2014 Webhooks:** Configure a delivery destination and listen for\n`document.extracted` events. See the Delivery tag.\n\n**Job status state machine:**\n`pending` \u2192 `queued` \u2192 `processing` \u2192 `complete` | `failed`\n\n## Performance\n\n| Document size | Expected latency | Max timeout |\n|---------------|------------------|-------------|\n| 1\u20135 pages | Sync, <3s | 30s |\n| 6\u201350 pages | <30s average | 5 min |\n| 50+ pages | <5 min average | 30 min |\n\n**Uptime SLA:** 99.5% (Build), 99.9% (Scale), custom (Enterprise).\n\n**Max file size:** 500 MB. JSON request bodies (schemas, jobs): 1 MB.\n\n**Idempotency:** Pass `Idempotency-Key` header on POST requests. Keys are\nvalid for 24 hours and scoped per API key. Duplicates return the cached\nresponse with `cached: true`.\n',
8
8
  contact: {
9
9
  name: "Talonic Support",
10
10
  email: "support@talonic.ai",
@@ -56,7 +56,7 @@ var openapi_default = {
56
56
  },
57
57
  {
58
58
  name: "Delivery",
59
- description: 'Outbound delivery pipeline \u2014 routing rules, delivery destinations (webhook, SFTP,\nS3, Azure Blob, Google Drive, OneDrive), bindings, filters, and the delivery\nhistory/DLQ/events log.\n\n## Webhook Contract\n\n**Event payload:**\n```json\n{\n "event": {\n "event_type": "document.extracted",\n "event_id": "42",\n "binding_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",\n "idempotency_key": "c9f3a7e1b2d4f6a8e0c2d4f6a8e0c2d4",\n "attempt": 1,\n "delivered_at": "2026-04-25T14:30:00.000Z"\n },\n "payload": { "document_id": "...", "data": { "...extracted fields..." } }\n}\n```\n\n**Event types:** `document.extracted`, `document.extraction_failed`,\n`run.dataspace.completed`, `run.dataspace.failed`, `result.dataspace.completed`,\n`result.dataspace.failed`, `run.structuring.completed`, `run.structuring.failed`,\n`run.resolution.completed`, `run.resolution.failed`, `run.extraction.completed`,\n`run.extraction.failed`, `result.flagged`, `result.approved`, `result.rejected`,\n`delivery.item.completed`, `delivery.item.failed`.\n\n**Signature verification (HMAC-SHA256):**\n\nHeader: `X-Talonic-Signature: t=1714060200000,v1=abc123...`\n\n```javascript\nconst crypto = require(\'crypto\');\nconst [tPart, vPart] = signature.split(\',\');\nconst timestamp = tPart.split(\'=\')[1];\nconst received = vPart.split(\'=\')[1];\nconst expected = crypto.createHmac(\'sha256\', signingSecret)\n .update(timestamp + \'.\' + rawBody).digest(\'hex\');\nconst valid = crypto.timingSafeEqual(\n Buffer.from(received), Buffer.from(expected));\n```\n\n**Retry policy:** Up to 7 attempts \u2014 0s, 30s, 2m, 8m, 30m, 2h, 8h (~10.5h total).\nHTTP 429/5xx are retryable. HTTP 4xx (except 408) goes to DLQ immediately.\nReplay failed deliveries via `POST /v1/delivery/dlq/{id}/replay`.\n'
59
+ description: 'Outbound delivery pipeline \u2014 routing rules, delivery destinations (webhook, SFTP,\nS3, Azure Blob, Google Drive, OneDrive), bindings, filters, and the delivery\nhistory/DLQ/events log.\n\n## Webhook Contract\n\n**Event payload:**\n```json\n{\n "event": {\n "event_type": "document.extracted",\n "event_id": "42",\n "binding_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",\n "idempotency_key": "c9f3a7e1b2d4f6a8e0c2d4f6a8e0c2d4",\n "attempt": 1,\n "delivered_at": "2026-04-25T14:30:00.000Z"\n },\n "payload": { "document_id": "...", "data": { "...extracted fields..." } }\n}\n```\n\n**Event types:** `document.extracted`, `document.extraction_failed`,\n`run.dataspace.completed`, `run.dataspace.failed`, `result.dataspace.completed`,\n`result.dataspace.failed`, `run.structuring.completed`, `run.structuring.failed`,\n`run.resolution.completed`, `run.resolution.failed`, `run.extraction.completed`,\n`run.extraction.failed`, `result.flagged`, `result.approved`, `result.rejected`,\n`delivery.item.completed`, `delivery.item.failed`.\n\n**Signature verification (HMAC-SHA256):**\n\nHeader: `X-Talonic-Signature: t=1714060200000,v1=abc123...`\n\n```javascript\nconst crypto = require(\'crypto\');\nconst [tPart, vPart] = signature.split(\',\');\nconst timestamp = tPart.split(\'=\')[1];\nconst received = vPart.split(\'=\')[1];\nconst expected = crypto.createHmac(\'sha256\', signingSecret)\n .update(timestamp + \'.\' + rawBody).digest(\'hex\');\nconst valid = crypto.timingSafeEqual(\n Buffer.from(received), Buffer.from(expected));\n```\n\n**Retry policy:** Up to 7 attempts \u2014 0s, 30s, 2m, 8m, 30m, 2h, 8h (~10.5h total).\nHTTP 429/5xx are retryable. HTTP 4xx (except 408) goes to DLQ immediately.\n\n**Dead-letter queue recovery:** When all retries are exhausted, the delivery\nlands in the DLQ. List failed deliveries with `GET /v1/delivery/dlq`\n(filterable by `binding_id` and `error_code`). Inspect a single entry with\n`GET /v1/delivery/dlq/{id}`. Replay with `POST /v1/delivery/dlq/{id}/replay`\n\u2014 this deletes the DLQ entry, re-signs the payload with the current\nsigning secret, resets the retry counter to attempt 1, and re-enqueues\nthe delivery through the full backoff ladder.\n'
60
60
  },
61
61
  {
62
62
  name: "Intelligence",
package/openapi.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "info": {
4
4
  "title": "Talonic API",
5
5
  "version": "1.0.0",
6
- "description": "Structure any document into schema-validated data.\n\nThe Talonic API lets you extract structured data from documents (PDFs, images,\nDOCX, CSV, plain text), manage reusable extraction schemas, track async jobs,\nand organise documents through sources.\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header.\nAPI keys are prefixed with `tlnc_` and scoped per customer.\n\n```\nAuthorization: Bearer tlnc_live_abc123...\n```\n\n## Async Extraction Pattern\n\nSmall documents (≤5 pages) are processed synchronously and return a `200`\nwith the extracted data immediately. Larger documents return a `202 Accepted`\nwith a `poll_url` — poll `GET /v1/documents/{id}` until `status` transitions\nto `completed`, then fetch results via `GET /v1/documents/{id}/extractions`.\n\nYou can force async processing by passing `options: {\"async\": true}` on\nany extraction request. Combine with webhooks for a fully event-driven flow:\nconfigure a webhook destination under Delivery and listen for the\n`extraction.complete` event.\n\n**Job status lifecycle:** `pending` → `processing` → `complete` | `failed`\n\n## Rate Limits\n\nRequests are metered per calendar day (UTC). Limits depend on your plan tier:\n\n| Tier | Extract | Platform | Ingest |\n|------------|---------|----------|--------|\n| Free | 50/day | 500/day | 50/day |\n| Pro | 2,000 | 10,000 | 2,000 |\n| Enterprise | Unlimited | Unlimited | Unlimited |\n\nEvery response includes rate-limit headers:\n- `X-RateLimit-Limit` — daily cap for the namespace\n- `X-RateLimit-Remaining` — requests left today\n- `X-RateLimit-Reset` — ISO 8601 timestamp when the window resets (midnight UTC)\n\n## Pagination\n\nList endpoints use cursor-based pagination. Pass `limit` (1–100, default 20),\n`cursor` (opaque token from `pagination.next_cursor`), and `order` (`asc` or `desc`, default `desc`).\n\n## Errors\n\nAll errors return a JSON body with `error` (machine-readable code) and `message`\n(human-readable explanation). Additional fields vary by error type.\n\n| Code | Error | Description |\n|------|--------------------|------------------------------------------|\n| 400 | validation_error | Request body is malformed or invalid |\n| 401 | unauthorized | Missing or invalid API key |\n| 403 | insufficient_scope | API key lacks the required scope |\n| 404 | not_found | Resource does not exist |\n| 409 | conflict | Resource state conflict |\n| 413 | payload_too_large | File exceeds 500 MB limit |\n| 422 | extraction_failed | Document could not be processed |\n| 429 | rate_limit_exceeded| Daily rate limit reached |\n| 500 | internal_error | Unexpected server error (retryable) |\n\nEvery error response follows this envelope:\n\n```json\n{\n \"statusCode\": 400,\n \"code\": \"VALIDATION_ERROR\",\n \"error\": \"Bad Request\",\n \"message\": \"name is required.\",\n \"retryable\": false,\n \"timestamp\": \"2026-04-25T14:30:00.000Z\",\n \"path\": \"/v1/schemas\"\n}\n```\n\nThe `code` field is one of: `VALIDATION_ERROR`, `AUTH_REQUIRED`, `TOKEN_EXPIRED`,\n`INSUFFICIENT_PERMISSIONS`, `RESOURCE_NOT_FOUND`, `QUOTA_EXCEEDED`,\n`INSUFFICIENT_CREDITS`, `LLM_RATE_LIMITED`, `LLM_TIMEOUT`, `LLM_UNAVAILABLE`,\n`OCR_FAILED`, `EXTRACTION_FAILED`, `EXTRACTION_TIMEOUT`, `FILE_TOO_LARGE`,\n`DUPLICATE_RESOURCE`, `DATASPACE_RUN_FAILED`, `INTERNAL_ERROR`.\n\n## Async Extraction Flow\n\nDocuments ≤5 pages return results synchronously (`200`). Larger documents\n— or any request with `options: {\"async\": true}` — return `202 Accepted`.\n\n**1. Submit extraction:**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n -H \"Authorization: Bearer tlnc_live_abc123\" \\\n -F \"file=@contract.pdf\" \\\n -F 'options={\"async\": true}'\n```\n\nResponse `202`:\n```json\n{\n \"request_id\": \"req_x7y8z9a0\",\n \"status\": \"processing\",\n \"document\": { \"id\": \"f0e1d2c3-b4a5-9687-8765-432109876543\" },\n \"poll_url\": \"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543\"\n}\n```\n\n**2. Poll until complete:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543 \\\n -H \"Authorization: Bearer tlnc_live_abc123\"\n```\n\nWhile processing: `{ \"status\": \"processing\" }`\nWhen done: `{ \"status\": \"completed\" }`\n\n**3. Retrieve results:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543/extractions \\\n -H \"Authorization: Bearer tlnc_live_abc123\"\n```\n\n**Python polling example:**\n\n```python\nimport time, requests\n\nresp = requests.post(\"https://api.talonic.com/v1/extract\",\n headers={\"Authorization\": \"Bearer tlnc_live_abc123\"},\n files={\"file\": open(\"contract.pdf\", \"rb\")},\n data={\"options\": '{\"async\": true}'})\ndoc_id = resp.json()[\"document\"][\"id\"]\n\ndelay = 2\nfor _ in range(15):\n time.sleep(delay)\n doc = requests.get(f\"https://api.talonic.com/v1/documents/{doc_id}\",\n headers={\"Authorization\": \"Bearer tlnc_live_abc123\"}).json()\n if doc[\"status\"] == \"completed\":\n break\n delay = min(delay * 2, 30) # 2s, 4s, 8s, 16s, 30s cap\n\nextractions = requests.get(\n f\"https://api.talonic.com/v1/documents/{doc_id}/extractions\",\n headers={\"Authorization\": \"Bearer tlnc_live_abc123\"}).json()\nprint(extractions[\"data\"][0][\"data\"])\n```\n\nRecommended polling: 2s initial, exponential backoff (2→4→8→16→30s cap),\ntimeout after 5 minutes.\n\n**Alternative — Webhooks:** Configure a delivery destination and listen for\n`document.extracted` events. See the Delivery tag.\n\n**Job status state machine:**\n`pending` → `queued` → `processing` → `complete` | `failed`\n\n## Performance\n\n| Document size | Expected latency | Max timeout |\n|---------------|------------------|-------------|\n| 1–5 pages | Sync, <3s | 30s |\n| 6–50 pages | <30s average | 5 min |\n| 50+ pages | <5 min average | 30 min |\n\n**Uptime SLA:** 99.5% (Build), 99.9% (Scale), custom (Enterprise).\n\n**Max file size:** 500 MB. JSON request bodies (schemas, jobs): 1 MB.\n\n**Idempotency:** Pass `Idempotency-Key` header on POST requests. Keys are\nvalid for 24 hours and scoped per API key. Duplicates return the cached\nresponse with `cached: true`.\n",
6
+ "description": "Structure any document into schema-validated data.\n\nThe Talonic API lets you extract structured data from documents (PDFs, images,\nDOCX, CSV, plain text), manage reusable extraction schemas, track async jobs,\nand organise documents through sources.\n\n## Quick Start\n\n**1. Get your API key**\n\nSign up at [app.talonic.com](https://app.talonic.com) → Settings → API Keys → Create key.\nKeys start with `tlnc_live_` (production) or `tlnc_test_` (sandbox).\nAll examples below use `tlnc_live_abc123` as a placeholder.\n\n**2. Extract your first document**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n -H \"Authorization: Bearer tlnc_live_abc123\" \\\n -F \"file=@invoice.pdf\" \\\n -F 'schema={\"properties\":{\"vendor_name\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"},\"invoice_date\":{\"type\":\"string\"}}}'\n```\n\n**Python:**\n```python\nimport requests\nresp = requests.post(\"https://api.talonic.com/v1/extract\",\n headers={\"Authorization\": \"Bearer tlnc_live_abc123\"},\n files={\"file\": open(\"invoice.pdf\", \"rb\")},\n data={\"schema\": '{\"properties\":{\"vendor_name\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"},\"invoice_date\":{\"type\":\"string\"}}}'})\nprint(resp.json()[\"data\"])\n```\n\n**TypeScript:**\n```typescript\nconst form = new FormData();\nform.append(\"file\", fs.createReadStream(\"invoice.pdf\"));\nform.append(\"schema\", '{\"properties\":{\"vendor_name\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"},\"invoice_date\":{\"type\":\"string\"}}}');\nconst res = await fetch(\"https://api.talonic.com/v1/extract\", {\n method: \"POST\",\n headers: { Authorization: \"Bearer tlnc_live_abc123\" },\n body: form,\n}).then(r => r.json());\nconsole.log(res.data);\n```\n\n**3. What you get back**\n\n```json\n{\n \"extraction_id\": \"d1a2b3c4-5678-9abc-def0-1234567890ab\",\n \"request_id\": \"req_x7y8z9a0b1c2d3e4\",\n \"status\": \"complete\",\n \"document\": {\n \"id\": \"f0e1d2c3-b4a5-9687-8765-432109876543\",\n \"filename\": \"invoice.pdf\",\n \"pages\": 2,\n \"size_bytes\": 184320,\n \"type_detected\": \"Invoice\",\n \"language_detected\": \"en\"\n },\n \"data\": {\n \"vendor_name\": \"Acme GmbH\",\n \"total_amount\": 14250.00,\n \"invoice_date\": \"2025-03-15\"\n },\n \"confidence\": {\n \"overall\": 0.96,\n \"fields\": {\n \"vendor_name\": 0.97,\n \"total_amount\": 0.94,\n \"invoice_date\": 0.99\n }\n },\n \"processing\": {\n \"duration_ms\": 1840,\n \"pages_processed\": 2,\n \"region\": \"eu-west\"\n },\n \"links\": {\n \"self\": \"/v1/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab\",\n \"document\": \"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543\"\n }\n}\n```\n\n- **`data`** — extracted fields as key-value pairs matching your schema.\n- **`confidence.fields`** — per-field score from 0 to 1. Above 0.9 is high confidence; below 0.7 flags for review.\n- **`extraction_id`** — use this to retrieve, correct, or deliver results later.\n- Full response schema: [ExtractSyncResponse](#/components/schemas/ExtractSyncResponse)\n\n**4. Next steps**\n\n- **50+ pages?** Use async mode — see [Async Extraction Flow](#section/Async-Extraction-Flow) below.\n- **Reusable schemas** — save field definitions with `POST /v1/schemas`, then pass `schema_id` on future extractions.\n- **Receive results via webhook** — configure a delivery destination and listen for `document.extracted` events. See the [Delivery](#tag/Delivery) tag.\n\n---\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header.\nAPI keys are prefixed with `tlnc_` and scoped per customer.\n\n```\nAuthorization: Bearer tlnc_live_abc123...\n```\n\n## Async Extraction Pattern\n\nSmall documents (≤5 pages) are processed synchronously and return a `200`\nwith the extracted data immediately. Larger documents return a `202 Accepted`\nwith a `poll_url` — poll `GET /v1/documents/{id}` until `status` transitions\nto `completed`, then fetch results via `GET /v1/documents/{id}/extractions`.\n\nYou can force async processing by passing `options: {\"async\": true}` on\nany extraction request. Combine with webhooks for a fully event-driven flow:\nconfigure a webhook destination under Delivery and listen for the\n`extraction.complete` event.\n\n**Job status lifecycle:** `pending` → `processing` → `complete` | `failed`\n\n## Rate Limits\n\nRequests are metered per calendar day (UTC). Limits depend on your plan tier:\n\n| Tier | Extract | Platform | Ingest |\n|------------|---------|----------|--------|\n| Free | 50/day | 500/day | 50/day |\n| Pro | 2,000 | 10,000 | 2,000 |\n| Enterprise | Unlimited | Unlimited | Unlimited |\n\nEvery response includes rate-limit headers:\n- `X-RateLimit-Limit` — daily cap for the namespace\n- `X-RateLimit-Remaining` — requests left today\n- `X-RateLimit-Reset` — ISO 8601 timestamp when the window resets (midnight UTC)\n\n## Pagination\n\nList endpoints use cursor-based pagination. Pass `limit` (1–100, default 20),\n`cursor` (opaque token from `pagination.next_cursor`), and `order` (`asc` or `desc`, default `desc`).\n\n## Errors\n\nAll errors return a JSON body with `error` (machine-readable code) and `message`\n(human-readable explanation). Additional fields vary by error type.\n\n| Code | Error | Description |\n|------|--------------------|------------------------------------------|\n| 400 | validation_error | Request body is malformed or invalid |\n| 401 | unauthorized | Missing or invalid API key |\n| 403 | insufficient_scope | API key lacks the required scope |\n| 404 | not_found | Resource does not exist |\n| 409 | conflict | Resource state conflict |\n| 413 | payload_too_large | File exceeds 500 MB limit |\n| 422 | extraction_failed | Document could not be processed |\n| 429 | rate_limit_exceeded| Daily rate limit reached |\n| 500 | internal_error | Unexpected server error (retryable) |\n\nEvery error response follows this envelope:\n\n```json\n{\n \"statusCode\": 400,\n \"code\": \"VALIDATION_ERROR\",\n \"error\": \"Bad Request\",\n \"message\": \"name is required.\",\n \"retryable\": false,\n \"timestamp\": \"2026-04-25T14:30:00.000Z\",\n \"path\": \"/v1/schemas\"\n}\n```\n\nThe `code` field is one of: `VALIDATION_ERROR`, `AUTH_REQUIRED`, `TOKEN_EXPIRED`,\n`INSUFFICIENT_PERMISSIONS`, `RESOURCE_NOT_FOUND`, `QUOTA_EXCEEDED`,\n`INSUFFICIENT_CREDITS`, `LLM_RATE_LIMITED`, `LLM_TIMEOUT`, `LLM_UNAVAILABLE`,\n`OCR_FAILED`, `EXTRACTION_FAILED`, `EXTRACTION_TIMEOUT`, `FILE_TOO_LARGE`,\n`DUPLICATE_RESOURCE`, `DATASPACE_RUN_FAILED`, `INTERNAL_ERROR`.\n\n## Async Extraction Flow\n\nDocuments ≤5 pages return results synchronously (`200`). Larger documents\n— or any request with `options: {\"async\": true}` — return `202 Accepted`.\n\n**1. Submit extraction:**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n -H \"Authorization: Bearer tlnc_live_abc123\" \\\n -F \"file=@contract.pdf\" \\\n -F 'options={\"async\": true}'\n```\n\nResponse `202`:\n```json\n{\n \"request_id\": \"req_x7y8z9a0\",\n \"status\": \"processing\",\n \"document\": { \"id\": \"f0e1d2c3-b4a5-9687-8765-432109876543\" },\n \"poll_url\": \"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543\"\n}\n```\n\n**2. Poll until complete:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543 \\\n -H \"Authorization: Bearer tlnc_live_abc123\"\n```\n\nWhile processing: `{ \"status\": \"processing\" }`\nWhen done: `{ \"status\": \"completed\" }`\n\n**3. Retrieve results:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543/extractions \\\n -H \"Authorization: Bearer tlnc_live_abc123\"\n```\n\n**Python — complete async flow with exponential backoff:**\n\n```python\nimport time\nimport requests\n\nAPI_KEY = \"tlnc_live_...\"\nBASE = \"https://api.talonic.com/v1\"\nHEADERS = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\n# Step 1: Submit async extraction\nresp = requests.post(f\"{BASE}/extract\",\n headers=HEADERS,\n files={\"file\": open(\"contract.pdf\", \"rb\")},\n data={\"options\": '{\"async\": true}'})\ndoc_id = resp.json()[\"document\"][\"id\"]\n\n# Step 2: Poll with exponential backoff (2s → 4s → 8s → 16s → 30s cap)\ndelay = 2\nfor _ in range(20):\n time.sleep(delay)\n doc = requests.get(f\"{BASE}/documents/{doc_id}\", headers=HEADERS).json()\n if doc[\"status\"] == \"completed\":\n break\n if doc[\"status\"] == \"error\":\n raise Exception(f\"Extraction failed: {doc.get('error')}\")\n delay = min(delay * 2, 30)\n\n# Step 3: Retrieve extracted data\nextractions = requests.get(\n f\"{BASE}/documents/{doc_id}/extractions\", headers=HEADERS).json()\ndata = extractions[\"data\"][0][\"data\"]\nconfidence = extractions[\"data\"][0][\"confidence\"][\"overall\"]\nprint(f\"Extracted {len(data)} fields (confidence: {confidence})\")\nprint(data)\n# → {\"vendor_name\": \"Acme Corp\", \"total_amount\": 1250.00, ...}\n```\n\n**TypeScript — same flow:**\n\n```typescript\nconst API_KEY = \"tlnc_live_...\";\nconst BASE = \"https://api.talonic.com/v1\";\nconst headers = { Authorization: `Bearer ${API_KEY}` };\n\n// Step 1: Submit async extraction\nconst form = new FormData();\nform.append(\"file\", fs.createReadStream(\"contract.pdf\"));\nform.append(\"options\", '{\"async\": true}');\nconst { document } = await fetch(`${BASE}/extract`, {\n method: \"POST\", headers, body: form,\n}).then((r) => r.json());\n\n// Step 2: Poll with exponential backoff\nlet delay = 2000;\nlet doc: any;\nfor (let i = 0; i < 20; i++) {\n await new Promise((r) => setTimeout(r, delay));\n doc = await fetch(`${BASE}/documents/${document.id}`, { headers }).then((r) => r.json());\n if (doc.status === \"completed\") break;\n if (doc.status === \"error\") throw new Error(`Extraction failed: ${doc.error}`);\n delay = Math.min(delay * 2, 30_000);\n}\n\n// Step 3: Retrieve extracted data\nconst { data: extractions } = await fetch(\n `${BASE}/documents/${document.id}/extractions`, { headers }\n).then((r) => r.json());\nconsole.log(extractions[0].data);\n// → { vendor_name: \"Acme Corp\", total_amount: 1250.00, ... }\n```\n\nRecommended polling: 2s initial, exponential backoff (2→4→8→16→30s cap),\ntimeout after 5 minutes.\n\n**Alternative — Webhooks:** Configure a delivery destination and listen for\n`document.extracted` events. See the Delivery tag.\n\n**Job status state machine:**\n`pending` → `queued` → `processing` → `complete` | `failed`\n\n## Performance\n\n| Document size | Expected latency | Max timeout |\n|---------------|------------------|-------------|\n| 1–5 pages | Sync, <3s | 30s |\n| 6–50 pages | <30s average | 5 min |\n| 50+ pages | <5 min average | 30 min |\n\n**Uptime SLA:** 99.5% (Build), 99.9% (Scale), custom (Enterprise).\n\n**Max file size:** 500 MB. JSON request bodies (schemas, jobs): 1 MB.\n\n**Idempotency:** Pass `Idempotency-Key` header on POST requests. Keys are\nvalid for 24 hours and scoped per API key. Duplicates return the cached\nresponse with `cached: true`.\n",
7
7
  "contact": {
8
8
  "name": "Talonic Support",
9
9
  "email": "support@talonic.ai",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  {
57
57
  "name": "Delivery",
58
- "description": "Outbound delivery pipeline — routing rules, delivery destinations (webhook, SFTP,\nS3, Azure Blob, Google Drive, OneDrive), bindings, filters, and the delivery\nhistory/DLQ/events log.\n\n## Webhook Contract\n\n**Event payload:**\n```json\n{\n \"event\": {\n \"event_type\": \"document.extracted\",\n \"event_id\": \"42\",\n \"binding_id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"idempotency_key\": \"c9f3a7e1b2d4f6a8e0c2d4f6a8e0c2d4\",\n \"attempt\": 1,\n \"delivered_at\": \"2026-04-25T14:30:00.000Z\"\n },\n \"payload\": { \"document_id\": \"...\", \"data\": { \"...extracted fields...\" } }\n}\n```\n\n**Event types:** `document.extracted`, `document.extraction_failed`,\n`run.dataspace.completed`, `run.dataspace.failed`, `result.dataspace.completed`,\n`result.dataspace.failed`, `run.structuring.completed`, `run.structuring.failed`,\n`run.resolution.completed`, `run.resolution.failed`, `run.extraction.completed`,\n`run.extraction.failed`, `result.flagged`, `result.approved`, `result.rejected`,\n`delivery.item.completed`, `delivery.item.failed`.\n\n**Signature verification (HMAC-SHA256):**\n\nHeader: `X-Talonic-Signature: t=1714060200000,v1=abc123...`\n\n```javascript\nconst crypto = require('crypto');\nconst [tPart, vPart] = signature.split(',');\nconst timestamp = tPart.split('=')[1];\nconst received = vPart.split('=')[1];\nconst expected = crypto.createHmac('sha256', signingSecret)\n .update(timestamp + '.' + rawBody).digest('hex');\nconst valid = crypto.timingSafeEqual(\n Buffer.from(received), Buffer.from(expected));\n```\n\n**Retry policy:** Up to 7 attempts — 0s, 30s, 2m, 8m, 30m, 2h, 8h (~10.5h total).\nHTTP 429/5xx are retryable. HTTP 4xx (except 408) goes to DLQ immediately.\nReplay failed deliveries via `POST /v1/delivery/dlq/{id}/replay`.\n"
58
+ "description": "Outbound delivery pipeline — routing rules, delivery destinations (webhook, SFTP,\nS3, Azure Blob, Google Drive, OneDrive), bindings, filters, and the delivery\nhistory/DLQ/events log.\n\n## Webhook Contract\n\n**Event payload:**\n```json\n{\n \"event\": {\n \"event_type\": \"document.extracted\",\n \"event_id\": \"42\",\n \"binding_id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"idempotency_key\": \"c9f3a7e1b2d4f6a8e0c2d4f6a8e0c2d4\",\n \"attempt\": 1,\n \"delivered_at\": \"2026-04-25T14:30:00.000Z\"\n },\n \"payload\": { \"document_id\": \"...\", \"data\": { \"...extracted fields...\" } }\n}\n```\n\n**Event types:** `document.extracted`, `document.extraction_failed`,\n`run.dataspace.completed`, `run.dataspace.failed`, `result.dataspace.completed`,\n`result.dataspace.failed`, `run.structuring.completed`, `run.structuring.failed`,\n`run.resolution.completed`, `run.resolution.failed`, `run.extraction.completed`,\n`run.extraction.failed`, `result.flagged`, `result.approved`, `result.rejected`,\n`delivery.item.completed`, `delivery.item.failed`.\n\n**Signature verification (HMAC-SHA256):**\n\nHeader: `X-Talonic-Signature: t=1714060200000,v1=abc123...`\n\n```javascript\nconst crypto = require('crypto');\nconst [tPart, vPart] = signature.split(',');\nconst timestamp = tPart.split('=')[1];\nconst received = vPart.split('=')[1];\nconst expected = crypto.createHmac('sha256', signingSecret)\n .update(timestamp + '.' + rawBody).digest('hex');\nconst valid = crypto.timingSafeEqual(\n Buffer.from(received), Buffer.from(expected));\n```\n\n**Retry policy:** Up to 7 attempts — 0s, 30s, 2m, 8m, 30m, 2h, 8h (~10.5h total).\nHTTP 429/5xx are retryable. HTTP 4xx (except 408) goes to DLQ immediately.\n\n**Dead-letter queue recovery:** When all retries are exhausted, the delivery\nlands in the DLQ. List failed deliveries with `GET /v1/delivery/dlq`\n(filterable by `binding_id` and `error_code`). Inspect a single entry with\n`GET /v1/delivery/dlq/{id}`. Replay with `POST /v1/delivery/dlq/{id}/replay`\n— this deletes the DLQ entry, re-signs the payload with the current\nsigning secret, resets the retry counter to attempt 1, and re-enqueues\nthe delivery through the full backoff ladder.\n"
59
59
  },
60
60
  {
61
61
  "name": "Intelligence",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talonic/docs",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "Talonic documentation components — API Reference & Platform Guide",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -1,45 +0,0 @@
1
- /**
2
- * Tailwind CSS preset for @talonic/docs consumers.
3
- * Adds the Void design system color tokens and font families
4
- * so doc components render correctly in any host app.
5
- */
6
- declare const voidDocsPreset: {
7
- darkMode: "class";
8
- theme: {
9
- extend: {
10
- colors: {
11
- 'void-bg': string;
12
- 'void-bg-elevated': string;
13
- 'void-surface': string;
14
- 'void-surface-2': string;
15
- 'void-surface-3': string;
16
- 'void-border': string;
17
- 'void-border-hover': string;
18
- 'void-text-primary': string;
19
- 'void-text-secondary': string;
20
- 'void-text-muted': string;
21
- 'void-text-tertiary': string;
22
- 'void-accent': string;
23
- 'void-accent-hover': string;
24
- 'void-accent-dim': string;
25
- 'void-accent-tint': string;
26
- 'void-danger': string;
27
- 'void-danger-solid': string;
28
- 'void-divider': string;
29
- 'void-warning': string;
30
- 'void-warning-dim': string;
31
- 'void-tier-1': string;
32
- 'void-tier-2': string;
33
- 'void-tier-3': string;
34
- };
35
- fontFamily: {
36
- space: string[];
37
- body: string[];
38
- mono: string[];
39
- };
40
- };
41
- };
42
- plugins: never[];
43
- };
44
-
45
- export { voidDocsPreset as default };
@@ -1,45 +0,0 @@
1
- /**
2
- * Tailwind CSS preset for @talonic/docs consumers.
3
- * Adds the Void design system color tokens and font families
4
- * so doc components render correctly in any host app.
5
- */
6
- declare const voidDocsPreset: {
7
- darkMode: "class";
8
- theme: {
9
- extend: {
10
- colors: {
11
- 'void-bg': string;
12
- 'void-bg-elevated': string;
13
- 'void-surface': string;
14
- 'void-surface-2': string;
15
- 'void-surface-3': string;
16
- 'void-border': string;
17
- 'void-border-hover': string;
18
- 'void-text-primary': string;
19
- 'void-text-secondary': string;
20
- 'void-text-muted': string;
21
- 'void-text-tertiary': string;
22
- 'void-accent': string;
23
- 'void-accent-hover': string;
24
- 'void-accent-dim': string;
25
- 'void-accent-tint': string;
26
- 'void-danger': string;
27
- 'void-danger-solid': string;
28
- 'void-divider': string;
29
- 'void-warning': string;
30
- 'void-warning-dim': string;
31
- 'void-tier-1': string;
32
- 'void-tier-2': string;
33
- 'void-tier-3': string;
34
- };
35
- fontFamily: {
36
- space: string[];
37
- body: string[];
38
- mono: string[];
39
- };
40
- };
41
- };
42
- plugins: never[];
43
- };
44
-
45
- export { voidDocsPreset as default };