History (report)
/api/v1/reports/historyRequest
/api/v1/reports/historycurl -X GET 'https://app.mailyte.com/api/v1/reports/history' \
-H 'Authorization: Bearer mk_live_YOUR_API_KEY'const response = await fetch('https://app.mailyte.com/api/v1/reports/history', {
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/history",
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/history');
$data = $response->json('data');require "net/http"
require "json"
uri = URI("https://app.mailyte.com/api/v1/reports/history")
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.
dataobjectdataarray<object>objectstringreport_generationidstringULID. `POST /reports/generate` used to call this `report_id` and `GET /reports/history` called it `id`, so following a report you had just queued meant knowing the two were the same field. One name now, and a generate response IS a history row.
template_idstringemail-delivery | domain-health | engagement | volume-trends | securityMatches the `id` of a row from `GET /reports/templates`. Note `security` is accepted here but is not advertised by that endpoint.
formatstringpdf | csv | jsonThe format you asked for. The job stores a JSON snapshot whichever you ask for -- PDF and CSV rendering is not built -- so this records the request, not what `result` is.
statusstringpending | processing | completed | failedPoll this. There is deliberately no `estimated_completion`: it was `now() + 30 seconds`, hardcoded and unrelated to the queue depth, the job or the report's size, so polling against it polled at the wrong time.
parametersobjectWhat the report was queued with. Always an object: it is an array cast, so it used to serialise as `[]` when empty and `{}` otherwise, and a field whose JSON type changes with its contents is unusable from a typed language.
errorstringWhy the build failed. Non-null only when `status` is `failed`. NULL MEANS NONE -- there is no error -- not that we lost the reason: the only two writers (`GenerateReportJob::handle()` and its `failed()` hook) set `status` and `error` in the same update, so a `failed` row always carries one and no other status ever does.
resultanyThe stored report, rendered through the SAME resource the live endpoint uses, so the vocabulary is identical whether you read a report live or out of history. Returning the raw snapshot would have re-published `total_volume`, `bounce_rate`, `total_sent` and the rest through the back door. Null while the job is queued, when it failed, and for a template we have no resource for. Its `period` is always null -- a snapshot keeps no record of the window it covered.
requested_atstringWhen the build was ASKED for (`created_at`), which is what a caller polling a queue cares about. NULL MEANS UNKNOWN -- we do not know when it was requested -- and never "it has not been requested yet": the row exists only because somebody requested it. `report_generations.created_at` is a NULLABLE timestamp column (Laravel's `timestamps()` default), so a row written without touching the timestamps has none. Do not sort a queue on this field without handling the null.
completed_atstringWhen the build finished, and it is only ever written on SUCCESS. Read it against `status`: while `pending` or `processing`, null means NOT YET; when `failed`, null means NONE and it will stay null forever, because the job's `failed()` hook sets `status` and `error` and never a finish time. So a null here is not a way to tell a running build from a dead one -- `status` is.
pagination_metaany
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.