{
  "openapi": "3.0.1",
  "info": {
    "title": "SiteVerdict — PDF & Invoice Data Extractor (tables, line items)",
    "description": "Extract text, tables and invoice data from PDFs without AI: supplier, VAT number (checked), invoice no., dates, net/VAT/gross totals and line items, each with a confidence score and arithmetic checks. UK/EU formats, optional OCR.",
    "version": "1.1",
    "x-build-id": "DRs35gdzHDeJtqizB"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/siteverdict~siteverdict-pdf-invoice-extractor/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-siteverdict-siteverdict-pdf-invoice-extractor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/siteverdict~siteverdict-pdf-invoice-extractor/runs": {
      "post": {
        "operationId": "runs-sync-siteverdict-siteverdict-pdf-invoice-extractor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/siteverdict~siteverdict-pdf-invoice-extractor/run-sync": {
      "post": {
        "operationId": "run-sync-siteverdict-siteverdict-pdf-invoice-extractor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "pdfUrls": {
            "title": "PDF URLs",
            "type": "array",
            "description": "Public or pre-signed (S3, GCS, SharePoint/Drive direct-download) PDF links. Query strings of signed URLs are redacted in the output. Apify key-value store record URLs (including files you upload in Apify Console) also work. Anything you put in a request's userData is carried to the output as \"context\".",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "keyValueStoreRecords": {
            "title": "Files in Apify key-value stores",
            "type": "array",
            "description": "PDFs already stored in Apify key-value stores, as \"storeIdOrName/key\" (or just \"key\" for this run's default store). Use this for files you upload yourself, so they never need a public URL.",
            "items": {
              "type": "string"
            }
          },
          "inboxMessages": {
            "title": "Inbox batch (e-mails with PDF attachments)",
            "type": "array",
            "description": "E-mail-style batch from your inbox parser, Zapier, Make or mail server: [{\"messageId\", \"from\", \"subject\", \"receivedAt\", \"attachments\": [\"https://...pdf\" | {\"url\", \"filename\"} | {\"kvRecord\": \"store/key\", \"filename\"}]}]. Every PDF attachment becomes one document; messageId/from/subject/receivedAt are copied to the output \"context\" so you can trace each bill to its e-mail. Non-PDF attachments (by filename) are skipped and not charged. Message bodies are never read."
          },
          "manifestRecord": {
            "title": "Inbox batch stored as a JSON record",
            "type": "string",
            "description": "Optional: \"storeIdOrName/key\" of a JSON record holding the same array as \"Inbox batch\" (or {\"messages\": [...]}) - handy when an automation drops a batch file into a key-value store."
          },
          "folderUrls": {
            "title": "Folder pages to scan for PDFs",
            "type": "array",
            "description": "Public pages that list PDFs: an HTML index / download page, a public S3-style bucket listing (XML), or a JSON list of URLs. Every PDF link found is processed. robots.txt is respected; pages behind a login are not supported. Combine with Monitor mode to process only new or changed files on each scheduled run.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "folderUrlPattern": {
            "title": "Folder link pattern (regex)",
            "type": "string",
            "description": "Optional regular expression for links to pick up from folder pages when they do not end in .pdf (for example \"/download\\?id=\"). Default: links ending in .pdf."
          },
          "folderMaxPdfs": {
            "title": "Max PDFs per folder page",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "Safety cap on links taken from each folder page.",
            "default": 200
          },
          "datasetId": {
            "title": "Dataset with PDF URLs",
            "type": "string",
            "description": "Optional: ID of an Apify dataset (e.g. from a crawler) whose items contain PDF URLs."
          },
          "datasetUrlField": {
            "title": "URL field in that dataset",
            "type": "string",
            "description": "Name of the field holding the PDF URL in each dataset item.",
            "default": "url"
          },
          "authorizationHeader": {
            "title": "Authorization header (optional)",
            "type": "string",
            "description": "Sent as the HTTP Authorization header (e.g. \"Bearer ...\") only to the host of each PDF/folder URL, never to redirect targets on other hosts. Never logged or stored in the output."
          },
          "invoiceMode": {
            "title": "Invoice field extraction",
            "enum": [
              "auto",
              "always",
              "off"
            ],
            "type": "string",
            "description": "auto = extract invoice/receipt fields only when the document looks like an invoice, receipt or credit note; always = try on every PDF; off = text and tables only (no invoice-extracted charge).",
            "default": "auto"
          },
          "extractTables": {
            "title": "Extract tables",
            "type": "boolean",
            "description": "Detect tables from text positions and return them as rows, Markdown and CSV.",
            "default": true
          },
          "includeText": {
            "title": "Include full text",
            "type": "boolean",
            "description": "Return the document text with the page layout preserved (columns line up).",
            "default": true
          },
          "includePageText": {
            "title": "Include per-page text",
            "type": "boolean",
            "description": "Also return the text of each page separately.",
            "default": false
          },
          "maxTextChars": {
            "title": "Max text characters per document",
            "minimum": 0,
            "maximum": 2000000,
            "type": "integer",
            "description": "Longer text is truncated (textTruncated = true). Tables and invoice fields are not affected.",
            "default": 100000
          },
          "numberFormat": {
            "title": "Number format",
            "enum": [
              "auto",
              "uk",
              "eu"
            ],
            "type": "string",
            "description": "auto detects per document. uk = 1,234.56 (also Indian 1,23,456.78); eu = 1.234,56 or 1 234,56.",
            "default": "auto"
          },
          "dateOrder": {
            "title": "Date order for ambiguous dates",
            "enum": [
              "auto",
              "DMY",
              "MDY"
            ],
            "type": "string",
            "description": "auto = decided per document: unambiguous dates such as 25/12 or 12/25 settle it, otherwise US signals ($, US address, sales tax) mean month first, else day first. Set DMY or MDY to force one.",
            "default": "auto"
          },
          "defaultCurrency": {
            "title": "Default currency",
            "type": "string",
            "description": "ISO code used when a document shows no currency (e.g. GBP, EUR). Leave empty to report null."
          },
          "defaultVatCountry": {
            "title": "Default VAT country",
            "type": "string",
            "description": "Two-letter country used to check VAT numbers printed without a country prefix (e.g. GB). Auto: GB when the document uses £."
          },
          "includeBuyerDetails": {
            "title": "Include buyer name and VAT number",
            "type": "boolean",
            "description": "Off by default because the buyer may be a private individual. Turn on only if you have a lawful basis to process it (needed for complete UBL/Factur-X drafts).",
            "default": false
          },
          "reviewConfidencePercent": {
            "title": "Review threshold (confidence %)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "A document is flagged needsReview when a key field (supplier, invoice number, date, currency, total) is missing or below this confidence, when an error-level check fails, or when it is a possible duplicate. Fields below the threshold are also what the optional AI step looks at.",
            "default": 80
          },
          "detectDuplicates": {
            "title": "Detect duplicate invoices",
            "type": "boolean",
            "description": "Flag the same file, the same supplier + invoice number, or the same supplier + amount + date seen earlier in the batch. Identical files are not processed or charged twice.",
            "default": true
          },
          "rememberAcrossRuns": {
            "title": "Remember invoices across runs",
            "type": "boolean",
            "description": "Keep duplicate-detection keys (file hash, supplier tax ID/name, invoice number, total, date) in a named key-value store in YOUR Apify account, so an invoice paid last month is flagged when it arrives again. Always on in Monitor mode.",
            "default": false
          },
          "monitorMode": {
            "title": "Monitor mode (only new or changed documents)",
            "type": "boolean",
            "description": "For scheduled runs: remembers every document (content hash, ETag, Last-Modified) in the named state store and outputs only new or changed ones. Unchanged documents are skipped and not charged. Uses polite conditional requests (If-None-Match / If-Modified-Since).",
            "default": false
          },
          "stateStoreName": {
            "title": "State store name",
            "type": "string",
            "description": "Named key-value store that holds monitor and duplicate state. Use one name per supplier folder / client to keep their histories apart.",
            "default": "siteverdict-invoice-state"
          },
          "alertWebhookUrl": {
            "title": "Alert webhook (Slack or any HTTPS URL)",
            "type": "string",
            "description": "Optional HTTPS webhook called once at the end of the run, e.g. a Slack incoming-webhook URL. Treated as a secret; never logged."
          },
          "alertFormat": {
            "title": "Alert format",
            "enum": [
              "slack",
              "json"
            ],
            "type": "string",
            "description": "slack = {\"text\": ...} message; json = structured payload with the run summary and flagged documents.",
            "default": "slack"
          },
          "alertOn": {
            "title": "Send the alert when",
            "enum": [
              "problems",
              "new",
              "always"
            ],
            "type": "string",
            "description": "problems = something needs review, is a duplicate or failed; new = at least one new/changed invoice; always = every run.",
            "default": "problems"
          },
          "exportFormats": {
            "title": "Export files",
            "type": "array",
            "description": "Files written to the run's key-value store (links in OUTPUT): Excel workbook, Xero bills CSV, QuickBooks Online bills CSV, flat invoices CSV, UBL 2.1 (Peppol BIS 3) XML drafts, Factur-X/ZUGFeRD (CII) XML drafts and an HTML batch report. Exports are included in the price.",
            "items": {
              "type": "string",
              "enum": [
                "xlsx",
                "xero",
                "quickbooks",
                "csv",
                "ubl",
                "facturx",
                "html"
              ],
              "enumTitles": [
                "Excel workbook (INVOICES.xlsx)",
                "Xero bills import (XERO_BILLS.csv)",
                "QuickBooks Online bills (QUICKBOOKS_BILLS.csv)",
                "Invoices CSV (INVOICES.csv)",
                "UBL 2.1 / Peppol XML per invoice",
                "Factur-X / ZUGFeRD CII XML per invoice",
                "HTML batch report (REPORT.html)"
              ]
            },
            "default": [
              "xlsx",
              "xero",
              "quickbooks",
              "html"
            ]
          },
          "exportDateFormat": {
            "title": "Date format in Xero / QuickBooks files",
            "enum": [
              "DMY",
              "MDY",
              "ISO"
            ],
            "type": "string",
            "description": "Match your accounting organisation's region.",
            "default": "DMY"
          },
          "xeroAccountCode": {
            "title": "Xero account code",
            "type": "string",
            "description": "Expense account for imported bill lines (429 = General Expenses in Xero's default chart).",
            "default": "429"
          },
          "xeroTaxType": {
            "title": "Xero tax rate name (optional)",
            "type": "string",
            "description": "Leave empty to map automatically (UK: 20% (VAT on Expenses), 5% (VAT on Expenses), Zero Rated Expenses, No VAT; elsewhere: Tax on Purchases). Set to force one tax rate name from your Xero organisation."
          },
          "quickbooksAccount": {
            "title": "QuickBooks expense account",
            "type": "string",
            "description": "Account name for imported bill lines.",
            "default": "Uncategorized Expense"
          },
          "writeLineItemsCsv": {
            "title": "Write LINE_ITEMS.csv",
            "type": "boolean",
            "description": "Save all line items of the run as one CSV file in the run's key-value store.",
            "default": true
          },
          "aiProvider": {
            "title": "AI refinement (optional, your own key)",
            "enum": [
              "none",
              "anthropic",
              "openai"
            ],
            "type": "string",
            "description": "Off by default. When on, only documents flagged needsReview are sent - and only their weak fields are asked for - to YOUR Anthropic or OpenAI account. Every AI answer is verified against the PDF text (values must be printed, tax IDs must pass check digits, totals must add up) before it is accepted. Charged as ai-refined-document only when a verified field was filled or corrected; the LLM usage is billed by your provider.",
            "default": "none"
          },
          "aiApiKey": {
            "title": "Your LLM API key",
            "type": "string",
            "description": "Your own Anthropic or OpenAI API key. Stored encrypted by Apify, never logged or written to the output."
          },
          "aiModel": {
            "title": "Model (optional)",
            "type": "string",
            "description": "Default: claude-sonnet-5-5 (Anthropic) or gpt-4.1-mini (OpenAI). For high volumes a cheaper model such as claude-haiku-5-5 usually suffices because every answer is verified."
          },
          "aiMaxDocuments": {
            "title": "Max documents sent to AI per run",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Cost guard for your LLM account.",
            "default": 100
          },
          "enableOcr": {
            "title": "OCR scanned pages (slower, higher price)",
            "type": "boolean",
            "description": "Read pages without a text layer with tesseract.js OCR. About 2-10 s per page; charged as ocr-page instead of page-processed. Accuracy depends on scan quality.",
            "default": false
          },
          "ocrLanguages": {
            "title": "OCR languages",
            "type": "string",
            "description": "Tesseract language codes joined by + (max 5), e.g. eng, eng+deu, fra+nld.",
            "default": "eng"
          },
          "ocrMinCharsPerPage": {
            "title": "OCR pages with fewer than N characters",
            "minimum": 1,
            "maximum": 10000,
            "type": "integer",
            "description": "A page is OCR'd only when its text layer has fewer characters than this.",
            "default": 20
          },
          "maxFileSizeMb": {
            "title": "Max file size (MB)",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Larger files are skipped (status too_large) and not charged.",
            "default": 25
          },
          "maxPagesPerDocument": {
            "title": "Max pages per document",
            "minimum": 1,
            "maximum": 2000,
            "type": "integer",
            "description": "Only the first N pages are processed and charged (status partial).",
            "default": 50
          },
          "maxDocuments": {
            "title": "Max documents",
            "minimum": 1,
            "maximum": 10000,
            "type": "integer",
            "description": "Safety cap on documents per run.",
            "default": 1000
          },
          "maxConcurrency": {
            "title": "Parallel documents",
            "minimum": 1,
            "maximum": 8,
            "type": "integer",
            "description": "Documents processed at the same time. Raise with more memory.",
            "default": 2
          },
          "storeSourceCopies": {
            "title": "Keep copies of the PDFs",
            "type": "boolean",
            "description": "Off by default: PDFs are processed in memory and discarded. On = save each successfully processed PDF to this run's key-value store (kept for your storage retention period).",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}