{
  "openapi": "3.1.0",
  "info": {
    "title": "Handwriting OCR API",
    "version": "3",
    "description": "REST API for converting handwriting to text. Upload PDFs or images,\npoll for status, and download transcribed results in your preferred\nformat.\n",
    "contact": {
      "name": "Handwriting OCR support",
      "email": "support@handwritingocr.com"
    }
  },
  "servers": [
    {
      "url": "https://api.handwritingocr.com/v3"
    }
  ],
  "tags": [
    {
      "name": "Documents",
      "description": "Upload, list, retrieve, and delete documents."
    },
    {
      "name": "Users",
      "description": "Account information for the authenticated user."
    },
    {
      "name": "Credits",
      "description": "Buy and inspect page credits."
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "All requests require a Bearer token in the `Authorization` header.\nGenerate keys at the [API tokens settings page](https://app.handwritingocr.com/settings?tab=api).\n"
      }
    },
    "parameters": {
      "DocumentId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The document's unique identifier (e.g. `abcde12345`).",
        "schema": {
          "type": "string",
          "example": "abcde12345"
        }
      }
    },
    "schemas": {
      "Document": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "k2D9ZRz9Ob"
          },
          "file_name": {
            "type": "string",
            "example": "My-Document.pdf"
          },
          "action": {
            "type": "string",
            "enum": [
              "transcribe",
              "tables",
              "extractor"
            ]
          },
          "page_count": {
            "type": "integer",
            "example": 24
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "processed",
              "failed"
            ]
          },
          "automatically_deleted_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  },
  "paths": {
    "/documents": {
      "post": {
        "operationId": "upload-document",
        "tags": [
          "Documents"
        ],
        "summary": "Upload document",
        "description": "Upload a new document for processing. Supports PDF files and\nvarious image formats. The API checks the page count of the\nsubmitted document against your credit balance before queueing\nfor processing.\n",
        "x-codeSamples": [
          {
            "lang": "bash",
            "source": "curl -X POST \"https://api.handwritingocr.com/v3/documents\" \\\n     -H \"Authorization: Bearer your-api-token\" \\\n     -H \"Accept: application/json\" \\\n     -F \"file=@/path/to/document.pdf\" \\\n     -F \"action=transcribe\" \\\n     -F \"delete_after=604800\"\n"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "action",
                  "file"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "transcribe",
                      "tables",
                      "extractor"
                    ],
                    "description": "What to do with the document. `transcribe` extracts\ntext, `tables` extracts table structure, `extractor`\nruns a Custom Extractor.\n"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The document to process. Valid file types are PDF,\nJPG, PNG, TIFF, HEIC, GIF. Maximum file size is 20MB.\n"
                  },
                  "delete_after": {
                    "type": "integer",
                    "minimum": 300,
                    "maximum": 1209600,
                    "description": "Seconds until auto-deletion. Overrides the\nauto-deletion period set in your user settings.\nMinimum 300 seconds, maximum 1209600 seconds (14 days).\n"
                  },
                  "extractor_id": {
                    "type": "string",
                    "description": "A 10-character alphanumeric string e.g. `Ks08XVPyMd`.\nCreate and test an extractor in the dashboard to get\nthe extractor ID. Required when `action` is `extractor`.\n"
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "A webhook URL to send the results for this request.\nOverrides your global webhook URL.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Document created and queued for processing.",
            "content": {
              "application/json": {
                "example": {
                  "id": "abc123",
                  "status": "queued"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — missing required fields."
          },
          "401": {
            "description": "Unauthorized — invalid or missing API token."
          },
          "403": {
            "description": "Forbidden — insufficient page credits."
          },
          "415": {
            "description": "Unsupported Media Type."
          },
          "422": {
            "description": "Validation Error — invalid parameters."
          },
          "429": {
            "description": "Too many requests — rate limited."
          },
          "500": {
            "description": "Server Error — file storage or processing failed."
          }
        }
      },
      "get": {
        "operationId": "list-documents",
        "tags": [
          "Documents"
        ],
        "summary": "List documents",
        "description": "Retrieves a paginated list of documents belonging to the\nauthenticated user. Documents are sorted by creation date in\ndescending order.\n",
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            },
            "description": "Number of items per page. Default 50, maximum 200."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            },
            "description": "The page number for pagination. Defaults to 1."
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a paginated list of documents.",
            "content": {
              "application/json": {
                "example": {
                  "documents": [
                    {
                      "id": "k2D9ZRz9Ob",
                      "file_name": "My-Document.pdf",
                      "action": "transcribe",
                      "page_count": 24,
                      "status": "processed",
                      "automatically_deleted_at": "2026-03-12T14:49:19.000000Z",
                      "created_at": "2026-03-05T14:49:19.000000Z",
                      "updated_at": "2026-03-05T14:49:19.000000Z"
                    },
                    {
                      "id": "ql78YGv4dE",
                      "file_name": "Test_Doc_2.pdf",
                      "action": "transcribe",
                      "page_count": 36,
                      "status": "processed",
                      "automatically_deleted_at": "2026-02-24T14:09:00.000000Z",
                      "created_at": "2026-02-18T18:37:03.000000Z",
                      "updated_at": "2026-02-20T00:50:30.000000Z"
                    }
                  ],
                  "current_page": 1,
                  "from": 1,
                  "to": 2,
                  "total": 63,
                  "per_page": 2,
                  "last_page": 63,
                  "next_page_url": "https://api.handwritingocr.com/v3/documents?page=2",
                  "prev_page_url": null
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized — invalid or missing API token."
          },
          "422": {
            "description": "Validation Error — invalid parameters."
          }
        }
      }
    },
    "/documents/{id}": {
      "get": {
        "operationId": "download-result",
        "tags": [
          "Documents"
        ],
        "summary": "Download result",
        "x-display-path": "/documents/{id}[.{format}]",
        "description": "Retrieve the status of a document, or download the processed\nresults. The format extension is optional — if not provided,\nreturns a JSON status response. If the format extension is\nprovided (e.g. `documents/abc123.txt`), downloads the processed\ndocument in that format.\n\nImage thumbnail URLs are provided for each page. These images\nmust be authenticated with your API token to download.\n\n### Webhooks\n\nWe strongly encourage using a **webhook** instead of polling\nthis endpoint repeatedly. Webhooks deliver the processed result\nin JSON format to a URL you choose as soon as the document is\nready, saving bandwidth and reducing latency. Configure a\nwebhook in the [user dashboard](https://app.handwritingocr.com/settings?tab=documents).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentId"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Output format passed as a URL extension on the path\n(e.g. `documents/abc123.txt`). Varies by action: `txt`,\n`docx`, `xlsx`, `csv`, `json`.\n",
            "schema": {
              "type": "string",
              "enum": [
                "txt",
                "docx",
                "xlsx",
                "csv",
                "json"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the processed result.",
            "content": {
              "application/json": {
                "examples": {
                  "transcribe": {
                    "summary": "action = transcribe",
                    "value": {
                      "id": "3486EvMD9p",
                      "file_name": "page-1.jpg",
                      "action": "transcribe",
                      "page_count": 2,
                      "status": "processed",
                      "results": [
                        {
                          "page_number": 1,
                          "transcript": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
                        },
                        {
                          "page_number": 2,
                          "transcript": "Ut enim ad minim veniam, quis nostrud exercitation ullamco."
                        }
                      ],
                      "thumbnails": [
                        {
                          "page_number": 1,
                          "url": "https://api.handwritingocr.com/v3/document/3486EvMD9p/image-1.jpg"
                        }
                      ],
                      "automatically_deleted_at": "2025-03-05 19:47:44",
                      "created_at": "2025-02-19T19:47:44.000000Z",
                      "updated_at": "2025-02-21T03:05:42.000000Z"
                    }
                  },
                  "tables": {
                    "summary": "action = tables",
                    "value": {
                      "id": "NV8OOaZk87",
                      "file_name": "invoice_template_14.jpeg",
                      "action": "tables",
                      "page_count": 1,
                      "status": "processed",
                      "results": [
                        {
                          "page_number": 1,
                          "tables": [
                            {
                              "rows": [],
                              "rowCount": 1,
                              "columnCount": 2,
                              "tableNumber": 1,
                              "hasHeaderRow": false,
                              "headerContent": null
                            }
                          ],
                          "key_value_pairs": [
                            {
                              "key": "VAT Number",
                              "value": "1234567"
                            }
                          ]
                        }
                      ]
                    }
                  },
                  "extractor": {
                    "summary": "action = extractor",
                    "value": {
                      "id": "gj8kAvDQ4p",
                      "file_name": "page-1.jpg",
                      "action": "extractor",
                      "page_count": 1,
                      "status": "processed",
                      "results": [
                        {
                          "page_number": 1,
                          "extractions": [
                            [
                              {
                                "key": "date_of_birth",
                                "name": "Date of birth",
                                "type": "string",
                                "array": false,
                                "value": "12/12/1994"
                              },
                              {
                                "key": "place",
                                "name": "Place",
                                "type": "string",
                                "array": false,
                                "value": "Paris"
                              }
                            ]
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Accepted — document is still being processed."
          },
          "400": {
            "description": "Bad Request — invalid format for action type."
          },
          "401": {
            "description": "Unauthorized — invalid or missing API token."
          },
          "403": {
            "description": "Forbidden — no permission to access document."
          },
          "404": {
            "description": "Not found — document not found."
          },
          "429": {
            "description": "Too many requests — rate limited."
          },
          "500": {
            "description": "Server Error — error preparing file for download."
          }
        }
      },
      "delete": {
        "operationId": "delete-document",
        "tags": [
          "Documents"
        ],
        "summary": "Delete document",
        "description": "Permanently delete a document and its associated files. This\naction cannot be undone.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentId"
          }
        ],
        "responses": {
          "204": {
            "description": "Document deleted."
          },
          "401": {
            "description": "Unauthorized — invalid or missing API token."
          },
          "403": {
            "description": "Forbidden — no permission to delete document."
          },
          "404": {
            "description": "Not Found — document not found."
          },
          "500": {
            "description": "Server Error — error deleting document."
          }
        }
      }
    },
    "/users/me": {
      "get": {
        "operationId": "get-user-information",
        "tags": [
          "Users"
        ],
        "summary": "Get user information",
        "description": "Returns the authenticated user's account details, including\ncore user fields (name, email, account tier) alongside the\ncurrent credit balance.\n",
        "responses": {
          "200": {
            "description": "Returns the authenticated user's account details.",
            "content": {
              "application/json": {
                "example": {
                  "id": "rjq89y8DRY",
                  "name": "Test User",
                  "email": "tester@email.com",
                  "verified": true,
                  "type": "medium-monthly",
                  "balance": 11020,
                  "token": "1|GS8ouqzNOCbSEzXCiFlWEBve7PisNL4Yg33cfpoB6cde17b2",
                  "updated_at": "2026-03-09T10:16:25.000000Z"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized — invalid or missing API token."
          }
        }
      }
    },
    "/credits/topup": {
      "post": {
        "operationId": "purchase-additional-credits",
        "tags": [
          "Credits"
        ],
        "summary": "Purchase additional credits",
        "description": "Triggers an immediate credit top-up for the authenticated user\nusing their saved payment method. Works independently of\nauto-topup settings. Rate-limited to one successful purchase\nper 5-minute window.\n",
        "x-codeSamples": [
          {
            "lang": "bash",
            "source": "curl -X POST \"https://api.handwritingocr.com/v3/credits/topup\" \\\n     -H \"Authorization: Bearer your-api-token\" \\\n     -H \"Accept: application/json\" \\\n     -F \"amount=500\"\n"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "amount"
                ],
                "properties": {
                  "amount": {
                    "type": "integer",
                    "example": 500,
                    "description": "Number of credits to purchase. Must be a multiple of 100.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purchase succeeded. Returns the number of credits added,\nthe user's updated balance, and the formatted charge amount.\n",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "credits_purchased": 500,
                  "new_balance": 1250,
                  "amount_charged": "$4.99"
                }
              }
            }
          },
          "402": {
            "description": "The payment requires 3DS or bank authentication before it\ncan complete. Follow `authentication_url` to verify, then retry.\n"
          },
          "403": {
            "description": "Invalid API token, or the user does not have an active\nsubscription. A subscription is required to purchase credits.\n"
          },
          "422": {
            "description": "Validation error. `amount_not_multiple_of_100`,\n`amount_below_minimum`, `no_payment_method`, or\n`payment_failed` (with `decline_code`).\n"
          },
          "429": {
            "description": "A successful purchase was already made within the last\n5 minutes. Check `retry_after` (ISO 8601) for when the next\npurchase is permitted.\n"
          }
        }
      }
    }
  }
}