Skip to main content
Parse every document in a storage bucket with one request, and write each result back to the bucket as its job ends. Use it for backfills and folder drops.

What you need

  • The Python SDK and an API key, set up as in Cookbooks.
  • boto3, with AWS credentials that can list and read the documents and write the results.
  • An Amazon S3 bucket of PDFs. Signed URLs from Google Cloud Storage or Azure Blob Storage work the same way.

Build it

1

Set up the clients

This code creates the Pulse and S3 clients, and names the bucket and its folders.
2

Sign a URL for each document

This code signs a download URL, valid for 48 hours, for each PDF in the folder.
Pulse fetches each URL when its job runs, up to 48 hours after you send the batch, so sign with credentials that last that long. A URL signed with temporary credentials, such as an assumed role’s, stops working when they expire.
3

Send the batch

This code sends the URLs in batches of up to 1,000 and keeps each batch_id.
A batch always runs async, and each URL becomes its own parse job. A URL that doesn’t return the document when its job runs, such as one whose signature has expired, fails only its own job.
4

Write each result as its job ends

drain reads a batch’s manifest, the list of its jobs that have ended, and passes each new job to handle, which writes its result to the bucket.
5

Run until every batch ends

This loop drains each batch in turn. A brief 429 or 5xx error stops drain; the loop waits and starts it again.
handled makes sure no result is read twice and none is skipped when drain starts again, even after a restart if you store it with the batch ids.

How it works

The id each step hands to the next: On each pass, drain reads the batch’s status and the manifest: The manifest’s entries never move, so drain follows each page’s Link header to the next page, then asks for the last page again until the batch ends. Each result is read once, so the recipe also works where your organization deletes a result the first time it’s read.

Edge cases

A manifest entry names its parse_id, not its URL, and the result’s history.file_name holds only the file’s name, which can repeat across folders. To file results by object key, or to retry one object, send one async /parse per object and store each parse_id with its key.
Add "storage": {"save": False} to CONFIG. Each result is then deleted 24 hours after its batch ends, or sooner if your organization sets a 1-hour retention. The free plan can’t turn saving off.
A batch ends failed when it isn’t done within 48 hours of being sent, or when it’s interrupted. After either, or after you cancel a batch, some of its jobs can still end: run drain once more a few minutes later, with the same handled, to collect them. An interrupted batch can also leave documents that never ran; to find those, track each object with its own parse_id, as above.
If anyone can list and read the folder, send it as folder_url instead of signing a URL for each document.
To extract from each document as well, start the extract from a parse.completed webhook. Then read each parse in handle only after its extract has ended, in case your organization deletes a result the first time it’s read.

Next steps

Batch

Sources, statuses, limits and the manifest.

Webhooks

Get a signed event as a job’s status changes.