Know what happened to every invoice
Each invoice records when it was sent, first opened and paid, and turns overdue on its own when the due date passes with money still owed.
Invoice tracking in ASHDOCS is part of every invoice rather than an add-on. When the email is delivered the status becomes sent, when your customer opens the hosted page it becomes viewed, and a payment makes it partially paid or paid.
A background job checks every minute for invoices past their due date with a balance left and marks them overdue. You can follow all of it in the dashboard, read it from the API, or, on paid plans, receive each change as a signed webhook.
curl "https://www.ashdocs.com/api/v1/invoices/inv_5b4384cd4b224b129b0c?include=events" \
-H "X-API-Key: ash_test_..."const res = await fetch(
"https://www.ashdocs.com/api/v1/invoices/inv_5b4384cd4b224b129b0c?include=events",
{ headers: { "X-API-Key": "ash_test_..." } },
);
const invoice = await res.json();
console.log(invoice.status, invoice.first_viewed_at, invoice.events.map((e) => e.type));import requests
res = requests.get(
"https://www.ashdocs.com/api/v1/invoices/inv_5b4384cd4b224b129b0c",
params={"include": "events"},
headers={"X-API-Key": "ash_test_..."},
)
invoice = res.json()
print(invoice["status"], invoice["first_viewed_at"], [e["type"] for e in invoice["events"]]){
"id": "inv_5b4384cd4b224b129b0c",
"number": "INV-0004",
"status": "viewed",
"customer": {
"name": "Acme Inc",
"email": "ap@acme.com"
},
"due_date": "2026-11-04",
"totals": {
"total_formatted": "$487.13",
"paid_formatted": "$0.00",
"balance_minor": 48713,
"balance_formatted": "$487.13"
},
"hosted_url": "https://api.ashdocs.com/i/<hosted_token>",
"issued_at": "2026-10-05T13:45:10.376000",
"sent_at": "2026-10-05T13:45:41.102000",
"first_viewed_at": "2026-10-06T08:12:09.554000",
"paid_at": null,
"events": [
{
"id": "evt_2f0c6b1d9e8a4c7b5a31",
"type": "invoice.created",
"at": "2026-10-05T13:45:10.355000+00:00"
},
{
"id": "evt_8a41d3c2b7e94f06a1c2",
"type": "invoice.issued",
"at": "2026-10-05T13:45:10.376000+00:00"
},
{
"id": "evt_c93e7f10a2b64d58e7f4",
"type": "invoice.sent",
"at": "2026-10-05T13:45:41.102000+00:00"
},
{
"id": "evt_5d27b8e6f1c04a39b0d8",
"type": "invoice.viewed",
"at": "2026-10-06T08:12:09.554000+00:00"
}
]
}Response with include=events, trimmed; values illustrative.
Statuses set by real events
sent_at, first_viewed_at and paid_at are filled by what actually happens: a successful delivery, an opened hosted page, a recorded payment. Overdue comes from the due date and the balance.
Webhooks, Slack and Teams
On paid plans, invoice.sent, invoice.viewed, invoice.paid and invoice.overdue reach your endpoint as signed webhooks. Slack and Microsoft Teams alerts cover paid and overdue by default, with viewed as an option.
Reminders that stop when paid
By default reminders are emailed 3 days before, on, and 7 days after the due date at 09:00 in your timezone, and they stop as soon as the invoice is paid or voided.
How invoice tracking works
Each status change is triggered by something you can point to. A delivery that fails, including a bounced email, is recorded and fires invoice.delivery_failed instead. A view is the first time someone other than you opens the hosted page: link scanners and preview bots such as Outlook Safe Links, Proofpoint and Slackbot are ignored, and the Open hosted page button in your dashboard does not count. Reopening the page later does not fire the event again.
| Status | Set when | Event |
|---|---|---|
| sent | The first delivery to the customer succeeds | invoice.sent |
| viewed | The customer first opens the hosted page | invoice.viewed |
| partially_paid | A payment covers part of the balance | invoice.partially_paid |
| paid | Payments cover the whole balance | invoice.paid |
| overdue | The due date has passed and a balance is left | invoice.overdue |
In the dashboard
The invoice list opens with four tiles per currency: overdue, due in the next 30 days, paid this month, and drafts. Each tile filters the list, and you can also filter by any status and search by number, customer name, reference or PO number.
Open an invoice to see its timeline of events, a Deliveries tab with every attempt by channel and its result, and the PDF preview. When a payment link could not be created, for example because Stripe is not connected, the invoice list flags it so you can fix the connection and re-create the link.
From the API
Everything in the dashboard is available to your own code with the same API key.
- GET /api/v1/invoices?status=overdue lists overdue invoices, newest first; add summary=1 for the same totals as the dashboard tiles.
- GET /api/v1/invoices/{invoice_id}?include=events returns the invoice with its event timeline.
- GET /api/v1/invoices/{invoice_id}/deliveries lists delivery attempts.
- POST /api/v1/invoices/{invoice_id}/remind sends a reminder now.
- GET /api/v1/invoices/export.csv exports every invoice for reporting.
Webhooks and chat alerts
Webhooks are on paid plans. Each delivery is a POST with a JSON body of event, data and delivered_at, an X-ASHDOCS-Event header, and an X-ASHDOCS-Signature header holding sha256= and the HMAC-SHA256 of the raw body keyed with your endpoint's secret. For invoice events, data carries the event id, type, time and the full invoice.
Slack and Microsoft Teams alerts are set up under Integrations in the invoicing dashboard. Each message names the invoice and links to its hosted page; overdue and part-payment alerts include the balance due.
Frequently asked questions
How do I track whether an invoice was viewed?
Send the invoice with its hosted page link (the default email includes it). When the customer opens the page, first_viewed_at is set, the status moves to viewed and invoice.viewed fires once; link scanners, preview bots and your own opens from the dashboard are not counted. A PDF opened from the email attachment cannot be tracked, only the hosted page.
What is invoice tracking software?
It records what happens to each invoice after you send it: whether it was delivered, opened, paid in full or in part, or has gone past its due date. ASHDOCS does this for every invoice it issues, in the dashboard and through the API, with no separate tool to connect.
Can I get a Slack message when an invoice is paid?
Yes. Add Slack under Integrations in the invoicing dashboard, with an incoming-webhook URL or with your Slack connection and a channel, and paid and overdue alerts are posted there by default with a link to the hosted invoice. Microsoft Teams works the same way through a Teams incoming-webhook URL, and alerts for views, part payments and failed deliveries can be switched on as well.
How are overdue invoices detected?
A background job runs every minute and marks an invoice overdue when its due date is before today in your account's timezone and a balance is still owed. It fires invoice.overdue once, and reminders continue on their schedule until the invoice is paid or voided.
Plans
- 100 credits per month
- 1 seat
- No webhooks
- 1,500 credits per month
- 1 seat
- Webhooks
- 10,000 credits per month
- 3 seats
- Webhooks
- 30,000 credits per month
- 5 seats
- Webhooks
- 100,000 credits per month
- 10 seats
- Webhooks
Test keys are free, never expire and never use credits; plan rate limits apply. Webhooks are on paid plans. Issuing an invoice uses 1 credit. No per-seat fees. See full pricing.