Email Delivery (report)
/api/v1/reports/email-deliveryRequest
/api/v1/reports/email-deliverycurl -X GET 'https://app.mailyte.com/api/v1/reports/email-delivery' \
-H 'Authorization: Bearer mk_live_YOUR_API_KEY'const response = await fetch('https://app.mailyte.com/api/v1/reports/email-delivery', {
method: 'GET',
headers: {
Authorization: 'Bearer mk_live_YOUR_API_KEY',
},
});
const { data } = await response.json();import requests
response = requests.get(
"https://app.mailyte.com/api/v1/reports/email-delivery",
headers={"Authorization": "Bearer mk_live_YOUR_API_KEY"},
)
data = response.json()["data"]<?php
$response = Http::withToken('mk_live_YOUR_API_KEY')
->get('https://app.mailyte.com/api/v1/reports/email-delivery');
$data = $response->json('data');require "net/http"
require "json"
uri = URI("https://app.mailyte.com/api/v1/reports/email-delivery")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer mk_live_YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }Response
Success.
dataobjectobjectstringemail_delivery_reportgenerated_atstringWhen this response was computed, ISO 8601 UTC. Every report answers it, so "is this figure stale?" never depends on which report you asked.
periodobjectThe window this report actually covers, which is not always the window you asked for: a `date_range` outside `day`, `week`, `month` and `quarter` is silently replaced with `month`, so a request for `year` returns thirty days and this object is the only place that says so. Null when the report covers no window -- a stored result read back from `/reports/history` keeps no record of the window it was built over, and inventing one from your current query would describe the query rather than the data.
start_atstringend_atstringgranularitystringdayThe width of one `series` bucket. Always `day`: the `granularity` query parameter is accepted and ignored.
totalsobjectThe counts for the whole period. No rates: every rate this endpoint used to publish was arithmetic over counts sitting beside it, and two fields that can disagree -- which rounding guarantees -- are a bug report waiting to be filed. The counts are published; divide them yourself.
sentintegerEvery delivery event recorded in the window: delivered, bounced, deferred, rejected and dropped. It is NOT `delivered + bounced + failed` -- deferrals are counted in and are broken out nowhere in the response, so `sent` is normally larger than the three figures beside it. Null means the figure is unavailable, never that it is zero.
deliveredintegerMessages a receiving server accepted (`email.delivered`). This is the denominator to divide the engagement counts by. Null means the figure is unavailable, never that it is zero.
bouncedintegerMessages a receiving server refused (`email.bounced`). Null means the figure is unavailable, never that it is zero.
failedintegerPermanent non-delivery: rejected plus dropped. A deferral is a retry, not a failure, and is not counted here. Null means the figure is unavailable, never that it is zero.
seriesarray<object>The same counts bucketed over the period, oldest first. Rows are SPARSE: a bucket in which nothing happened has no row at all, rather than a row of zeros, so do not index this array by day offset.
start_atstringThe instant this bucket opens, midnight UTC. Replaces the bare `2026-09-17` these rows used to carry, which named no timezone. NULL MEANS UNKNOWN -- we could not read this bucket's boundary -- and never that the bucket has no start or is empty. A LIVE report cannot produce it: the rows are grouped by `delivery_events.created_at`, which is NOT NULL, so every bucket is keyed by a real date. It is reachable only through `GET /reports/history`, where the row is JSON written by whichever version of the report ran at the time and re-rendered through this same resource WITHOUT being re-validated; a stored row carrying no date becomes null here rather than being silently dated today. Drop such a row or read the report live.
sentintegerEvery delivery event recorded in the window: delivered, bounced, deferred, rejected and dropped. It is NOT `delivered + bounced + failed` -- deferrals are counted in and are broken out nowhere in the response, so `sent` is normally larger than the three figures beside it. Null means the figure is unavailable, never that it is zero.
deliveredintegerMessages a receiving server accepted (`email.delivered`). This is the denominator to divide the engagement counts by. Null means the figure is unavailable, never that it is zero.
bouncedintegerMessages a receiving server refused (`email.bounced`). Null means the figure is unavailable, never that it is zero.
failedintegerPermanent non-delivery: rejected plus dropped. A deferral is a retry, not a failure, and is not counted here. Null means the figure is unavailable, never that it is zero.
bounce_reasonsarray<object>The ten most frequent bounce reasons in the window, most frequent first. There is no `percentage` on a row: it was `count / bounced`, and both numbers are already in this response.
reasonstringThe reason as the bounce event reported it. `unknown` is a real value here, not a null: it groups bounces whose payload carried no `bounce_reason`, and dropping them would make these counts fail to add up to `totals.bounced`.
countintegerBounces in the window with this reason. Null means the figure is unavailable, never that it is zero.
Returned inside the standard envelope.
Errors
| Status | When |
|---|---|
401 | The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist. |
403 | The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys. |
404 | No such resource in this organization. |
422 | The request was understood but the values were not acceptable. |
429 | Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait. |
Every status, with what causes it and what to do, is on the error reference.