{
	"openapi": "3.1.0",
	"info": {
		"title": "Datanem API",
		"summary": "Turn PDFs, scans and photos of documents into structured tables and databases.",
		"description": "Submit invoices, CVs, receipts, delivery notes, bank statements or any other repeating document type and get back typed columns and rows, or a runnable SQL schema. Extraction runs in the background: POST /v1/extract returns a job id straight away, then poll the job until it is complete.\n\nAI agents should prefer the MCP server at https://datanem.com/mcp, which is included on every plan and needs no API key.",
		"version": "1.0.0",
		"contact": { "name": "Datanem", "email": "hello@datanem.com", "url": "https://datanem.com" },
		"termsOfService": "https://datanem.com/terms",
		"license": { "name": "Proprietary", "url": "https://datanem.com/terms" }
	},
	"servers": [{ "url": "https://datanem.com", "description": "Production" }],
	"externalDocs": { "description": "API keys and usage", "url": "https://datanem.com/app/api" },
	"security": [{ "bearerAuth": [] }],
	"tags": [
		{ "name": "Templates", "description": "Built-in document types and saved column designs." },
		{ "name": "Extraction", "description": "Submitting documents and reading the results." }
	],
	"paths": {
		"/v1/templates": {
			"get": {
				"tags": ["Templates"],
				"operationId": "listTemplates",
				"summary": "List document types and saved designs",
				"description": "The built-in templates plus any column designs saved on this account. Pass an id back as templateId or schemaId. Omit both and the columns are inferred from the documents themselves.",
				"responses": {
					"200": {
						"description": "Templates and saved designs.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"templates": { "type": "array", "items": { "$ref": "#/components/schemas/NamedId" } },
										"schemas": { "type": "array", "items": { "$ref": "#/components/schemas/NamedId" } }
									}
								}
							}
						}
					},
					"401": { "$ref": "#/components/responses/Unauthorized" },
					"402": { "$ref": "#/components/responses/PaymentRequired" }
				}
			}
		},
		"/v1/extract": {
			"post": {
				"tags": ["Extraction"],
				"operationId": "extract",
				"summary": "Submit documents and start extraction",
				"description": "Upload and start in one call. Accepts PDF, DOCX, TXT, JPEG and PNG, including scanned and photographed pages with no selectable text. Returns immediately with a job id; extraction continues in the background. Each document counts against the account's allowance, so do not resubmit to retry.",
				"requestBody": {
					"required": true,
					"content": {
						"multipart/form-data": {
							"schema": {
								"type": "object",
								"required": ["file"],
								"properties": {
									"file": {
										"type": "array",
										"items": { "type": "string", "format": "binary" },
										"description": "One or more documents. Repeat the field for a batch."
									},
									"templateId": { "type": "string", "description": "A built-in template id from /v1/templates." },
									"schemaId": { "type": "string", "description": "A saved design id from /v1/templates." }
								}
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Accepted. Extraction is running.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"id": { "type": "string" },
										"status": { "type": "string", "const": "processing" },
										"documents": { "type": "integer" }
									}
								}
							}
						}
					},
					"400": { "$ref": "#/components/responses/BadRequest" },
					"401": { "$ref": "#/components/responses/Unauthorized" },
					"402": { "$ref": "#/components/responses/PaymentRequired" },
					"429": { "$ref": "#/components/responses/RateLimited" }
				}
			}
		},
		"/v1/jobs": {
			"get": {
				"tags": ["Extraction"],
				"operationId": "listJobs",
				"summary": "List recent jobs",
				"responses": {
					"200": { "description": "Recent jobs, newest first." },
					"401": { "$ref": "#/components/responses/Unauthorized" }
				}
			}
		},
		"/v1/jobs/{jobId}": {
			"parameters": [{ "$ref": "#/components/parameters/JobId" }],
			"get": {
				"tags": ["Extraction"],
				"operationId": "getJob",
				"summary": "Check whether extraction has finished",
				"description": "Poll this until status is completed, partial or failed before reading results.",
				"responses": {
					"200": {
						"description": "Job status and per-document progress.",
						"content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobStatus" } } }
					},
					"401": { "$ref": "#/components/responses/Unauthorized" },
					"404": { "$ref": "#/components/responses/NotFound" }
				}
			},
			"delete": {
				"tags": ["Extraction"],
				"operationId": "deleteJob",
				"summary": "Delete a job and its documents",
				"responses": {
					"200": { "description": "Deleted." },
					"401": { "$ref": "#/components/responses/Unauthorized" },
					"404": { "$ref": "#/components/responses/NotFound" }
				}
			}
		},
		"/v1/jobs/{jobId}/results": {
			"parameters": [{ "$ref": "#/components/parameters/JobId" }],
			"get": {
				"tags": ["Extraction"],
				"operationId": "getResults",
				"summary": "Read the extracted data as JSON",
				"parameters": [
					{
						"name": "shape",
						"in": "query",
						"schema": { "type": "string", "enum": ["flat", "grouped"], "default": "grouped" },
						"description": "flat puts each document on one row. grouped splits repeating sections such as invoice line items into their own tables."
					}
				],
				"responses": {
					"200": {
						"description": "Tables of columns and rows.",
						"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Results" } } }
					},
					"401": { "$ref": "#/components/responses/Unauthorized" },
					"404": { "$ref": "#/components/responses/NotFound" }
				}
			}
		},
		"/v1/jobs/{jobId}/export": {
			"parameters": [{ "$ref": "#/components/parameters/JobId" }],
			"get": {
				"tags": ["Extraction"],
				"operationId": "exportJob",
				"summary": "Download the job as a spreadsheet, CSV or SQL",
				"description": "sql returns CREATE TABLE statements with primary keys, foreign keys and indexes plus the inserts, ready to run in SQLite, PostgreSQL or DuckDB.",
				"parameters": [
					{
						"name": "format",
						"in": "query",
						"schema": { "type": "string", "enum": ["xlsx", "csv", "sql"], "default": "xlsx" }
					},
					{
						"name": "shape",
						"in": "query",
						"schema": { "type": "string", "enum": ["flat", "grouped"] }
					}
				],
				"responses": {
					"200": {
						"description": "The exported file.",
						"content": {
							"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { "schema": { "type": "string", "format": "binary" } },
							"text/csv": { "schema": { "type": "string" } },
							"application/sql": { "schema": { "type": "string" } }
						}
					},
					"401": { "$ref": "#/components/responses/Unauthorized" },
					"404": { "$ref": "#/components/responses/NotFound" }
				}
			}
		}
	},
	"components": {
		"securitySchemes": {
			"bearerAuth": {
				"type": "http",
				"scheme": "bearer",
				"description": "An API key from https://datanem.com/app/api, sent as `Authorization: Bearer <key>`. Available on paid plans. Agents should use the MCP server at https://datanem.com/mcp instead, which uses OAuth 2.1 and is included on every plan."
			}
		},
		"parameters": {
			"JobId": {
				"name": "jobId",
				"in": "path",
				"required": true,
				"schema": { "type": "string" }
			}
		},
		"schemas": {
			"NamedId": {
				"type": "object",
				"properties": { "id": { "type": "string" }, "name": { "type": "string" } }
			},
			"JobStatus": {
				"type": "object",
				"properties": {
					"id": { "type": "string" },
					"status": {
						"type": "string",
						"enum": ["pending", "inferring", "awaiting_schema", "processing", "completed", "partial", "failed"]
					},
					"total": { "type": "integer" },
					"completed": { "type": "integer" },
					"failed": { "type": "integer" },
					"items": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"id": { "type": "string" },
								"filename": { "type": "string" },
								"status": { "type": "string" },
								"error": { "type": ["string", "null"] },
								"refunded": { "type": "boolean" }
							}
						}
					}
				}
			},
			"Results": {
				"type": "object",
				"properties": {
					"id": { "type": "string" },
					"status": { "type": "string" },
					"tables": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"name": { "type": "string" },
								"parent": { "type": ["string", "null"], "description": "The table this one hangs off, for repeating sections." },
								"columns": { "type": "array", "items": { "type": "string" } },
								"rows": { "type": "array", "items": { "type": "array" } }
							}
						}
					}
				}
			},
			"Error": {
				"type": "object",
				"properties": { "error": { "type": "string" } }
			}
		},
		"responses": {
			"BadRequest": {
				"description": "The request could not be read.",
				"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
			},
			"Unauthorized": {
				"description": "Missing or unknown API key.",
				"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
			},
			"PaymentRequired": {
				"description": "The plan does not include API access, or the allowance is spent.",
				"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
			},
			"NotFound": {
				"description": "No such job on this account.",
				"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
			},
			"RateLimited": {
				"description": "Too many requests.",
				"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
			}
		}
	}
}
