Skip to main content
Fetched invoices shown as a list next to the structured JSON response Bill fetching can be a single task: log in and fetch the latest bill. When a credential holds many accounts, a single task returns one combined result, with no way to tell which accounts contributed, which are closed, or where a partial delivery came from. This guide splits the work into three narrow tasks:
  1. Extract accounts: runs once per credential. Returns a list of accounts behind a single credential.
  2. Check for a new bill: runs against a single account. Checks for the latest bill and reports whether a bill newer than your last known date exists.
  3. Fetch latest bill: per-account download that delivers exactly one bill, with extraction returning its fields as structured data.
Splitting the bill fetch into several tasks gives you a few things:
  • Per-account attribution. If a bill is missing for an account, there is one run to inspect, not a single long run across every account.
  • Retry granularity. A failed run is tightly scoped and can be retried on its own.
  • Lower cost when nothing is new. When there’s no new bill, you pay for only the task run rather than deduplication and extraction.
  • A durable account list. You store the list and drive per-account work from it. If an account disappears from a later discovery run, you notice.

Prerequisites

This guide assumes you have an agent, a source, and a stored credential; the Quickstart covers those steps. The fetch task uses storage and extraction, available as an add-on on paid plans.

Create the tasks

All three tasks belong to the same agent. See Tasks for guidance on writing prompts.
1

Extract accounts

Runs once per credential per refresh cycle, typically monthly, or on demand when a user adds or removes accounts on the source. You store the returned list. The task returns metadata only, so leave storage off.
Request
Not every source shows a bill date on the account list, so treat latest_bill_date as a hint. For an account with no known date yet, run the task that checks for a new bill, with last_known_bill_date set far enough back that any bill counts as new.
2

Check for a new bill

Runs once per account per checking cycle. It takes the account number and your last known bill date, and reports whether the source has anything newer. With storage disabled, runs of this task can’t return files, so the task stays read-only regardless of prompt wording.
Request
3

Fetch latest bill

Runs only for accounts where the previous task returned has_new_bill: true. It takes the account number alone; the decision to fetch was already made upstream. Storage and extraction are enabled, and the extraction schema pulls the bill’s fields from the file.
Request
Deduplication is optional here: the date input on the previous task already prevents most duplicate downloads. As an extra safeguard, enable deduplication keyed on the statement number and account number.

Run the sequence

You run the tasks from your own code. The task that extracts accounts runs once per cycle, the task that checks for a new bill runs for each account on your schedule, and the task that fetches the bill runs only when a newer one exists. Runs are asynchronous: you receive the output through a task_run.completed event or by polling, as in the Quickstart. The responses below show the completed runs, trimmed to the relevant fields.

Discover accounts

Run the task that extracts accounts once per credential per cycle:
Request
Response
Persist the account list keyed by account_number, alongside the last known bill date for each account. This stored state is what the per-account calls read from and write back to.

Check each account

For each account on your schedule (weekly is typical), run the task that checks for a new bill. Pass the session_id from the previous run to reuse the open session instead of logging in again:
Request
Response
When has_new_bill is false, record the result and move on. Nothing else runs for that account this cycle.

Fetch where a new bill exists

When the previous task returns has_new_bill: true, run the task that fetches the latest bill with the same session:
Request
When the run completes, the file is in storage with its extraction inline:
Response
Update the account’s stored last known bill date from bill_date, so the next check compares against it.

Session reuse

Passing session_id keeps a credential’s runs in one open environment, so the agent logs in once per cycle instead of once per call. Sessions close after 10 minutes of inactivity; see Sessions. The saved login applies to runs of the same credential, so working through a credential’s accounts sequentially in one session is the simplest approach. Starting a fresh session per account also works, at the cost of a login per account.

Schedule the work

The discovery task takes no input, so a monthly trigger can run it across every credential. The check and fetch tasks need per-account input, and a trigger has a single input shared by every run it creates, so create those runs from your own scheduler. See Inputs under fan-out.

Handle failures

Every run names one account, so a transient failure is one run to retry, not a batch to replay. The run’s errors array says what went wrong; see Errors. If the credential goes invalid (a changed password, for example), Deck emits a credential.invalid event so you can prompt the user to re-authenticate. Skip that credential’s accounts until it recovers; checks resume from the last known dates you stored.