Extract text in a Zap, no txtfetch app required.

There is no txtfetch app in the Zapier directory. Webhooks by Zapier's Custom Request action calls the same API directly, and a link works better than a file step ever would.

the-problem

A Zap that needs text out of an incoming document usually starts from a Google Drive file, a Gmail attachment, or a form upload. Zapier's steps pass those around as file objects. Forwarding one to a Custom Request action as binary data is fiddly and easy to get wrong. Zaps also run on a fixed step timeout. A document that takes a while to OCR can fail the step before it ever gets a result back.

how-to-wire-it-up

txtfetch has no Zapier integration listed in the app directory. Webhooks by Zapier's Custom Request action reaches the same REST endpoint a curl command would, with no app to install first. Most upstream steps already expose a shareable link for the file — a Google Drive share link, a Gmail attachment URL. Pass that as the url query parameter, instead of trying to forward the file's bytes. For a document that's large or slow, add async and webhook_url to the same request. Then let a second Zap start from a Catch Hook trigger when the result is ready.

  • Pass ?url= with a file's existing share link, so the Custom Request action never handles binary file data.
  • Automatic OCR covers scanned PDFs and photographed forms, with no separate OCR app needed in the Zap.
  • Async mode returns a job_id immediately, so a slow extraction never times out the Custom Request step.
  • A Catch Hook trigger on a second Zap picks up the webhook_url callback and continues the automation from there.
  • Idempotency-Key support keeps a Zapier auto-replay from re-running and re-billing the same extraction.

pass-a-link-not-a-file

curl
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/report.pdf" \
  -H "Authorization: Bearer $TXTFETCH_KEY"
Python
import os
import requests

r = requests.post(
    "https://api.txtfetch.com/v1/extract",
    headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
    params={"url": "https://example.com/report.pdf"},
)

print(r.json()["extracted_text"])
JavaScript
const endpoint = new URL("https://api.txtfetch.com/v1/extract");
endpoint.searchParams.set("url", "https://example.com/report.pdf");

const res = await fetch(endpoint, {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
});

const { extracted_text } = await res.json();
console.log(extracted_text);
Go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
)

type extractResponse struct {
	Status        string `json:"status"`
	ExtractedText string `json:"extracted_text"`
}

func main() {
	endpoint, err := url.Parse("https://api.txtfetch.com/v1/extract")
	if err != nil {
		panic(err)
	}
	q := endpoint.Query()
	q.Set("url", "https://example.com/report.pdf")
	endpoint.RawQuery = q.Encode()

	req, err := http.NewRequest("POST", endpoint.String(), nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))

	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": "..."
}

large-or-slow-documents

POST /v1/extract returns 202 with a job_id whenever the document is large or slow to process, or whenever async=true is set. Poll GET /v1/extract/{job_id} for the result, or set webhook_url and have txtfetch push it instead. No single request on this page is safe to assume will always finish synchronously.

Submit (async)
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/report.pdf&async=true" \
  -H "Authorization: Bearer $TXTFETCH_KEY"

# {"status": "processing", "job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"}
Poll
curl "https://api.txtfetch.com/v1/extract/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer $TXTFETCH_KEY"

# {"status": "processing", "job_id": "..."} while running, then the same
# {"status": "success", "extracted_text": "...", "metadata": {...}} shape
# POST /v1/extract would have returned synchronously.
curl
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/report.pdf" \
  -H "Authorization: Bearer $TXTFETCH_KEY" \
  --data-urlencode "webhook_url=https://example.com/webhooks/txtfetch"

setup-steps

  1. Add a Webhooks by Zapier action and choose Custom Request.
  2. Set Method to POST.
  3. Set URL to https://api.txtfetch.com/v1/extract, then add url as a query string parameter with the document's link.
  4. Under Headers, add Authorization with the value Bearer, followed by your API key.
  5. For a large document, add async set to true and webhook_url set to a second Zap's Catch Hook address.
  6. Test the action. Zapier shows extracted_text in the returned data, ready to map into the next step.

faq

Is there a txtfetch app in the Zapier directory?
No. txtfetch has no listed Zapier app or connector. Webhooks by Zapier's Custom Request action reaches the same REST API with no app install needed.
How do I send a file from a Zap without a txtfetch app?
Use the file's share link from the upstream step — Google Drive, Dropbox, and Gmail attachments all expose one. Pass it as the url query parameter, rather than forwarding the file itself.
Can a Zap wait for a slow OCR job without timing out?
Yes. Add async=true and webhook_url to the request, and end the first Zap there. Start a second Zap from a Catch Hook trigger when the callback arrives.
How does a Zap tell a failed extraction from a successful one?
Check the status field in the response. A failed request still returns a typed error.code instead of extracted_text, so a Filter step can catch it before the Zap continues.

related-reading

Add the step to your Zapier flow.

One HTTP node with your key does the whole job.

Get an API key →

See every integration →