Turn incoming documents into structured action.
Invoices, inbound email, scanned forms — extract the text first, then classify, route, or act on it in whatever system runs your workflow.
the-problem
Document-driven workflows — invoice processing, inbound-email routing, resume screening, claims intake — all share the same first step: turn an arbitrary incoming file into text before any business logic can run. That first step is usually the least reliable part of the pipeline, because the inputs are the least controlled: a photographed invoice, a forwarded email thread with attachments, a scanned form from a fax gateway. Bolting together OCR for the images, a mail parser for the email, and a document library for everything else means the automation breaks in the specific case nobody tested.
how-txtfetch-solves-it
txtfetch is the extraction step of the workflow, not a workflow engine itself: POST the incoming file (or its URL) and get back plain text, whatever the source — a scanned invoice, an .eml thread with attachments, a form photo from a phone. Async mode with a webhook_url means the workflow doesn't block on OCR; the callback fires when text is ready, and your automation (Zapier, a queue worker, a Lambda) picks up from there.
- Automatic OCR for scanned invoices, forms, and photographed documents — no separate vision/OCR service to wire in
- Email (.eml/.msg/.mbox) extraction includes headers and attachment text, useful for routing rules
- Webhook callbacks (webhook_url) so long-running OCR jobs don't hold a workflow connection open
- HMAC-signed webhook payloads, verifiable with the SDK's verifyWebhook/verify_webhook helper
- Idempotency-Key support so a retried webhook delivery or a re-queued job doesn't reprocess a document twice
curl -X POST https://api.txtfetch.com/v1/extract \
-H "Authorization: Bearer $TXTFETCH_KEY" \
-F file=@invoice.pngimport os
import requests
with open("invoice.png", "rb") as f:
r = requests.post(
"https://api.txtfetch.com/v1/extract",
headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
files={"file": f},
)
print(r.json()["extracted_text"])import { readFile } from "node:fs/promises";
const file = new Blob([await readFile("invoice.png")]);
const form = new FormData();
form.append("file", file, "invoice.png");
const res = await fetch("https://api.txtfetch.com/v1/extract", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
body: form,
});
const { extracted_text } = await res.json();
console.log(extracted_text);package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
type extractResponse struct {
Status string `json:"status"`
ExtractedText string `json:"extracted_text"`
}
func main() {
f, err := os.Open("invoice.png")
if err != nil {
panic(err)
}
defer f.Close()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile("file", "invoice.png")
if err != nil {
panic(err)
}
if _, err := io.Copy(part, f); err != nil {
panic(err)
}
writer.Close()
req, err := http.NewRequest("POST", "https://api.txtfetch.com/v1/extract", &body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result extractResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
fmt.Println(result.ExtractedText)
}{
"status": "success",
"extracted_text": "..."
}faq
- Can txtfetch OCR a photographed invoice for an automation pipeline?
- Yes — POST the image (PNG/JPG/TIFF) to /v1/extract and Tesseract OCR runs automatically; the response is the same { status, extracted_text } shape as any other format, ready for your invoice-parsing logic downstream.
- How do I avoid blocking a workflow on a slow OCR job?
- Pass async=true and supply a webhook_url — txtfetch calls it back with the result when extraction finishes, so the workflow can move on instead of holding a connection open.
- Are webhook deliveries verifiable, so I know they came from txtfetch?
- Yes — each webhook is HMAC-SHA256 signed; verify it with the SDK's verifyWebhook (JS) / verify_webhook (Python) helper, or reproduce the raw HMAC check documented at /docs/async.
related-reading
other-solutions
Stop parsing. Start shipping.
Create an account and get an API key in minutes — the free Hobby plan needs no card.
Get started →