Sign in Create account
API reference

Suppression list API

The list of addresses that no longer receive email from your team.

The suppression list holds addresses that should no longer receive email from your team. Permanent bounces (bounce) and spam complaints (complaint) are added automatically; you can also add addresses yourself (manual). Suppressed recipients are removed from the send and generate the email.suppressed event. An address on the list also never becomes a contact: creating it answers 422 email_suppressed and the import skips it. In endpoints with {id}, you can use either the ID or the email address itself.

#List suppressions

GET/suppressions

Full-access key

Accepts limit, after and before. source_id is the email that caused the bounce or the complaint.

GET /suppressions

cURL

curl https://api.postal.so/suppressions \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/suppressions', {
  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/suppressions",
    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('suppressions', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Response
{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "suppression",
      "id": "019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b",
      "email": "[email protected]",
      "origin": "bounce",
      "source_id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
      "created_at": "2026-10-20T09:12:00.000000Z"
    }
  ]
}

#Add an address

POST/suppressions

Full-access key

Adds the address with origin manual. If it is already on the list, returns the existing record with status 200. Triggers suppression.added.

Request body

  • emailstringrequired
    Email address, up to 320 characters.

Errors

  • 422validation_error
    A field is invalid. The message says which one.
POST /suppressions

cURL

curl -X POST https://api.postal.so/suppressions \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]"
  }'

Node.js

const response = await fetch('https://api.postal.so/suppressions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: '[email protected]',
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/suppressions",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "email": "[email protected]",
    },
    timeout=10,
)

data = response.json()

PHP

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

$response = $client->post('suppressions', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'email' => '[email protected]',
    ],
]);

$data = json_decode($response->getBody(), true);
201Response
{
  "object": "suppression",
  "id": "019a1c20-8f90-7aa1-8b2c-3d4e5f6a7b8c",
  "email": "[email protected]",
  "origin": "manual",
  "source_id": null,
  "created_at": "2026-10-20T09:12:00.000000Z"
}

#Add in bulk

POST/suppressions/batch/add

Full-access key

Request body

  • emailsstring[]required
    From 1 to 100 addresses.

Errors

  • 422validation_error
    A field is invalid. The message says which one.
POST /suppressions/batch/add

cURL

curl -X POST https://api.postal.so/suppressions/batch/add \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": ["[email protected]", "[email protected]"]
  }'

Node.js

const response = await fetch('https://api.postal.so/suppressions/batch/add', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    emails: ['[email protected]', '[email protected]'],
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/suppressions/batch/add",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "emails": ["[email protected]", "[email protected]"],
    },
    timeout=10,
)

data = response.json()

PHP

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

$response = $client->post('suppressions/batch/add', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'emails' => ['[email protected]', '[email protected]'],
    ],
]);

$data = json_decode($response->getBody(), true);
201Response
{
  "data": [
    {
      "object": "suppression",
      "id": "019a1c21-0a1b-7c2d-9e3f-4a5b6c7d8e9f"
    },
    {
      "object": "suppression",
      "id": "019a1c21-0a1c-7d3e-8f4a-5b6c7d8e9f0a"
    }
  ]
}

#Remove in bulk

POST/suppressions/batch/remove

Full-access key

Removes by address or by ID (one of the two). Items that are not on the list are ignored.

Request body

  • emailsstring[]
    From 1 to 100 addresses.
  • idsstring[]
    From 1 to 100 IDs. Use instead of emails.

Errors

  • 422validation_error
    Neither field, or both together.
POST /suppressions/batch/remove

cURL

curl -X POST https://api.postal.so/suppressions/batch/remove \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": ["[email protected]"]
  }'

Node.js

const response = await fetch('https://api.postal.so/suppressions/batch/remove', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    emails: ['[email protected]'],
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/suppressions/batch/remove",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "emails": ["[email protected]"],
    },
    timeout=10,
)

data = response.json()

PHP

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

$response = $client->post('suppressions/batch/remove', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'emails' => ['[email protected]'],
    ],
]);

$data = json_decode($response->getBody(), true);
200Response
{
  "data": [
    {
      "object": "suppression",
      "id": "019a1c21-0a1b-7c2d-9e3f-4a5b6c7d8e9f",
      "deleted": true
    }
  ]
}

#Get a suppression

GET/suppressions/{id}

Full-access key

Path parameters

  • idstringrequired
    ID or email address.

Errors

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

cURL

curl https://api.postal.so/suppressions/[email protected] \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/suppressions/[email protected]', {
  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/suppressions/[email protected]",
    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('suppressions/[email protected]', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Response
{
  "object": "suppression",
  "id": "019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b",
  "email": "[email protected]",
  "origin": "bounce",
  "source_id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
  "created_at": "2026-10-20T09:12:00.000000Z"
}

#Remove an address

DELETE/suppressions/{id}

Full-access key

The address can receive email again. If it was suppressed because of a bounce, first confirm that the problem has been fixed. Triggers suppression.removed.

Path parameters

  • idstringrequired
    ID or email address.

Errors

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

cURL

curl -X DELETE https://api.postal.so/suppressions/019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/suppressions/019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.delete(
    "https://api.postal.so/suppressions/019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b",
    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->delete('suppressions/019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Response
{
  "object": "suppression",
  "id": "019a1530-6d7e-7f80-9a1b-2c3d4e5f6a7b",
  "deleted": true
}