> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minimo.it/llms.txt
> Use this file to discover all available pages before exploring further.

# Get One-Shot Email Statistics

> Poll delivery, open, and click metrics for a single HTML email sent via the one-shot endpoint

## Overview

After dispatching an email through [`POST /public/v1/emails`](/api-reference/messaging-channels/email/send-html), use the returned `id` (or the full `statsUrl`) to read back delivery and engagement metrics for that **single** delivery.

Unlike the template-stats endpoint, these numbers refer to **one recipient and one HTML payload** — not aggregated counters across a campaign.

<Tip>
  The endpoint is scoped to your company. IDs that belong to a different company return `404`, never another tenant's
  data.
</Tip>

## Request

```bash theme={null}
curl --request GET \
  --url https://api.minimo.it/public/v1/emails/DMPNEF8/stats \
  --header 'Authorization: Bearer mn-{apiClientId}-{secret}'
```

## Response Example

```json theme={null}
{
  "data": {
    "id": "DMPNEF8",
    "status": "sent",
    "to": "customer@example.com",
    "subject": "Your receipt",
    "sentAt": "2026-05-19T10:30:00Z",
    "opened": true,
    "firstOpenAt": "2026-05-19T10:32:14Z",
    "clickCount": 2,
    "firstClickAt": "2026-05-19T10:33:05Z",
    "failureReason": null
  }
}
```

## Field Reference

| Field           | Type                              | Description                                                                 |
| --------------- | --------------------------------- | --------------------------------------------------------------------------- |
| `id`            | `string`                          | Echo of the opaque sqid id returned by the POST endpoint.                   |
| `status`        | `"pending" \| "sent" \| "failed"` | Lifecycle state of the delivery.                                            |
| `to`            | `string`                          | Recipient address as it was sent.                                           |
| `subject`       | `string`                          | Subject line as it was sent.                                                |
| `sentAt`        | `date-time`                       | When the delivery row was created (queue-in time, not provider acceptance). |
| `opened`        | `boolean`                         | `true` once the tracking pixel has been fetched at least once.              |
| `firstOpenAt`   | `date-time \| null`               | Timestamp of the first open; `null` until the pixel is fetched.             |
| `clickCount`    | `integer`                         | Total number of clicks across all tracked links in the email.               |
| `firstClickAt`  | `date-time \| null`               | Timestamp of the earliest tracked click; `null` until the first click.      |
| `failureReason` | `string \| null`                  | Populated when `status = "failed"` — the provider's rejection reason.       |

## How the Counters Are Updated

* **Open**: triggered the first time the recipient's email client fetches the embedded `<img>` open-pixel. Image proxies (Gmail, Apple Mail Privacy Protection) trigger this immediately on arrival, which inflates open rates compared to pre-2021 baselines.
* **Click**: every fetch of a rewritten `/api/click/...` URL appends a row to the click ledger. `clickCount` is the cardinality of that ledger; `firstClickAt` is its minimum timestamp.

Both signals are **per delivery**: opens and clicks tied to a different `id` do not affect this row.

## Use Cases

