Search the docs

Find a page, a section, or an endpoint.

Pods

Every pods endpoint, generated from the API's own schemas.

List pods

get/api/v1/pods

The containers in this account, the default first. A pod holds addresses and domains — a customer of yours, a client, or just test apart from production. **Each pod has its own sending reputation**, so bounces from one customer cannot degrade delivery for another — mail sends under the pod its address is in, whichever domain it is on. A pod key (`pod_id` on `POST /api-keys`) reaches one pod and nothing else. Not paged: this is a menu somebody switches with, and a product where that menu needs a cursor is one where the menu was the wrong shape.

Responses

  • 200Every pod.
  • 400The request is not valid. `error.field` names the input at fault when there is one.
  • 401No API key, or one that is not valid.
  • 403Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
  • 404No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
  • 409It conflicts with what is there: it already exists, or the `etag` you sent is not the current one.
  • 429Rate limited. `X-RateLimit-Reset` says when to retry.
  • 500Something went wrong on our side. Retry; if it keeps happening, tell us.
  • 503Something this needs is not answering right now. Retry in a moment.
bash
curl https://pidgeon.ai/api/v1/pods \
  -H "Authorization: Bearer $PIDGEON_API_KEY"

Generated · public/openapi.json

Create a pod

post/api/v1/pods

Name it after whatever it holds — a customer, an environment. `client_id` is your own id for it, carried and never parsed, and has to be unique within the account so that looking one up by it has an answer. **Provisioning in one call.** Pass `address` to create an address in the new pod (the same fields as `POST /identities`) and `key` to mint a pod key: a key that reaches the pod’s addresses, now and later, and nothing else. All of it is made or none of it is. Needs a live key over the whole account; a test key gets 403, and `key.test` mints a test key for the pod instead. **The token is shown once.** Send an `Idempotency-Key`: a retry with it returns the same pod, address and key, with `token: null`, because the secret is never stored. If the first answer was lost, rotate the key (`POST /api-keys/{id}/rotate`) for a new secret.

Parameters

  • Idempotency-Keystring

    Any string unique to this attempt, reused on its retries. A repeat with the same key and the same request returns the first answer with `Idempotent-Replay: true` and does nothing — no second email. The same key with a different request is a `409`. Kept for 24 hours; a failure is not kept, so a retry after one runs.

Body

  • namestringrequired
  • client_idstring | null

    Your own id for this pod. Carried and returned, never parsed.

  • addressobject

    An address to create in the new pod. The same fields as `POST /identities`.

  • keyobject

    A key for the new pod, reaching its addresses and nothing else. Its token is in this response once; a replay returns the key with `token: null`.

Responses

  • 201The pod, with its address and key.
  • 400The request is not valid. `error.field` names the input at fault when there is one.
  • 401No API key, or one that is not valid.
  • 402Your plan does not include this. `error.message` says what does.
  • 403Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
  • 404No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
  • 409This `Idempotency-Key` was used with a different request, or that request is still running. Nothing was sent by this call.
  • 429Rate limited. `X-RateLimit-Reset` says when to retry.
  • 500Something went wrong on our side. Retry; if it keeps happening, tell us.
  • 503Something this needs is not answering right now. Retry in a moment.
bash
curl https://pidgeon.ai/api/v1/pods \
  -X POST \
  -H "Authorization: Bearer $PIDGEON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

Generated · public/openapi.json

Fetch one pod

get/api/v1/pods/{id}

Parameters

  • idstringrequired

Responses

  • 200The pod.
  • 400The request is not valid. `error.field` names the input at fault when there is one.
  • 401No API key, or one that is not valid.
  • 403Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
  • 404No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
  • 409It conflicts with what is there: it already exists, or the `etag` you sent is not the current one.
  • 429Rate limited. `X-RateLimit-Reset` says when to retry.
  • 500Something went wrong on our side. Retry; if it keeps happening, tell us.
  • 503Something this needs is not answering right now. Retry in a moment.
bash
curl https://pidgeon.ai/api/v1/pods/{id} \
  -H "Authorization: Bearer $PIDGEON_API_KEY"

Generated · public/openapi.json

Rename a pod, or change its client id

patch/api/v1/pods/{id}

Parameters

  • idstringrequired

Body

  • namestring
  • client_idstring | null

    Your own id for this pod. Carried and returned, never parsed.

Responses

  • 200The pod.
  • 400The request is not valid. `error.field` names the input at fault when there is one.
  • 401No API key, or one that is not valid.
  • 403Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
  • 404No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
  • 409It conflicts with what is there: it already exists, or the `etag` you sent is not the current one.
  • 429Rate limited. `X-RateLimit-Reset` says when to retry.
  • 500Something went wrong on our side. Retry; if it keeps happening, tell us.
  • 503Something this needs is not answering right now. Retry in a moment.
bash
curl https://pidgeon.ai/api/v1/pods/{id} \
  -X PATCH \
  -H "Authorization: Bearer $PIDGEON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

Generated · public/openapi.json

Delete a pod, its addresses and their mail

delete/api/v1/pods/{id}

**This deletes customer data and cannot be undone.** It revokes every key of the pod, and every key those minted, then deletes each address in the pod with all of its mail, then the pod. A pod that still holds an address is refused with 409 unless you pass `delete_addresses=true`. The default pod and a pod holding a domain are always refused: delete the domain first. Needs a live key over the whole account. If it fails part way, call it again: it carries on from where it stopped. To keep the mail, suspend the addresses (`PATCH /identities/{id}`) or move them to another pod instead.

Parameters

  • idstringrequired
  • delete_addressesenum

    true · false

Responses

  • 200What was deleted.
  • 400The request is not valid. `error.field` names the input at fault when there is one.
  • 401No API key, or one that is not valid.
  • 403Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
  • 404No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
  • 409It conflicts with what is there: it already exists, or the `etag` you sent is not the current one.
  • 429Rate limited. `X-RateLimit-Reset` says when to retry.
  • 500Something went wrong on our side. Retry; if it keeps happening, tell us.
  • 503Something this needs is not answering right now. Retry in a moment.
bash
curl https://pidgeon.ai/api/v1/pods/{id} \
  -X DELETE \
  -H "Authorization: Bearer $PIDGEON_API_KEY"

Generated · public/openapi.json