Skip to content
Hardcount
Run it locally
Pre-1.0 · one maintainer · Stripe and cards only · no SDKs (client libraries) yet · no production users yet. Docs describe v0.9.1 (29 Oct 2026) · What’s new →

Email the invoice (PDF attached) to a recipient

POST
/v1/invoices/{id}/send
curl --request POST \
--url http://localhost:8080/v1/invoices/example/send \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "email": "hello@example.com", "additional_emails": [ "example" ] }'

Sends the invoice document email. additional_emails is tri-state (ADR-082): absent → the customer’s stored additional_emails are CC’d (so legacy {email}-only bodies now CC by default); explicit [] → primary only for this send; explicit list → validated exact override (same rules as the customer field — normalize, dedupe, not-the-recipient, cap 10).

id
required
string
Idempotency-Key
string

Makes the call safe to retry. Send a unique value (a UUID works) and the same value on every retry. For 24 hours, a repeat with the same key, method, path and body gets the first response again, with an Idempotent-Replayed: true header, instead of running again. The error cases are in docs/api-surface.md. The usage routes do not take it: each usage event carries its own idempotency_key.

Media typeapplication/json
object
email
required
string format: email
additional_emails
Array<string>
<= 10 items

Example generated

{
"email": "hello@example.com",
"additional_emails": [
"example"
]
}

Email enqueued

Media typeapplication/json
object
status
required
string
Allowed values: sent

Example

{
"status": "sent"
}

Invoice not found

Nothing was sent. Codes: email_not_configured (this server has no SMTP set up), or payment_in_flight / payment_unidentifiable (a charge on the invoice is unresolved).

Media typeapplication/json
object
error
object
type

One of invalid_request_error, authentication_error, rate_limit_error or api_error. Every error the API answers has this shape, including an unknown path (404, code route_not_found) and a method the path does not take (405, code method_not_allowed, with an Allow header). The few exceptions are listed in docs/api-surface.md.

string
code
string
message
string
request_id
string
param

The request field the error is about. Sent only when the error names one. A request body may hold only the fields its operation lists, spelled and cased as listed: any other field, or one the server sets (such as id), is refused with 422 and param naming it. An operation with no request body lists no fields: send no body, {} or null. The Stripe and Postmark webhooks and the LiteLLM callback take their sender’s body as it comes.

string

Example

{
"error": {
"type": "invalid_request_error"
}
}

email is missing or invalid, a CC entry is invalid, or the body has an unknown field (param names it)