<AccordionGroup>
  <Accordion title="Confirm a magic link landed">
    After sending a sign-in email, poll the stats endpoint to surface "Email opened by recipient" in your internal dashboard.

    ```javascript theme={null}
    const { data: stats } = await fetch(`https://api.minimo.it/public/v1/emails/${id}/stats`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    }).then((r) => r.json());

    if (stats.opened) {
      console.log(`Magic link opened at ${stats.firstOpenAt}`);
    }
    ```
  </Accordion>

  <Accordion title="Detect failed deliveries in a queue worker">
    When `status === "failed"`, persist `failureReason` against the originating business object so support can react.

    ```javascript theme={null}
    const { data: stats } = await getEmailStats(id);
    if (stats.status === 'failed') {
      await logDeliveryFailure({ id, reason: stats.failureReason });
    }
    ```
  </Accordion>

  <Accordion title="Attribute a CTA click back to the trigger">
    The first click timestamp lets you measure end-to-end latency from "we sent it" to "user acted."

    ```javascript theme={null}
    const { data: stats } = await getEmailStats(id);
    if (stats.firstClickAt) {
      const sentAt = new Date(stats.sentAt);
      const clickedAt = new Date(stats.firstClickAt);
      const minutesToFirstClick = (clickedAt - sentAt) / 60000;
      track('email_click_latency_minutes', minutesToFirstClick);
    }
    ```
  </Accordion>
</AccordionGroup>

## Common Errors

| Status | Cause                                                                                              |
| ------ | -------------------------------------------------------------------------------------------------- |
| `401`  | API key missing or malformed.                                                                      |
| `403`  | API key lacks the `TRANSACTIONAL` permission.                                                      |
| `404`  | The `id` doesn't exist, or it belongs to a different company than the one this API key authorizes. |

## Polling Guidance

* **Open events**: usually surface within seconds for image-proxied clients (Gmail, Apple Mail Privacy Protection). For other clients, wait until the recipient actually opens the message.
* **Click events**: stored synchronously the moment the rewritten URL is fetched — they appear in the next stats response.
* **Rate**: a steady cadence of one poll every 30–60 seconds for the first \~10 minutes is plenty. Aggressive polling won't surface data faster.

## Related Endpoints

* [Send One-Shot HTML Email](/api-reference/messaging-channels/email/send-html) — the producer side of these statistics
* [Get Email Template Stats](/api-reference/messaging-channels/email/stats) — aggregated stats for template-backed sends


## OpenAPI

````yaml get /public/v1/emails/{id}/stats
openapi: 3.1.0
info:
  title: API Documentation
  description: Documentation for transactional and subscribe APIs
  version: 1.0.0
servers:
  - url: https://app.minimo.it
security:
  - bearerAuth: []
paths:
  /public/v1/emails/{id}/stats:
    servers:
      - url: https://api.minimo.it
    get:
      summary: Retrieve one-shot email statistics
      description: |
        Returns send status plus open/click metrics for a single delivery,
        identified by the sqid returned from `POST /public/v1/emails`.
        Scoped to the calling company — IDs that belong to other companies
        return 404.

        `opened` flips to `true` after the recipient fetches the tracking
        pixel for the first time. `clickCount` is the total number of
        clicks across all tracked links in the message; `firstClickAt`
        is the timestamp of the earliest click.
      operationId: getHtmlEmailStats
      parameters:
        - name: id
          in: path
          required: true
          description: Opaque sqid id returned by `POST /public/v1/emails`.
          schema:
            type: string
            example: DMPNEF8
      responses:
        '200':
          description: Statistics for the delivery.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        example: DMPNEF8
                      status:
                        type: string
                        enum:
                          - pending
                          - sent
                          - failed
                      to:
                        type: string
                        format: email
                      subject:
                        type: string
                      sentAt:
                        type: string
                        format: date-time
                        description: When the delivery row was created.
                      opened:
                        type: boolean
                        description: >-
                          True once the tracking pixel has been fetched at least
                          once.
                      firstOpenAt:
                        type: string
                        format: date-time
                        nullable: true
                        description: Timestamp of the first open; `null` if never opened.
                      clickCount:
                        type: integer
                        description: Total clicks recorded across all tracked links.
                      firstClickAt:
                        type: string
                        format: date-time
                        nullable: true
                        description: Timestamp of the first click; `null` if no clicks.
                      failureReason:
                        type: string
                        nullable: true
                        description: Populated when `status = "failed"`.
              examples:
                sentNotOpened:
                  summary: Sent but not yet opened
                  value:
                    data:
                      id: DMPNEF8
                      status: sent
                      to: customer@example.com
                      subject: Your receipt
                      sentAt: '2026-05-19T10:30:00Z'
                      opened: false
                      firstOpenAt: null
                      clickCount: 0
                      firstClickAt: null
                      failureReason: null
                openedAndClicked:
                  summary: Opened and clicked
                  value:
                    data:
                      id: DMPNEF8
                      status: sent
                      to: customer@example.com
                      subject: Your receipt
                      sentAt: '2026-05-19T10:30:00Z'
                      opened: true
                      firstOpenAt: '2026-05-19T10:32:14Z'
                      clickCount: 2
                      firstClickAt: '2026-05-19T10:33:05Z'
                      failureReason: null
        '401':
          description: Missing or invalid API key.
        '403':
          description: API key lacks the `TRANSACTIONAL` permission.
        '404':
          description: Delivery not found, or it belongs to a different company.
      security:
        - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: mn-API_CLIENT_ID-API_KEY

````