Sign in Create account
API reference

Request logs API

The record of every request made with an API key and of every message sent over SMTP.

Every request made with an API key, and every message received over SMTP, is recorded with the body that was sent and the response. Attachment contents and texts longer than 5,000 characters are truncated. Requests made from the dashboard are not included in the logs. Logs are kept for 30 days. An SMTP send shows up with method SMTP and endpoint /smtp: the body carries the sender, the envelope recipients, the subject, the size and the number of attachments, and the response carries the email id (or the reason for the refusal).

#List logs

GET/logs

Full-access key

Query parameters

  • limitinteger
    From 1 to 100. Default: 20.
  • afterstring
    Cursor for the next page.
  • beforestring
    Cursor for the previous page.
  • statusstring
    HTTP statuses or ranges separated by commas, such as 4xx,500.
  • methodstring
    Methods separated by commas, such as POST,PATCH. SMTP sends use the SMTP method.
  • sourcestring
    api or smtp.
  • user_agentstring
    Part of the User-Agent.
  • api_key_idstring
    Only requests made with one key.
  • searchstring
    Searches the path, such as /emails/batch.
  • start_datestring
    From this date (ISO 8601, inclusive). With no time zone, UTC applies.
  • end_datestring
    Up to this date (ISO 8601, inclusive). With only the date, it covers the whole day. If it comes before start_date, the response is 422. See the date filters.

Errors

  • 422validation_error
    A field is invalid. The message says which one.
GET /logs

cURL

curl 'https://api.postal.so/logs?status=4xx&source=api' \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/logs?status=4xx&source=api', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/logs",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    params={
        "status": "4xx",
        "source": "api",
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('logs', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'query' => [
        'status' => '4xx',
        'source' => 'api',
    ],
]);

$data = json_decode($response->getBody(), true);
200Response
{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "id": "019a1b2d-0000-7b11-a2c3-d4e5f6a7b8c9",
      "created_at": "2026-10-24T13:02:11.000000Z",
      "endpoint": "/emails",
      "method": "POST",
      "response_status": 422,
      "user_agent": "node-fetch/1.0",
      "api_key_id": "0199f0e2-7b8c-7d9e-8f0a-1b2c3d4e5f6a"
    }
  ]
}

#Get a log

GET/logs/{id}

Full-access key

Returns the log with request_body (the JSON that was sent, or the query string on GET requests) and response_body.

Path parameters

  • idstringrequired
    Log ID.

Errors

  • 404not_found
    The resource does not exist or belongs to another team.
GET /logs/{id}

cURL

curl https://api.postal.so/logs/019a1b2c-4d60-7a11-b2c3-d4e5f6a7b8c9 \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/logs/019a1b2c-4d60-7a11-b2c3-d4e5f6a7b8c9', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/logs/019a1b2c-4d60-7a11-b2c3-d4e5f6a7b8c9",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('logs/019a1b2c-4d60-7a11-b2c3-d4e5f6a7b8c9', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Response
{
  "object": "log",
  "id": "019a1b2c-4d60-7a11-b2c3-d4e5f6a7b8c9",
  "created_at": "2026-10-24T13:02:11.000000Z",
  "endpoint": "/emails",
  "method": "POST",
  "response_status": 200,
  "user_agent": "node-fetch/1.0",
  "api_key_id": "0199f0e2-7b8c-7d9e-8f0a-1b2c3d4e5f6a",
  "request_body": {
    "from": "Acme Store <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your order #10482 is out for delivery",
    "html": "<p>Order <b>#10482</b> is on its way.</p>"
  },
  "response_body": {
    "id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b"
  }
}