{
  "openapi": "3.1.0",
  "info": {
    "title": "ForkLabs Doc Extract API",
    "version": "1.0.0",
    "description": "Developer API for the Doc Extract demo. The demo key only works on the sample documents; it never calls a model."
  },
  "servers": [
    {
      "url": "/api",
      "description": "Same origin as this site"
    }
  ],
  "paths": {
    "/v1/extract": {
      "post": {
        "operationId": "extractSample",
        "summary": "Extract a sample document",
        "description": "Returns the precomputed pipeline result for one sample document. The demo key only works on the sample documents.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExtractRequest"
              },
              "example": {
                "sample_id": "acme-supplies-inv-1042"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The extraction result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SampleResult"
                }
              }
            }
          },
          "400": {
            "description": "The body is not {\"sample_id\": \"<id>\"}.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or wrong X-Api-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "There is no sample with that id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}": {
      "get": {
        "operationId": "getJob",
        "summary": "Get a job",
        "description": "Status of a document uploaded with an invite, and its result once done. Jobs and results are deleted automatically within 24 hours.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The job id."
          }
        ],
        "responses": {
          "200": {
            "description": "Job status, with the result when it is done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "404": {
            "description": "The job does not exist or has been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "The demo key. It only works on the sample documents."
      }
    },
    "schemas": {
      "Field": {
        "type": "object",
        "description": "One extracted value. Money travels as decimal strings.",
        "required": [
          "raw",
          "value"
        ],
        "properties": {
          "raw": {
            "type": [
              "string",
              "null"
            ],
            "description": "Exactly as printed on the document."
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "description": "Normalized value (decimal string for amounts, ISO date for dates)."
          }
        }
      },
      "LineItem": {
        "type": "object",
        "required": [
          "description",
          "quantity",
          "unit_price",
          "line_total",
          "category"
        ],
        "properties": {
          "description": {
            "$ref": "#/components/schemas/Field"
          },
          "quantity": {
            "$ref": "#/components/schemas/Field"
          },
          "unit_price": {
            "$ref": "#/components/schemas/Field"
          },
          "line_total": {
            "$ref": "#/components/schemas/Field"
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Header": {
        "type": "object",
        "required": [
          "vendor_name",
          "vendor_address",
          "vendor_tax_id",
          "customer_name",
          "number",
          "issue_date",
          "due_date",
          "currency",
          "subtotal",
          "discount",
          "tax_total",
          "tax_rate",
          "shipping",
          "grand_total",
          "payment_terms"
        ],
        "properties": {
          "vendor_name": {
            "$ref": "#/components/schemas/Field"
          },
          "vendor_address": {
            "$ref": "#/components/schemas/Field"
          },
          "vendor_tax_id": {
            "$ref": "#/components/schemas/Field"
          },
          "customer_name": {
            "$ref": "#/components/schemas/Field"
          },
          "number": {
            "$ref": "#/components/schemas/Field"
          },
          "issue_date": {
            "$ref": "#/components/schemas/Field"
          },
          "due_date": {
            "$ref": "#/components/schemas/Field"
          },
          "currency": {
            "$ref": "#/components/schemas/Field"
          },
          "subtotal": {
            "$ref": "#/components/schemas/Field"
          },
          "discount": {
            "$ref": "#/components/schemas/Field"
          },
          "tax_total": {
            "$ref": "#/components/schemas/Field"
          },
          "tax_rate": {
            "$ref": "#/components/schemas/Field"
          },
          "shipping": {
            "$ref": "#/components/schemas/Field"
          },
          "grand_total": {
            "$ref": "#/components/schemas/Field"
          },
          "payment_terms": {
            "$ref": "#/components/schemas/Field"
          }
        }
      },
      "Extraction": {
        "type": "object",
        "required": [
          "doc_type",
          "header",
          "items",
          "custom"
        ],
        "properties": {
          "doc_type": {
            "type": "string",
            "enum": [
              "invoice",
              "receipt"
            ]
          },
          "header": {
            "$ref": "#/components/schemas/Header"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItem"
            }
          },
          "custom": {
            "type": "object",
            "description": "Custom fields by name.",
            "additionalProperties": {
              "$ref": "#/components/schemas/Field"
            }
          }
        }
      },
      "Box": {
        "type": "object",
        "description": "Bounding box as fractions (0-1) of the page size.",
        "required": [
          "page",
          "x0",
          "y0",
          "x1",
          "y1"
        ],
        "properties": {
          "page": {
            "type": "integer",
            "description": "Zero-based page index."
          },
          "x0": {
            "type": "number"
          },
          "y0": {
            "type": "number"
          },
          "x1": {
            "type": "number"
          },
          "y1": {
            "type": "number"
          }
        }
      },
      "FieldResult": {
        "type": "object",
        "required": [
          "path",
          "status",
          "reason",
          "boxes",
          "rechecked"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "header.<name>, items[<i>].<name> or custom.<name>."
          },
          "status": {
            "type": "string",
            "enum": [
              "verified",
              "check",
              "missing"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the field needs a check, in plain words."
          },
          "boxes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Box"
            }
          },
          "rechecked": {
            "type": "boolean",
            "description": "True when a second model re-read this field."
          }
        }
      },
      "Result": {
        "type": "object",
        "required": [
          "extraction",
          "fields",
          "pages",
          "cost_usd",
          "models"
        ],
        "properties": {
          "extraction": {
            "$ref": "#/components/schemas/Extraction"
          },
          "fields": {
            "type": "object",
            "description": "Status per field path.",
            "additionalProperties": {
              "$ref": "#/components/schemas/FieldResult"
            }
          },
          "pages": {
            "type": "integer"
          },
          "cost_usd": {
            "type": [
              "string",
              "number"
            ],
            "description": "Decimal serialized by the backend."
          },
          "models": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "SampleResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Result"
          },
          {
            "type": "object",
            "properties": {
              "sample_id": {
                "type": "string"
              },
              "file": {
                "type": "string",
                "description": "Path of the sample document."
              },
              "tags": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "duplicate_of": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "ExtractRequest": {
        "type": "object",
        "required": [
          "sample_id"
        ],
        "additionalProperties": false,
        "properties": {
          "sample_id": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,64}$",
            "description": "One of the sample document ids."
          }
        }
      },
      "Job": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "description": "For example queued, processing, done or failed."
          },
          "error_code": {
            "type": "string"
          },
          "error_message": {
            "type": "string"
          },
          "result": {
            "$ref": "#/components/schemas/Result"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}
