---
title: "Get the email indicators of several entities"
method: GET
path: "/v1/accounts/{account_id}/email-indicators"
tags: ["AccountEmails"]
---

# Get the email indicators of several entities

`GET /v1/accounts/{account_id}/email-indicators`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/accounts/{account_id}/email-indicators`
- Auth: HTTP bearer

Returns, for each related entity id given, how many emails the history holds for it, the
status of the most recent one and when it was sent. Lets you show the state of an entity's
email without loading its full history.

- **`last_status`:** carries whatever the latest attempt ended in, `REJECTED` and `QUEUED`
  included, so a `count` above zero does not mean an email reached anyone.
- **Ids with no associated emails:** omitted from the response rather than returned with
  `count` 0.

**Closed catalogue.** This collection is fixed and bounded by the request itself — at most
one indicator per id in `related_entity_ids`: it carries no `pagination`, it takes no
`page`/`limit`, and every response holds the whole set.

## Query parameters

- `related_entity_ids` string[], required

## Response `200`

Indicators retrieved successfully

- EmailDeliveryIndicatorListResponse
  - `success` boolean, required
  - `data` object, required
    - `indicators` EmailDeliveryIndicator[], required
      - `related_entity_id` string, uuid, required: Id of the related entity (e.g. invoice_id)
      - `count` integer, required: Number of emails recorded for the entity, whatever their outcome
      - `last_status` 'QUEUED' | 'REJECTED' | 'SENT' | 'FAILED' | 'DELIVERED' | 'BOUNCED' | 'OPENED': Status of an email. The history records every email the system decided to send, not only the ones that went out: an email stopped by policy is listed as REJECTED rather than omitted. - QUEUED: authorised and recorded, not dispatched yet - REJECTED: stopped by policy and never sent (terminal, not retried). In test environments invoices may only be emailed to the account owner's own address (`+tag` aliases included), so a message addressed elsewhere lands here - SENT: successfully sent to the provider - FAILED: sending failed - DELIVERED / BOUNCED / OPENED: reported by the provider's webhooks
      - `last_sent_at` string, date-time: Time of the last email sent for the entity
  - `meta` ResponseMeta
    - `timestamp` string, date-time
    - `request_id` string

## Other responses

- `400`: The request target could not be read as declared, so nothing was looked up. Three causes, all named in `error.details`: a path or query parameter whose value does not parse as its type (`VALIDATION_ERROR` — a UUID that is not a UUID, an unknown enum value, an empty element in a list such as `status=ISSUED,`), a required parameter that was not sent (`MISSING_PARAMETER`), or a header that is meant to carry an identifier and does not (`ACTIVE_COMPANY_HEADER_INVALID`). A list parameter sent entirely empty (`status=`) is not an error: it is the same as omitting it. The fault is in the target, not in the content — which is what `422` is defined over.
- `401`: Missing or invalid authentication. Like every other error, `message`/`detail` is localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the header is missing or asks for none of those.
- `403`: The credential cannot reach the account in the path, or lacks the `emails:read` scope. An account you cannot reach and an account that does not exist answer identically.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `default`: Any status code the operation does not list above. Every operation declares it, so a generated client always has a branch to fall into and never loses the cause of a failure it did not anticipate. This is where the transport-level answers land — `405`, `406`, `415` and `429` — together with any status a future version of the API starts returning. All of them carry the same error envelope as the codes listed explicitly, so `error.code` is what tells them apart: switching on the status code alone is not enough. See «Transport-level errors» in the API description for when each one is produced. A `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the operation depends on failed or did not answer in time. It is a transient condition — retry with the same `Idempotency-Key` where the operation accepts one. One exception to the envelope: a failure of the network edge that never reaches the application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not BeeL's — it may not even be JSON. Treat those as "no answer", and retry.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
