Skip to content

Use cases · Published 2026-09-29 · AgentiSend team

Receipts from a store agent

A store agent sends a receipt after a payment. The key's ceiling is a monthly count, and each address on the message counts as one.

A store agent sends one receipt after a payment that has already happened, to the address on that order. The message is transactional: it confirms the amount, the order, and where the full receipt lives.

The ceiling

Set the key before the route below runs. PATCH /limits/keys/{id} accepts only budget_per_period, period and rate_ceiling_per_minute. This job uses:

{
  "budget_per_period": 400,
  "period": "monthly",
  "rate_ceiling_per_minute": 20
}

Four hundred is under a Free plan's 1,000 a month, and twenty a minute is under the default 600. A key cannot raise either. The budget period stays monthly.

The send

"""Flask: one POST route that sends an order receipt.

    POST /send  {"email": "ada@example.com", "order_id": "1042"}
    200         {"id": "..."}                     accepted
    400         {"error": "..."}                  not one address; the API was not called
    4xx/5xx     {"code": "...", "fix": "..."}     the API refused, and says what to do

Environment: AGENTISEND_API_KEY (a key with sending_access), MAIL_FROM (an
address on a domain you have verified), and optionally AGENTISEND_BASE_URL.
Run: flask --app app run
"""

from __future__ import annotations

import os
import re

from flask import Flask, jsonify, request

from agentisend import AgentiSend, AgentiSendError, idempotency_key

agentisend = AgentiSend()  # reads AGENTISEND_API_KEY and AGENTISEND_BASE_URL
MAIL_FROM = os.environ["MAIL_FROM"]

# One address, no spaces, a dot in the domain. The API checks properly; this
# only stops a form typo from costing a request.
ADDRESS = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")

app = Flask(__name__)


@app.post("/send")
def send():
    body = request.get_json(silent=True) or {}
    email = str(body.get("email", "")).strip()
    order_id = str(body.get("order_id", "")).strip()
    if not ADDRESS.match(email):
        return jsonify(error="email must be one address, like you@example.com"), 400
    if not order_id:
        return jsonify(error="order_id is required"), 400

    try:
        sent = agentisend.send_email(
            {
                "from": MAIL_FROM,
                "to": email,
                "subject": f"Receipt for order {order_id}",
                "text": f"Thanks for your order. Order {order_id} is paid.",
            },
            # One receipt per order, whoever asks and however often: a retry
            # after a timeout replays the first send instead of mailing twice.
            idempotency=idempotency_key("receipt", order_id),
        )
    except AgentiSendError as err:
        return jsonify(code=err.code, fix=err.fix), err.status
    return jsonify(id=sent["id"])
examples/flask/app.py, run by the test suite against a local AgentiSend server

The starter for the message itself is Receipt.

The refusal

An address that hard-bounced before is on the suppression list. The send is refused and nothing is delivered:

{
  "error": {
    "code": "suppressed_recipient",
    "message": "Recipient is on the account suppression list.",
    "fix": "GET /suppressions says which address and why. A hard bounce you have fixed can be cleared with DELETE /suppressions/:id; an unsubscribe or a spam complaint cannot — that address asked not to be contacted.",
    "docs_url": "https://agentisend.com/what-does-suppressed-recipient-mean#suppressed_recipient",
    "retryable": false
  }
}

Honest limit

Each To, Cc and Bcc address counts as one email against the key and against the plan inclusion. A scheduled receipt is counted when it is accepted. Cancelling it before it sends gives that count back.

Next