https://txtfetch.com/solutions/document-workflows/
Turn incoming documents into structured action.
Invoices, inbound email, and scanned forms all start the same way. Extract the text first, then classify, route, or act on it downstream.
the-problem
Document-driven workflows share the same first step: turn an incoming file into text before any business logic runs. That step is usually the least reliable part of the pipeline. The inputs are the least controlled: a photographed form, a forwarded email thread, a scan from a fax gateway. Stitching together OCR, a mail parser, and a document library often breaks on the one case nobody tested.
how-txtfetch-solves-it
txtfetch is the extraction step, not a workflow engine. POST the incoming file, or its URL, and get back plain text, whatever the source. Async mode with a webhook_url means the workflow never blocks on OCR. The callback fires when the text is ready, and your automation, a queue worker, or a Lambda, picks up from there.
- OCR runs automatically on scanned forms and photographed documents, with no separate vision service to wire in.
- Email extraction (.eml/.msg/.mbox) includes headers and attachment text, useful for routing rules.
- Webhook callbacks (webhook_url) mean a long-running OCR job never holds a workflow connection open.
- Webhook payloads are HMAC-signed and verifiable with the SDK's verifyWebhook or verify_webhook helper.
- Idempotency-Key support stops a retried webhook delivery from reprocessing the same document twice.
- The same endpoint handles a PDF, a scanned form, and an email thread with no branch in your workflow code.
- A queue worker, a Lambda function, or a Zapier automation can each pick up the extracted text the same way.
curl -X POST https://api.txtfetch.com/v1/extract \
-H "Authorization: Bearer $TXTFETCH_KEY" \
-F file=@scanned-form.pngimport os
import requests
with open("scanned-form.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("scanned-form.png")]);
const form = new FormData();
form.append("file", file, "scanned-form.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("scanned-form.png")
if err != nil {
panic(err)
}
defer f.Close()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile("file", "scanned-form.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 form 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.
- 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.
- 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) or verify_webhook (Python) helper. You can also reproduce the raw HMAC check documented at /docs/async.
related-reading
Start on the free plan.
Run your own documents through it before you commit. The Hobby plan needs no card.
Get started →