Discovery

A bare key is enough to start. Two calls turn it into a context: which organization it opens, with which role, and what is already there.

Telling a production key from a test one

A key carries no label saying which environment it belongs to. What it carries is an organization, and that is the thing to assert: compare organization.slug — or organization.id — against what your integration expects, and stop if they differ.
bash
ORG=$(curl -s -H "x-api-key: $AGENTMAIL_API_KEY" \
  "https://www.agentsmail.io/api/v1/me" | jq -r '.data.organization.slug')

[ "$ORG" = "acme-staging" ] || { echo "wrong organization: $ORG"; exit 1; }
One call, at start-up, and it is the whole distance between a rehearsal and a real audience. An agent that skips it finds out where it was pointed after the send.

The bootstrap sequence

1

Find out where you are

bash
curl -s -H "x-api-key: $AGENTMAIL_API_KEY" \
  "https://www.agentsmail.io/api/v1/me" | jq '.data'
Assert the organization is the one you meant, and read role: member means every write below will answer 403.
2

Pick the list

bash
LIST_ID=$(curl -s -H "x-api-key: $AGENTMAIL_API_KEY" \
  "https://www.agentsmail.io/api/v1/lists" | jq -r '.data[] | select(.name == "Newsletter") | .id')
An empty answer means the organization has no list yet — create one with POST /api/v1/lists, see Audience.
3

Work the audience

bash
curl -s -H "x-api-key: $AGENTMAIL_API_KEY" \
  "https://www.agentsmail.io/api/v1/contacts?listId=$LIST_ID&status=subscribed"
Everything about contacts and tags — reading, adding, importing a batch, unsubscribing — is on Audience. GET /api/v1/tags is the same trick as /lists, for tag ids.
4

Compose and send

bash
curl -s -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
  -d '{"name":"August newsletter","subject":"What shipped in August","templateId":"'$TEMPLATE_ID'","listId":"'$LIST_ID'"}' \
  "https://www.agentsmail.io/api/v1/campaigns"
Templates, rendering, campaigns and the send itself are on Content & Send, which walks the whole path end to end.
Two calls of context, and the rest of the API answers. Nothing here is stored on your side: an agent that starts every run with /me and /lists never works from a stale id.