openapi: 3.0.3
info:
title: 'Postmaster+ API Documentation'
description: ''
version: 1.0.0
servers:
- url: 'https://postmasterplus.app'
tags:
- name: Domains
description: ''
- name: APRF
description: ''
- name: IPs
description: ''
- name: Intelligence
description: ''
- name: Blocklists
description: ''
- name: Seedbox
description: ''
- name: 'Spam Identifiers'
description: ''
- name: Tools
description: ''
components:
securitySchemes:
default:
type: http
scheme: bearer
description: 'You can retrieve your token by visiting your dashboard and clicking Team Settings > API Tokens.'
security:
-
default: []
paths:
/api/v1/domains:
get:
summary: 'Retrieve Domains.'
operationId: retrieveDomains
description: ''
parameters:
-
in: query
name: page
description: 'The page number. Must be at least 1.'
example: 1
required: false
schema:
type: integer
description: 'The page number. Must be at least 1.'
example: 1
-
in: query
name: per_page
description: 'The number of domains per page. Must be at least 1. Must not be greater than 100.'
example: 15
required: false
schema:
type: integer
description: 'The number of domains per page. Must be at least 1. Must not be greater than 100.'
example: 15
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'Domains retrieved successfully.'
data:
-
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
meta:
current_page: 1
from: 1
last_page: 1
per_page: 15
to: 1
total: 1
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Domains retrieved successfully.'
data:
type: array
example:
- id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
items:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
description:
type: string
example: 'Primary sending domain'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
meta:
type: object
properties:
current_page:
type: integer
example: 1
from:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 15
to:
type: integer
example: 1
total:
type: integer
example: 1
tags:
- Domains
'/api/v1/domains/{id}/feed':
get:
summary: 'Retrieve Domain Feed.'
operationId: retrieveDomainFeed
description: ''
parameters:
-
in: query
name: page
description: 'The page number for paginated feed results. Must be at least 1.'
example: 1
required: false
schema:
type: integer
description: 'The page number for paginated feed results. Must be at least 1.'
example: 1
nullable: true
-
in: query
name: date
description: 'Filter feed items reported on or after this date, up to today. Must not be older than 90 days from today. Must be a valid date in the format Y-m-d.'
example: '2026-08-06'
required: false
schema:
type: string
description: 'Filter feed items reported on or after this date, up to today. Must not be older than 90 days from today. Must be a valid date in the format Y-m-d.'
example: '2026-08-06'
nullable: true
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'Domain feed retrieved successfully.'
data:
-
reported_at: 'Mar 28, 2026 5:30PM'
mail_stream: 'Transactional Stream'
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
spf_domain: example.com
seed_message:
mail_from_name: 'Test Sender'
mail_from: sender@example.com
subject: 'Seed message'
preview_line: 'This is a preview.'
is_compliant: true
is_blocklisted: false
is_test: false
-
message: 'SPF is valid.'
reported_at: 'Mar 28, 2026 4:45PM'
mail_stream: 'Transactional Stream'
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
spf_domain: null
seed_message: null
meta:
current_page: 1
from: 1
last_page: 2
per_page: 15
to: 15
total: 16
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Domain feed retrieved successfully.'
data:
type: array
example:
-
reported_at: 'Mar 28, 2026 5:30PM'
mail_stream: 'Transactional Stream'
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
spf_domain: example.com
seed_message:
mail_from_name: 'Test Sender'
mail_from: sender@example.com
subject: 'Seed message'
preview_line: 'This is a preview.'
is_compliant: true
is_blocklisted: false
is_test: false
-
message: 'SPF is valid.'
reported_at: 'Mar 28, 2026 4:45PM'
mail_stream: 'Transactional Stream'
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
spf_domain: null
seed_message: null
items:
type: object
properties:
reported_at:
type: string
example: 'Mar 28, 2026 5:30PM'
mail_stream:
type: string
example: 'Transactional Stream'
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
description:
type: string
example: 'Primary sending domain'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
spf_domain:
type: string
example: example.com
seed_message:
type: object
properties:
mail_from_name:
type: string
example: 'Test Sender'
mail_from:
type: string
example: sender@example.com
subject:
type: string
example: 'Seed message'
preview_line:
type: string
example: 'This is a preview.'
is_compliant:
type: boolean
example: true
is_blocklisted:
type: boolean
example: false
is_test:
type: boolean
example: false
meta:
type: object
properties:
current_page:
type: integer
example: 1
from:
type: integer
example: 1
last_page:
type: integer
example: 2
per_page:
type: integer
example: 15
to:
type: integer
example: 15
total:
type: integer
example: 16
403:
description: ''
content:
application/json:
schema:
type: object
example:
success: false
message: 'Feed is only available for activated domains.'
data: []
properties:
success:
type: boolean
example: false
message:
type: string
example: 'Feed is only available for activated domains.'
data:
type: array
example: []
tags:
- Domains
parameters:
-
in: path
name: id
description: 'The ULID of the domain.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
'/api/v1/domains/{id}':
get:
summary: 'Retrieve Domain.'
operationId: retrieveDomain
description: ''
parameters:
-
in: query
name: start_date
description: 'Filter related IPs from this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-01'
required: false
schema:
type: string
description: 'Filter related IPs from this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-01'
-
in: query
name: end_date
description: 'Filter related IPs until this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-03-31'
required: false
schema:
type: string
description: 'Filter related IPs until this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-03-31'
-
in: query
name: related_ips_page
description: 'The page number for related IP results.'
example: 1
required: false
schema:
type: integer
description: 'The page number for related IP results.'
example: 1
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'Domain retrieved successfully.'
data:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
logo: null
team:
name: 'Owner Custom Team'
mail_streams:
-
name: 'Transactional Stream'
type: transactional
logo: 'https://cdn.example.com/mail-streams/transactional.svg'
configuration:
spf_domains: []
dkim_selectors: []
bimi_selectors: []
dmarc:
valid: true
record: 'v=DMARC1; p=none;'
mx:
valid: true
records:
- mx1.example.com
- mx2.example.com
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
alignment:
items: []
settings:
estimated_message_volume: '1000'
general_settings:
estimated_message_volume: '1000'
shared_team_ids: []
mail_streams:
-
name: 'Transactional Stream'
type: transactional
general_settings: []
spf_domains: []
compliance:
is_compliant: true
pre_send:
is_compliant: true
mail_streams:
-
name: 'Transactional Stream'
type: transactional
is_compliant: true
checks:
ips: true
one_click_unsub: false
blocklists: true
spf: true
dkim: true
dmarc: true
tls: true
post_send:
is_compliant: false
requirements:
spf: true
dkim: null
dmarc_alignment: null
dmarc_policy: false
encryption: null
user_reported_spam_rate: null
dns_records: null
one_click_unsubscribe: null
honor_unsubscribe: null
message_formatting: null
subdomain:
domain_id: mail.example.com
requirements:
spf: false
dkim: false
dmarc_alignment: null
dmarc_policy: null
encryption: null
user_reported_spam_rate: null
dns_records: null
one_click_unsubscribe: null
honor_unsubscribe: null
message_formatting: null
mail_streams:
-
name: 'Transactional Stream'
type: transactional
is_compliant: true
checks:
ips: true
one_click_unsub: false
blocklists: true
spf: true
dkim: true
dmarc: true
tls: true
complaint_rate_averages:
periods: []
related_ips:
date_range:
start_date: '2026-01-01 00:00:00'
end_date: '2026-03-31 23:59:59'
items:
-
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
meta:
current_page: 1
last_page: 1
per_page: 10
total: 0
blocklists:
is_blacklist: false
blacklist_count: 0
listed_count: 0
listed_muted: 0
listed_details: []
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Domain retrieved successfully.'
data:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
description:
type: string
example: 'Primary sending domain'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
logo:
type: string
example: null
nullable: true
team:
type: object
properties:
name:
type: string
example: 'Owner Custom Team'
mail_streams:
type: array
example:
- name: 'Transactional Stream'
type: transactional
logo: 'https://cdn.example.com/mail-streams/transactional.svg'
items:
type: object
properties:
name:
type: string
example: 'Transactional Stream'
type:
type: string
example: transactional
logo:
type: string
example: 'https://cdn.example.com/mail-streams/transactional.svg'
configuration:
type: object
properties:
spf_domains:
type: array
example: []
dkim_selectors:
type: array
example: []
bimi_selectors:
type: array
example: []
dmarc:
type: object
properties:
valid:
type: boolean
example: true
record:
type: string
example: 'v=DMARC1; p=none;'
mx:
type: object
properties:
valid:
type: boolean
example: true
records:
type: array
example:
- mx1.example.com
- mx2.example.com
items:
type: string
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
alignment:
type: object
properties:
items:
type: array
example: []
settings:
type: object
properties:
estimated_message_volume:
type: string
example: '1000'
general_settings:
type: object
properties:
estimated_message_volume:
type: string
example: '1000'
shared_team_ids:
type: array
example: []
mail_streams:
type: array
example:
-
name: 'Transactional Stream'
type: transactional
general_settings: []
items:
type: object
properties:
name:
type: string
example: 'Transactional Stream'
type:
type: string
example: transactional
general_settings:
type: array
example: []
spf_domains:
type: array
example: []
compliance:
type: object
properties:
is_compliant:
type: boolean
example: true
pre_send:
type: object
properties:
is_compliant:
type: boolean
example: true
mail_streams:
type: array
example:
-
name: 'Transactional Stream'
type: transactional
is_compliant: true
checks:
ips: true
one_click_unsub: false
blocklists: true
spf: true
dkim: true
dmarc: true
tls: true
items:
type: object
properties:
name:
type: string
example: 'Transactional Stream'
type:
type: string
example: transactional
is_compliant:
type: boolean
example: true
checks:
type: object
properties: { ips: { type: boolean, example: true }, one_click_unsub: { type: boolean, example: false }, blocklists: { type: boolean, example: true }, spf: { type: boolean, example: true }, dkim: { type: boolean, example: true }, dmarc: { type: boolean, example: true }, tls: { type: boolean, example: true } }
post_send:
type: object
properties:
is_compliant:
type: boolean
example: false
requirements:
type: object
properties:
spf:
type: boolean
example: true
dkim:
type: string
example: null
nullable: true
dmarc_alignment:
type: string
example: null
nullable: true
dmarc_policy:
type: boolean
example: false
encryption:
type: string
example: null
nullable: true
user_reported_spam_rate:
type: string
example: null
nullable: true
dns_records:
type: string
example: null
nullable: true
one_click_unsubscribe:
type: string
example: null
nullable: true
honor_unsubscribe:
type: string
example: null
nullable: true
message_formatting:
type: string
example: null
nullable: true
subdomain:
type: object
properties:
domain_id:
type: string
example: mail.example.com
requirements:
type: object
properties:
spf: { type: boolean, example: false }
dkim: { type: boolean, example: false }
dmarc_alignment: { type: string, example: null, nullable: true }
dmarc_policy: { type: string, example: null, nullable: true }
encryption: { type: string, example: null, nullable: true }
user_reported_spam_rate: { type: string, example: null, nullable: true }
dns_records: { type: string, example: null, nullable: true }
one_click_unsubscribe: { type: string, example: null, nullable: true }
honor_unsubscribe: { type: string, example: null, nullable: true }
message_formatting: { type: string, example: null, nullable: true }
mail_streams:
type: array
example:
-
name: 'Transactional Stream'
type: transactional
is_compliant: true
checks:
ips: true
one_click_unsub: false
blocklists: true
spf: true
dkim: true
dmarc: true
tls: true
items:
type: object
properties:
name:
type: string
example: 'Transactional Stream'
type:
type: string
example: transactional
is_compliant:
type: boolean
example: true
checks:
type: object
properties:
ips:
type: boolean
example: true
one_click_unsub:
type: boolean
example: false
blocklists:
type: boolean
example: true
spf:
type: boolean
example: true
dkim:
type: boolean
example: true
dmarc:
type: boolean
example: true
tls:
type: boolean
example: true
complaint_rate_averages:
type: object
properties:
periods:
type: array
example: []
related_ips:
type: object
properties:
date_range:
type: object
properties:
start_date:
type: string
example: '2026-01-01 00:00:00'
end_date:
type: string
example: '2026-03-31 23:59:59'
items:
type: array
example:
- id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
items:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: 192.0.2.10
description:
type: string
example: 'Primary sending IP'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
meta:
type: object
properties:
current_page:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 10
total:
type: integer
example: 0
blocklists:
type: object
properties:
is_blacklist:
type: boolean
example: false
blacklist_count:
type: integer
example: 0
listed_count:
type: integer
example: 0
listed_muted:
type: integer
example: 0
listed_details:
type: array
example: []
tags:
- Domains
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
related_ips_page:
type: integer
description: 'Must be at least 1.'
example: 16
nullable: true
start_date:
type: string
description: 'Must be a valid date in the format Y-m-d. Must be a date before or equal to today. Must be a date before or equal to end_date.'
example: '2022-08-31'
nullable: true
end_date:
type: string
description: 'Must be a valid date in the format Y-m-d. Must be a date before or equal to today. Must be a date after or equal to start_date.'
example: '2052-08-29'
nullable: true
parameters:
-
in: path
name: id
description: 'The ULID of the domain.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
/api/v1/aprf-reports:
get:
summary: 'Retrieve APRF Reports.'
operationId: retrieveAPRFReports
description: "List the Comcast/Xfinity APRF (Aggregate Postmaster Report Feedback) reports\nreceived for this team in the given date range.\n\nThe collection is team-wide rather than nested under a domain on purpose:\na provider may send a rollup covering several domains or selectors, or a\nreport for a domain this team does not track, and both must stay reachable.\nThose reports carry `domain: null` and are never attributed to a tracked\ndomain by name.\n\nMetric values are provider-supplied approximate bucket upper bounds. They\nare not counts, so they must not be summed, averaged or turned into\npercentages; `metric_value_semantics` repeats that on every response."
parameters:
-
in: query
name: domain_id
description: 'Optionally filter reports to a single accessible domain ULID. Rollups and reports for untracked domains carry no domain, so this filter excludes them.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: false
schema:
type: string
description: 'Optionally filter reports to a single accessible domain ULID. Rollups and reports for untracked domains carry no domain, so this filter excludes them.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
-
in: query
name: start_date
description: 'Filter reports whose report_date falls on or after this date (Y-m-d). Maximum selected range is 90 days. Defaults to the trailing 90 days.'
example: '2026-05-09'
required: false
schema:
type: string
description: 'Filter reports whose report_date falls on or after this date (Y-m-d). Maximum selected range is 90 days. Defaults to the trailing 90 days.'
example: '2026-05-09'
-
in: query
name: end_date
description: 'Filter reports whose report_date falls on or before this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-08-06'
required: false
schema:
type: string
description: 'Filter reports whose report_date falls on or before this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-08-06'
-
in: query
name: sort
description: 'Sort field. Either a report column (report_date, report_end, source, dkim_selector) or a single metric bucket as metric:.. Reports without the sorted metric are always ordered last.'
example: report_date
required: false
schema:
type: string
description: 'Sort field. Either a report column (report_date, report_end, source, dkim_selector) or a single metric bucket as metric:.. Reports without the sorted metric are always ordered last.'
example: report_date
-
in: query
name: direction
description: 'Sort direction, asc or desc.'
example: desc
required: false
schema:
type: string
description: 'Sort direction, asc or desc.'
example: desc
-
in: query
name: page
description: 'The page number for paginated report results.'
example: 1
required: false
schema:
type: integer
description: 'The page number for paginated report results.'
example: 1
-
in: query
name: per_page
description: 'Reports per page. Defaults to 25 and is clamped to a maximum of 100.'
example: 25
required: false
schema:
type: integer
description: 'Reports per page. Defaults to 25 and is clamped to a maximum of 100.'
example: 25
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'APRF reports retrieved successfully.'
data:
-
id: 1421
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
is_rollup: false
source: Comcast/Xfinity
dkim_domain: example.com
dkim_selector: s1
report_start: '2026-08-04T00:00:00+00:00'
report_end: '2026-08-04T23:59:59+00:00'
report_date: '2026-08-04'
sender_verified: true
billing:
status: charged
is_billed: true
withheld_reason: null
credits_used: 1
metrics:
-
category: classification
metric_key: inbox
approximate_bucket_upper_bound: 25
-
id: 1420
domain: null
is_rollup: true
source: Comcast/Xfinity
dkim_domain: '*.example.com'
dkim_selector: '*'
report_start: '2026-08-03T00:00:00+00:00'
report_end: '2026-08-03T23:59:59+00:00'
report_date: '2026-08-03'
sender_verified: false
billing:
status: not_billable
is_billed: false
withheld_reason: null
credits_used: 0
metrics: []
meta:
current_page: 1
last_page: 1
per_page: 25
total: 2
date_range:
start_date: '2026-05-09'
end_date: '2026-08-06'
sort:
field: report_date
direction: desc
metric_value_semantics: provider_bucket_upper_bound_non_additive
properties:
success:
type: boolean
example: true
message:
type: string
example: 'APRF reports retrieved successfully.'
data:
type: array
example:
-
id: 1421
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
is_rollup: false
source: Comcast/Xfinity
dkim_domain: example.com
dkim_selector: s1
report_start: '2026-08-04T00:00:00+00:00'
report_end: '2026-08-04T23:59:59+00:00'
report_date: '2026-08-04'
sender_verified: true
billing:
status: charged
is_billed: true
withheld_reason: null
credits_used: 1
metrics:
- category: classification
metric_key: inbox
approximate_bucket_upper_bound: 25
-
id: 1420
domain: null
is_rollup: true
source: Comcast/Xfinity
dkim_domain: '*.example.com'
dkim_selector: '*'
report_start: '2026-08-03T00:00:00+00:00'
report_end: '2026-08-03T23:59:59+00:00'
report_date: '2026-08-03'
sender_verified: false
billing:
status: not_billable
is_billed: false
withheld_reason: null
credits_used: 0
metrics: []
items:
type: object
properties:
id:
type: integer
example: 1421
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
is_rollup:
type: boolean
example: false
source:
type: string
example: Comcast/Xfinity
dkim_domain:
type: string
example: example.com
dkim_selector:
type: string
example: s1
report_start:
type: string
example: '2026-08-04T00:00:00+00:00'
report_end:
type: string
example: '2026-08-04T23:59:59+00:00'
report_date:
type: string
example: '2026-08-04'
sender_verified:
type: boolean
example: true
billing:
type: object
properties:
status:
type: string
example: charged
is_billed:
type: boolean
example: true
withheld_reason:
type: string
example: null
nullable: true
credits_used:
type: integer
example: 1
metrics:
type: array
example:
- category: classification
metric_key: inbox
approximate_bucket_upper_bound: 25
items:
type: object
properties:
category:
type: string
example: classification
metric_key:
type: string
example: inbox
approximate_bucket_upper_bound:
type: integer
example: 25
meta:
type: object
properties:
current_page:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 25
total:
type: integer
example: 2
date_range:
type: object
properties:
start_date:
type: string
example: '2026-05-09'
end_date:
type: string
example: '2026-08-06'
sort:
type: object
properties:
field:
type: string
example: report_date
direction:
type: string
example: desc
metric_value_semantics:
type: string
example: provider_bucket_upper_bound_non_additive
tags:
- APRF
'/api/v1/aprf-reports/{id}':
get:
summary: 'Retrieve APRF Report.'
operationId: retrieveAPRFReport
description: "Return one APRF report and its unsegmented metrics. Segmented metric rows\ndescribe slices of a report and would double-count, so they are never\nexposed.\n\nA report belonging to another team, a report we were never able to charge\nfor, and an identifier that does not exist all answer the same 404, so the\nresponse never reveals which case it was.\n\nThe id is typed as a string because `whereNumber` admits a value past bigint\nthat an int parameter would fail to coerce, answering 500 instead of the\nusual 404."
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'APRF report retrieved successfully.'
data:
id: 1421
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
is_rollup: false
source: Comcast/Xfinity
dkim_domain: example.com
dkim_selector: s1
report_start: '2026-08-04T00:00:00+00:00'
report_end: '2026-08-04T23:59:59+00:00'
report_date: '2026-08-04'
sender_verified: true
billing:
status: charged
is_billed: true
withheld_reason: null
credits_used: 1
metrics:
-
category: classification
metric_key: inbox
approximate_bucket_upper_bound: 25
metric_value_semantics: provider_bucket_upper_bound_non_additive
properties:
success:
type: boolean
example: true
message:
type: string
example: 'APRF report retrieved successfully.'
data:
type: object
properties:
id:
type: integer
example: 1421
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
is_rollup:
type: boolean
example: false
source:
type: string
example: Comcast/Xfinity
dkim_domain:
type: string
example: example.com
dkim_selector:
type: string
example: s1
report_start:
type: string
example: '2026-08-04T00:00:00+00:00'
report_end:
type: string
example: '2026-08-04T23:59:59+00:00'
report_date:
type: string
example: '2026-08-04'
sender_verified:
type: boolean
example: true
billing:
type: object
properties:
status:
type: string
example: charged
is_billed:
type: boolean
example: true
withheld_reason:
type: string
example: null
nullable: true
credits_used:
type: integer
example: 1
metrics:
type: array
example:
- category: classification
metric_key: inbox
approximate_bucket_upper_bound: 25
items:
type: object
properties:
category:
type: string
example: classification
metric_key:
type: string
example: inbox
approximate_bucket_upper_bound:
type: integer
example: 25
metric_value_semantics:
type: string
example: provider_bucket_upper_bound_non_additive
404:
description: ''
content:
application/json:
schema:
type: object
example:
success: false
message: 'APRF report not found.'
data: []
properties:
success:
type: boolean
example: false
message:
type: string
example: 'APRF report not found.'
data:
type: array
example: []
tags:
- APRF
parameters:
-
in: path
name: id
description: 'The APRF report identifier.'
example: 1421
required: true
schema:
type: integer
'/api/v1/domains/{id}/aprf-status':
get:
summary: 'Retrieve Domain APRF Status.'
operationId: retrieveDomainAPRFStatus
description: "Return the stored APRF (Aggregate Postmaster Report Feedback) DNS and\nconsent snapshot for one domain, plus the DNS records to publish so this\nteam receives reports for it.\n\nThis is a snapshot, never a live lookup: every record, verdict and message\nis what we last observed, and `checked_at` is the only indicator of how\nfresh that is. A stale `checked_at` means our snapshot is old, not that DNS\nchanged. There is no refresh parameter.\n\n`has_our_seed_address` is the one derived value. Selector records are shared\nbetween the teams that track the same domain, so the verdict cannot be\nstored against the record; it is computed per request from the requesting\nteam's own report address.\n\nThe response carries no metrics, so it carries no `metric_value_semantics`."
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'APRF status retrieved successfully.'
data:
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
report_address: seed@a-abc123.seed.example.com
wildcard:
record: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid: true
message: 'APRF record is valid.'
source: wildcard
has_our_seed_address: true
checked_at: '2026-08-05T09:00:00+00:00'
selectors:
-
selector: s1
record: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid: true
message: 'APRF record is valid.'
source: selector
has_our_seed_address: true
checked_at: '2026-08-05T09:00:00+00:00'
sdi:
header: MsgInfo
separator: ^
recommended_records:
-
name: '*._aprf._domainkey.example.com'
type: TXT
value: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope: wildcard
selector: null
-
name: s1._aprf._domainkey.example.com
type: TXT
value: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope: selector
selector: s1
properties:
success:
type: boolean
example: true
message:
type: string
example: 'APRF status retrieved successfully.'
data:
type: object
properties:
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
report_address:
type: string
example: seed@a-abc123.seed.example.com
wildcard:
type: object
properties:
record:
type: string
example: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid:
type: boolean
example: true
message:
type: string
example: 'APRF record is valid.'
source:
type: string
example: wildcard
has_our_seed_address:
type: boolean
example: true
checked_at:
type: string
example: '2026-08-05T09:00:00+00:00'
selectors:
type: array
example:
- selector: s1
record: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid: true
message: 'APRF record is valid.'
source: selector
has_our_seed_address: true
checked_at: '2026-08-05T09:00:00+00:00'
items:
type: object
properties:
selector:
type: string
example: s1
record:
type: string
example: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid:
type: boolean
example: true
message:
type: string
example: 'APRF record is valid.'
source:
type: string
example: selector
has_our_seed_address:
type: boolean
example: true
checked_at:
type: string
example: '2026-08-05T09:00:00+00:00'
sdi:
type: object
properties:
header:
type: string
example: MsgInfo
separator:
type: string
example: ^
recommended_records:
type: array
example:
- name: '*._aprf._domainkey.example.com'
type: TXT
value: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope: wildcard
selector: null
- name: s1._aprf._domainkey.example.com
type: TXT
value: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope: selector
selector: s1
items:
type: object
properties:
name:
type: string
example: '*._aprf._domainkey.example.com'
type:
type: string
example: TXT
value:
type: string
example: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope:
type: string
example: wildcard
selector:
type: string
example: null
nullable: true
tags:
- APRF
parameters:
-
in: path
name: id
description: 'The ULID of the domain.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
'/api/v1/domains/{id}/aprf-sdi':
put:
summary: 'Update Domain APRF SDI.'
operationId: updateDomainAPRFSDI
description: "Set or clear the optional Sender Defined Identifier pair for one domain.\nBoth fields must be sent: a header with a separator sets the pair, and two\nnulls clear it. One without the other is a 422, because a half-configured\npair cannot be written into a record.\n\nThis changes the records the domain owner must publish. The SDI pair is\nappended to every recommended record as `sdi=,`, so a\nrecord published before this call no longer matches the recommendation\nafterwards. The response is the full status payload for exactly that\nreason: read `recommended_records` back and re-publish from it.\n\nNothing about the stored DNS snapshot changes here. No lookup is performed,\nevery `checked_at` is untouched, and the domain does not begin or stop\nreceiving reports because of this call.\n\nUnlike the read endpoint, this resolves the domain by owning team only. A\ndomain merely shared with this team is a 404 here: the SDI pair decides what\nits owner has to publish, so a team it was shared with must not rewrite it."
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'APRF SDI updated successfully.'
data:
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
report_address: seed@a-abc123.seed.example.com
wildcard:
record: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid: true
message: 'APRF record is valid.'
source: wildcard
has_our_seed_address: true
checked_at: '2026-08-05T09:00:00+00:00'
selectors: []
sdi:
header: MsgInfo
separator: ^
recommended_records:
-
name: '*._aprf._domainkey.example.com'
type: TXT
value: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope: wildcard
selector: null
properties:
success:
type: boolean
example: true
message:
type: string
example: 'APRF SDI updated successfully.'
data:
type: object
properties:
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
report_address:
type: string
example: seed@a-abc123.seed.example.com
wildcard:
type: object
properties:
record:
type: string
example: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com'
valid:
type: boolean
example: true
message:
type: string
example: 'APRF record is valid.'
source:
type: string
example: wildcard
has_our_seed_address:
type: boolean
example: true
checked_at:
type: string
example: '2026-08-05T09:00:00+00:00'
selectors:
type: array
example: []
sdi:
type: object
properties:
header:
type: string
example: MsgInfo
separator:
type: string
example: ^
recommended_records:
type: array
example:
- name: '*._aprf._domainkey.example.com'
type: TXT
value: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope: wildcard
selector: null
items:
type: object
properties:
name:
type: string
example: '*._aprf._domainkey.example.com'
type:
type: string
example: TXT
value:
type: string
example: 'v=APRFv1; rua=mailto:seed@a-abc123.seed.example.com; sdi=MsgInfo,^'
scope:
type: string
example: wildcard
selector:
type: string
example: null
nullable: true
tags:
- APRF
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
aprf_sdi_header:
type: string
description: 'The header name providers should report the subscriber-data identifier under. Send null together with a null separator to clear the pair. Must not contain ; = , or :. The value field must be a string. Must match the regex /^[\x21-\x7E]+$/. Must not be greater than 255 characters.'
example: MsgInfo
nullable: true
aprf_sdi_separator:
type: string
description: 'The single printable character separating the identifier fields. Must not be ; = or , because each would corrupt the published record. The value field must be a string. Must match the regex /^[\x20-\x7E]$/. Must not be one of ;, =, or , Must be 1 character.'
example: ^
nullable: true
parameters:
-
in: path
name: id
description: 'The ULID of the domain. Must be owned by this team; a domain only shared with it is not found here.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
/api/v1/ips:
get:
summary: 'Retrieve IPs.'
operationId: retrieveIPs
description: ''
parameters:
-
in: query
name: page
description: 'The page number. Must be at least 1.'
example: 1
required: false
schema:
type: integer
description: 'The page number. Must be at least 1.'
example: 1
-
in: query
name: per_page
description: 'The number of IPs per page. Must be at least 1. Must not be greater than 100.'
example: 15
required: false
schema:
type: integer
description: 'The number of IPs per page. Must be at least 1. Must not be greater than 100.'
example: 15
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'IPs retrieved successfully.'
data:
-
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
meta:
current_page: 1
from: 1
last_page: 1
per_page: 15
to: 1
total: 1
properties:
success:
type: boolean
example: true
message:
type: string
example: 'IPs retrieved successfully.'
data:
type: array
example:
- id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
items:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: 192.0.2.10
description:
type: string
example: 'Primary sending IP'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
meta:
type: object
properties:
current_page:
type: integer
example: 1
from:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 15
to:
type: integer
example: 1
total:
type: integer
example: 1
tags:
- IPs
'/api/v1/ips/{id}/feed':
get:
summary: 'Retrieve IP Feed.'
operationId: retrieveIPFeed
description: ''
parameters:
-
in: query
name: page
description: 'The page number for paginated feed results. Must be at least 1.'
example: 1
required: false
schema:
type: integer
description: 'The page number for paginated feed results. Must be at least 1.'
example: 1
nullable: true
-
in: query
name: date
description: 'Filter feed items reported on or after this date, up to today. Must not be older than 90 days from today. Must be a valid date in the format Y-m-d.'
example: '2026-08-06'
required: false
schema:
type: string
description: 'Filter feed items reported on or after this date, up to today. Must not be older than 90 days from today. Must be a valid date in the format Y-m-d.'
example: '2026-08-06'
nullable: true
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'IP feed retrieved successfully.'
data:
-
reported_at: 'Mar 28, 2026 5:30PM'
mail_stream: 'Transactional Stream'
ip:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
seed_message:
mail_from_name: 'Test Sender'
mail_from: sender@example.com
subject: 'Seed message'
preview_line: 'This is a preview.'
is_compliant: true
is_blocklisted: false
is_test: false
-
message: 'IP is compliant.'
reported_at: 'Mar 28, 2026 4:45PM'
mail_stream: 'Transactional Stream'
ip:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
seed_message: null
meta:
current_page: 1
from: 1
last_page: 2
per_page: 15
to: 15
total: 16
properties:
success:
type: boolean
example: true
message:
type: string
example: 'IP feed retrieved successfully.'
data:
type: array
example:
-
reported_at: 'Mar 28, 2026 5:30PM'
mail_stream: 'Transactional Stream'
ip:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
seed_message:
mail_from_name: 'Test Sender'
mail_from: sender@example.com
subject: 'Seed message'
preview_line: 'This is a preview.'
is_compliant: true
is_blocklisted: false
is_test: false
-
message: 'IP is compliant.'
reported_at: 'Mar 28, 2026 4:45PM'
mail_stream: 'Transactional Stream'
ip:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
seed_message: null
items:
type: object
properties:
reported_at:
type: string
example: 'Mar 28, 2026 5:30PM'
mail_stream:
type: string
example: 'Transactional Stream'
ip:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: 192.0.2.10
description:
type: string
example: 'Primary sending IP'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
seed_message:
type: object
properties:
mail_from_name:
type: string
example: 'Test Sender'
mail_from:
type: string
example: sender@example.com
subject:
type: string
example: 'Seed message'
preview_line:
type: string
example: 'This is a preview.'
is_compliant:
type: boolean
example: true
is_blocklisted:
type: boolean
example: false
is_test:
type: boolean
example: false
meta:
type: object
properties:
current_page:
type: integer
example: 1
from:
type: integer
example: 1
last_page:
type: integer
example: 2
per_page:
type: integer
example: 15
to:
type: integer
example: 15
total:
type: integer
example: 16
403:
description: ''
content:
application/json:
schema:
type: object
example:
success: false
message: 'Feed is only available for activated IPs.'
data: []
properties:
success:
type: boolean
example: false
message:
type: string
example: 'Feed is only available for activated IPs.'
data:
type: array
example: []
tags:
- IPs
parameters:
-
in: path
name: id
description: 'The ULID of the IP.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
'/api/v1/ips/{id}':
get:
summary: 'Retrieve IP.'
operationId: retrieveIP
description: ''
parameters:
-
in: query
name: start_date
description: 'Filter related domains from this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-01'
required: false
schema:
type: string
description: 'Filter related domains from this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-01'
-
in: query
name: end_date
description: 'Filter related domains until this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-03-31'
required: false
schema:
type: string
description: 'Filter related domains until this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-03-31'
-
in: query
name: related_domains_page
description: 'The page number for related domain results.'
example: 1
required: false
schema:
type: integer
description: 'The page number for related domain results.'
example: 1
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'IP retrieved successfully.'
data:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: 192.0.2.10
description: 'Primary sending IP'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
logo: null
team:
name: 'Owner Custom Team'
mail_streams:
-
name: 'Transactional Stream'
type: transactional
logo: 'https://cdn.example.com/mail-streams/transactional.svg'
configuration:
rdns: mail.example.com
fcrdns: true
rdns_summary: null
provider:
asn:
asn: AS64500
name: 'Example ASN'
location: '37.7749,-122.4194'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
settings:
shared_team_ids: []
compliance:
is_compliant: true
sender_score: 98
checks:
blocklists: true
fcrdns: true
complaint_rate_averages:
periods: []
inbox_placement_averages:
periods: []
related_domains:
date_range:
start_date: '2026-01-01 00:00:00'
end_date: '2026-03-31 23:59:59'
items:
-
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
meta:
current_page: 1
last_page: 1
per_page: 10
total: 0
blocklists:
is_blacklist: false
blacklist_count: 0
listed_count: 0
listed_muted: 0
listed_details: []
properties:
success:
type: boolean
example: true
message:
type: string
example: 'IP retrieved successfully.'
data:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: 192.0.2.10
description:
type: string
example: 'Primary sending IP'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
logo:
type: string
example: null
nullable: true
team:
type: object
properties:
name:
type: string
example: 'Owner Custom Team'
mail_streams:
type: array
example:
- name: 'Transactional Stream'
type: transactional
logo: 'https://cdn.example.com/mail-streams/transactional.svg'
items:
type: object
properties:
name:
type: string
example: 'Transactional Stream'
type:
type: string
example: transactional
logo:
type: string
example: 'https://cdn.example.com/mail-streams/transactional.svg'
configuration:
type: object
properties:
rdns:
type: string
example: mail.example.com
fcrdns:
type: boolean
example: true
rdns_summary:
type: string
example: null
nullable: true
provider:
type: object
properties:
asn:
type: object
properties:
asn:
type: string
example: AS64500
name:
type: string
example: 'Example ASN'
location:
type: string
example: '37.7749,-122.4194'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
settings:
type: object
properties:
shared_team_ids:
type: array
example: []
compliance:
type: object
properties:
is_compliant:
type: boolean
example: true
sender_score:
type: integer
example: 98
checks:
type: object
properties:
blocklists:
type: boolean
example: true
fcrdns:
type: boolean
example: true
complaint_rate_averages:
type: object
properties:
periods:
type: array
example: []
inbox_placement_averages:
type: object
properties:
periods:
type: array
example: []
related_domains:
type: object
properties:
date_range:
type: object
properties:
start_date:
type: string
example: '2026-01-01 00:00:00'
end_date:
type: string
example: '2026-03-31 23:59:59'
items:
type: array
example:
- id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
description: 'Primary sending domain'
created_at: '2026-03-28T10:30:00.000000Z'
updated_at: '2026-03-28T10:30:00.000000Z'
items:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
description:
type: string
example: 'Primary sending domain'
created_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
updated_at:
type: string
example: '2026-03-28T10:30:00.000000Z'
meta:
type: object
properties:
current_page:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 10
total:
type: integer
example: 0
blocklists:
type: object
properties:
is_blacklist:
type: boolean
example: false
blacklist_count:
type: integer
example: 0
listed_count:
type: integer
example: 0
listed_muted:
type: integer
example: 0
listed_details:
type: array
example: []
tags:
- IPs
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
related_domains_page:
type: integer
description: 'Must be at least 1.'
example: 16
nullable: true
start_date:
type: string
description: 'Must be a valid date in the format Y-m-d. Must be a date before or equal to today. Must be a date before or equal to end_date.'
example: '2022-08-31'
nullable: true
end_date:
type: string
description: 'Must be a valid date in the format Y-m-d. Must be a date before or equal to today. Must be a date after or equal to start_date.'
example: '2052-08-29'
nullable: true
parameters:
-
in: path
name: id
description: 'The ULID of the IP.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
'/api/v1/intelligence/single-emails/{email}':
get:
summary: 'Retrieve Single Email.'
operationId: retrieveSingleEmail
description: ''
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 11
email: price.amber@example.org
status: null
created_at: '2026-08-06 14:24:38'
updated_at: '2026-08-06 14:24:38'
properties:
data:
type: object
properties:
id:
type: integer
example: 11
email:
type: string
example: price.amber@example.org
status:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-08-06 14:24:38'
updated_at:
type: string
example: '2026-08-06 14:24:38'
tags:
- Intelligence
delete:
summary: 'Delete Single Email.'
operationId: deleteSingleEmail
description: ''
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Single email deleted.'
deleted: true
properties:
message:
type: string
example: 'Single email deleted.'
deleted:
type: boolean
example: true
tags:
- Intelligence
parameters:
-
in: path
name: email
description: 'The email address to retrieve.'
example: example@postmasterplus.com
required: true
schema:
type: string
/api/v1/intelligence/single-emails/scan:
post:
summary: 'Scan Single Email.'
operationId: scanSingleEmail
description: ''
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 12
email: rempel.chadrick@example.org
status: null
created_at: '2026-08-06 14:24:38'
updated_at: '2026-08-06 14:24:38'
properties:
data:
type: object
properties:
id:
type: integer
example: 12
email:
type: string
example: rempel.chadrick@example.org
status:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-08-06 14:24:38'
updated_at:
type: string
example: '2026-08-06 14:24:38'
tags:
- Intelligence
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
description: 'The email address to scan.'
example: example@postmasterplus.com
actions:
type: string
description: 'The actions in comma separated format to perform.'
example: '"verification,activity,postal_append"'
required:
- email
- actions
/api/v1/blocklist/scan/start:
post:
summary: 'Start Blocklist Scan.'
operationId: startBlocklistScan
description: ''
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 01kzbqcfbr82g17w8vcqgfqn8h
status: pending
status_label: Pending
unique_hosts_checked: 3
total_hosts_detected: null
urls_scanned: 0
urls_skipped: 0
blocklisted: false
credits_used: 0
error_message: ''
started_at: null
completed_at: null
success: true
message: 'Blocklist check started successfully.'
properties:
data:
type: object
properties:
id:
type: string
example: 01kzbqcfbr82g17w8vcqgfqn8h
description: 'The unique identifier for the blocklist check.'
status:
type: string
example: pending
description: 'The status of the blocklist check. Example: `pending`, `processing`, `completed`, `partially_completed`, `failed`'
enum:
- pending
- processing
- completed
- partially_completed
- failed
status_label:
type: string
example: Pending
description: 'Human-friendly status label. Example: Pending, Processing, Completed, Partially Completed, Failed'
unique_hosts_checked:
type: integer
example: 3
description: 'The number of unique hosts checked.'
total_hosts_detected:
type: string
example: null
description: 'The number of hosts detected.'
urls_scanned:
type: integer
example: 0
description: 'The number of URLs scanned.'
urls_skipped:
type: integer
example: 0
description: 'The number of URLs skipped.'
blocklisted:
type: boolean
example: false
description: 'Whether the check is blocklisted.'
credits_used:
type: integer
example: 0
description: 'The number of credits used.'
error_message:
type: string
example: ''
description: 'The error message if the check failed.'
started_at:
type: string
example: null
description: 'The date and time the check started.'
completed_at:
type: string
example: null
description: 'The date and time the check completed.'
required:
- id
- status
- status_label
- unique_hosts_checked
- total_hosts_detected
- urls_scanned
- urls_skipped
- blocklisted
- credits_used
- error_message
- started_at
- completed_at
success:
type: boolean
example: true
message:
type: string
example: 'Blocklist check started successfully.'
tags:
- Blocklists
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
urls:
type: array
description: 'Array of HTTP(S) URLs, bare domains, or public IP addresses to scan (minimum 1 target, maximum 100 targets).'
example:
- 'https://optipub.com/newsletter'
- optipub.com
- 8.8.8.8
items:
type: string
follow_redirects:
type: boolean
description: 'optional Whether to follow redirects for full HTTP(S) URL targets. Defaults to true. Bare domains and IP targets always bypass redirect processing.'
example: true
required:
- urls
'/api/v1/blocklist/scan/status/{id}':
get:
summary: 'Retrieve Blocklist Scan Status.'
operationId: retrieveBlocklistScanStatus
description: ''
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 01kzbqcfc62awwsmrkkc7qn50r
status: pending
status_label: Pending
unique_hosts_checked: 4
total_hosts_detected: null
urls_scanned: 0
urls_skipped: 0
blocklisted: false
credits_used: 0
error_message: ''
started_at: null
completed_at: null
success: true
message: 'Blocklist check status retrieved successfully.'
properties:
data:
type: object
properties:
id:
type: string
example: 01kzbqcfc62awwsmrkkc7qn50r
description: 'The unique identifier for the blocklist check.'
status:
type: string
example: pending
description: 'The status of the blocklist check. Example: `pending`, `processing`, `completed`, `partially_completed`, `failed`'
enum:
- pending
- processing
- completed
- partially_completed
- failed
status_label:
type: string
example: Pending
description: 'Human-friendly status label. Example: Pending, Processing, Completed, Partially Completed, Failed'
unique_hosts_checked:
type: integer
example: 4
description: 'The number of unique hosts checked.'
total_hosts_detected:
type: string
example: null
description: 'The number of hosts detected.'
urls_scanned:
type: integer
example: 0
description: 'The number of URLs scanned.'
urls_skipped:
type: integer
example: 0
description: 'The number of URLs skipped.'
blocklisted:
type: boolean
example: false
description: 'Whether the check is blocklisted.'
credits_used:
type: integer
example: 0
description: 'The number of credits used.'
error_message:
type: string
example: ''
description: 'The error message if the check failed.'
started_at:
type: string
example: null
description: 'The date and time the check started.'
completed_at:
type: string
example: null
description: 'The date and time the check completed.'
required:
- id
- status
- status_label
- unique_hosts_checked
- total_hosts_detected
- urls_scanned
- urls_skipped
- blocklisted
- credits_used
- error_message
- started_at
- completed_at
success:
type: boolean
example: true
message:
type: string
example: 'Blocklist check status retrieved successfully.'
tags:
- Blocklists
parameters:
-
in: path
name: id
description: 'The ULID of the blocklist check.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string
/api/v1/seedboxes:
get:
summary: ''
operationId: getApiV1Seedboxes
description: ''
parameters: []
responses: {}
tags:
- Seedbox
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
status:
type: string
description: ''
example: active
enum:
- active
- revoked
nullable: true
mode:
type: string
description: ''
example: null
client_reference:
type: string
description: 'Must not be greater than 255 characters.'
example: b
nullable: true
per_page:
type: integer
description: 'Must be at least 1. Must not be greater than 100.'
example: 22
page:
type: integer
description: 'Must be at least 1.'
example: 67
post:
summary: ''
operationId: postApiV1Seedboxes
description: ''
parameters: []
responses: {}
tags:
- Seedbox
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Must not be greater than 120 characters.'
example: b
client_reference:
type: string
description: 'Must not be greater than 255 characters.'
example: 'n'
nullable: true
scan_blocklists:
type: boolean
description: ''
example: true
mode:
type: string
description: ''
example: null
max_messages:
type: string
description: ''
example: null
expires_at:
type: string
description: ''
example: null
required:
- name
'/api/v1/seedboxes/{seedbox}/messages':
get:
summary: ''
operationId: getApiV1SeedboxesSeedboxMessages
description: ''
parameters: []
responses: {}
tags:
- Seedbox
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
per_page:
type: integer
description: 'Must be at least 1. Must not be greater than 100.'
example: 1
page:
type: integer
description: 'Must be at least 1.'
example: 22
include_content:
type: string
description: ''
example: 'true'
enum:
- 'true'
- 'false'
- '1'
- '0'
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58C6f7nnFCJ9M6rjyc6rTKMzn6
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox}/messages/{message}':
get:
summary: ''
operationId: getApiV1SeedboxesSeedboxMessagesMessage
description: ''
parameters: []
responses: {}
tags:
- Seedbox
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
include_content:
type: string
description: ''
example: '1'
enum:
- 'true'
- 'false'
- '1'
- '0'
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58C6f7nnFCJ9M6rjyc6rTKMzn6
required: true
schema:
type: string
-
in: path
name: message
description: 'The message.'
example: BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox}/messages/{message}/unsubscribe':
post:
summary: 'Request a one-click unsubscribe for the list behind a seedbox message.'
operationId: requestAOneClickUnsubscribeForTheListBehindASeedboxMessage
description: "Mirrors the web endpoint exactly: this action owns no unsubscribe logic\nof its own, it resolves the message through the current team, delegates\nto the shared action, and maps the returned outcome to a status through\n{@see RequestUnsubscribeOutcome}, so every surface agrees on whether an\noutcome counts as a success. A `rate_limited` outcome answers 429 and the same\nrequest may succeed once the budget refills."
parameters: []
responses: {}
tags:
- Seedbox
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58C6f7nnFCJ9M6rjyc6rTKMzn6
required: true
schema:
type: string
-
in: path
name: message
description: 'The message.'
example: BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox_id}/subscriptions':
get:
summary: ''
operationId: getApiV1SeedboxesSeedbox_idSubscriptions
description: ''
parameters: []
responses: {}
tags:
- Seedbox
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
state:
type: string
description: ''
example: subscribed
enum:
- subscribed
- unsubscribe_pending
- unsubscribe_failed
- unsubscribed
- mail_after_unsubscribe_within_threshold
- mail_after_unsubscribe
nullable: true
search:
type: string
description: 'Must not be greater than 255 characters.'
example: b
nullable: true
sort:
type: string
description: ''
example: last_seen_at
enum:
- severity
- last_seen_at
- oldest_seen_at
nullable: true
per_page:
type: integer
description: 'Must be at least 1. Must not be greater than 100.'
example: 22
page:
type: integer
description: 'Must be at least 1.'
example: 67
parameters:
-
in: path
name: seedbox_id
description: 'The ID of the seedbox.'
example: architecto
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox}/subscriptions/unsubscribe-all':
post:
summary: 'Request an unsubscribe from every actionable list matching the given filters.'
operationId: requestAnUnsubscribeFromEveryActionableListMatchingTheGivenFilters
description: "Requests are paced, so this answers 202 with counts rather than a per-list\noutcome."
parameters: []
responses: {}
tags:
- Seedbox
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
state:
type: string
description: ''
example: mail_after_unsubscribe
enum:
- subscribed
- unsubscribe_pending
- unsubscribe_failed
- unsubscribed
- mail_after_unsubscribe_within_threshold
- mail_after_unsubscribe
nullable: true
search:
type: string
description: 'Must not be greater than 255 characters.'
example: b
nullable: true
sort:
type: string
description: ''
example: severity
enum:
- severity
- last_seen_at
- oldest_seen_at
nullable: true
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58C6f7nnFCJ9M6rjyc6rTKMzn6
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox}/subscriptions/{subscription}/unsubscribe':
post:
summary: ''
operationId: postApiV1SeedboxesSeedboxSubscriptionsSubscriptionUnsubscribe
description: ''
parameters: []
responses: {}
tags:
- Seedbox
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58C6f7nnFCJ9M6rjyc6rTKMzn6
required: true
schema:
type: string
-
in: path
name: subscription
description: 'The subscription.'
example: '564'
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox}':
get:
summary: ''
operationId: getApiV1SeedboxesSeedbox
description: ''
parameters: []
responses: {}
tags:
- Seedbox
patch:
summary: 'Update editable seedbox metadata without changing its address or lifecycle.'
operationId: updateEditableSeedboxMetadataWithoutChangingItsAddressOrLifecycle
description: ''
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 01kzbqcfemk8k9bj46s9gx4jvc
team_id: 44
name: null
client_reference: null
status: active
address: opti@b-01kzbqcfemk8k9bj46s9gx4jvd.seeds.dev.optipub.com
scan_blocklists: false
receive_credits_per_message: 1
messages_count: 0
rejected_insufficient_credit_count: 0
unresolved_insufficient_credit_rejection_count: 0
accepting_messages: true
can_delete: false
revoked_at: null
last_received_at: null
last_rejected_insufficient_credit_at: null
created_at: '2026-08-06T14:24:38+00:00'
success: true
message: 'Seedbox updated successfully.'
properties:
data:
type: object
properties:
id:
type: string
example: 01kzbqcfemk8k9bj46s9gx4jvc
team_id:
type: integer
example: 44
name:
type: string
example: null
nullable: true
client_reference:
type: string
example: null
nullable: true
status:
type: string
example: active
address:
type: string
example: opti@b-01kzbqcfemk8k9bj46s9gx4jvd.seeds.dev.optipub.com
scan_blocklists:
type: boolean
example: false
receive_credits_per_message:
type: integer
example: 1
messages_count:
type: integer
example: 0
rejected_insufficient_credit_count:
type: integer
example: 0
unresolved_insufficient_credit_rejection_count:
type: integer
example: 0
accepting_messages:
type: boolean
example: true
can_delete:
type: boolean
example: false
revoked_at:
type: string
example: null
nullable: true
last_received_at:
type: string
example: null
nullable: true
last_rejected_insufficient_credit_at:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-08-06T14:24:38+00:00'
success:
type: boolean
example: true
message:
type: string
example: 'Seedbox updated successfully.'
tags:
- Seedbox
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'A non-empty human-readable name. Omit this field to preserve the current name. Must not be greater than 120 characters.'
example: 'Transactional seedbox'
client_reference:
type: string
description: 'A stable external identifier. Send null to clear it, or omit this field to preserve it. Must not be greater than 255 characters.'
example: campaign-2026-07
nullable: true
scan_blocklists:
type: boolean
description: 'Whether future received messages should be scanned against blocklists. Enabling it requires blocklist-check:scan:start and may increase future credit usage.'
example: true
delete:
summary: ''
operationId: deleteApiV1SeedboxesSeedbox
description: ''
parameters: []
responses: {}
tags:
- Seedbox
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58C6f7nnFCJ9M6rjyc6rTKMzn6
required: true
schema:
type: string
'/api/v1/seedboxes/{seedbox}/delete':
delete:
summary: ''
operationId: deleteApiV1SeedboxesSeedboxDelete
description: ''
parameters: []
responses: {}
tags:
- Seedbox
parameters:
-
in: path
name: seedbox
description: 'The seedbox.'
example: 58
required: true
schema:
type: integer
/api/v1/spam-identifiers:
get:
summary: 'Retrieve Spam Identifiers.'
operationId: retrieveSpamIdentifiers
description: "List all Gmail Postmaster Tools v2 spam (feedback loop) identifiers reported\nfor accessible domains in the given date range, along with each identifier's\naverage complaint rate across that window."
parameters:
-
in: query
name: domain_id
description: 'Optionally filter identifiers to a single accessible domain ULID.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: false
schema:
type: string
description: 'Optionally filter identifiers to a single accessible domain ULID.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
-
in: query
name: page
description: 'The page number for paginated identifier results.'
example: 1
required: false
schema:
type: integer
description: 'The page number for paginated identifier results.'
example: 1
-
in: query
name: start_date
description: 'Filter identifiers from this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-22'
required: false
schema:
type: string
description: 'Filter identifiers from this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-22'
-
in: query
name: end_date
description: 'Filter identifiers until this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-04-22'
required: false
schema:
type: string
description: 'Filter identifiers until this date (Y-m-d). Maximum selected range is 90 days.'
example: '2026-04-22'
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'Spam identifiers retrieved successfully.'
data:
-
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
identifier: '66189376'
sample_count: 57
average_complaint_rate: 0.12
min_complaint_rate: 0.05
max_complaint_rate: 0.31
-
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FBG
value: example.net
identifier: '66189799'
sample_count: 40
average_complaint_rate: 0.05
min_complaint_rate: 0.01
max_complaint_rate: 0.14
meta:
current_page: 1
last_page: 1
per_page: 25
total: 2
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Spam identifiers retrieved successfully.'
data:
type: array
example:
-
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
identifier: '66189376'
sample_count: 57
average_complaint_rate: 0.12
min_complaint_rate: 0.05
max_complaint_rate: 0.31
-
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FBG
value: example.net
identifier: '66189799'
sample_count: 40
average_complaint_rate: 0.05
min_complaint_rate: 0.01
max_complaint_rate: 0.14
items:
type: object
properties:
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
identifier:
type: string
example: '66189376'
sample_count:
type: integer
example: 57
average_complaint_rate:
type: number
example: 0.12
min_complaint_rate:
type: number
example: 0.05
max_complaint_rate:
type: number
example: 0.31
meta:
type: object
properties:
current_page:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 25
total:
type: integer
example: 2
tags:
- 'Spam Identifiers'
'/api/v1/spam-identifiers/{identifier}':
get:
summary: 'Retrieve Spam Identifier.'
operationId: retrieveSpamIdentifier
description: "Return the daily Gmail complaint rate time series for a single spam\n(feedback loop) identifier across accessible domains, plus the aggregate\naverage over the selected date range for each domain."
parameters:
-
in: query
name: domain_id
description: 'Optionally filter the identifier to a single accessible domain ULID.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: false
schema:
type: string
description: 'Optionally filter the identifier to a single accessible domain ULID.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
-
in: query
name: start_date
description: 'Start date of the reporting window (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-22'
required: false
schema:
type: string
description: 'Start date of the reporting window (Y-m-d). Maximum selected range is 90 days.'
example: '2026-01-22'
-
in: query
name: end_date
description: 'End date of the reporting window (Y-m-d). Maximum selected range is 90 days.'
example: '2026-04-22'
required: false
schema:
type: string
description: 'End date of the reporting window (Y-m-d). Maximum selected range is 90 days.'
example: '2026-04-22'
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'Spam identifier retrieved successfully.'
data:
-
identifier: '66189376'
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
date_range:
start_date: '2026-01-22'
end_date: '2026-04-22'
aggregate:
average_complaint_rate: 0.12
sample_count: 57
time_series:
-
date: '2026-01-22'
complaint_rate: 0.1
-
date: '2026-01-23'
complaint_rate: null
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Spam identifier retrieved successfully.'
data:
type: array
example:
-
identifier: '66189376'
domain:
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value: example.com
date_range:
start_date: '2026-01-22'
end_date: '2026-04-22'
aggregate:
average_complaint_rate: 0.12
sample_count: 57
time_series:
- date: '2026-01-22'
complaint_rate: 0.1
- date: '2026-01-23'
complaint_rate: null
items:
type: object
properties:
identifier:
type: string
example: '66189376'
domain:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
value:
type: string
example: example.com
date_range:
type: object
properties:
start_date:
type: string
example: '2026-01-22'
end_date:
type: string
example: '2026-04-22'
aggregate:
type: object
properties:
average_complaint_rate:
type: number
example: 0.12
sample_count:
type: integer
example: 57
time_series:
type: array
example:
- date: '2026-01-22'
complaint_rate: 0.1
- date: '2026-01-23'
complaint_rate: null
items:
type: object
properties:
date:
type: string
example: '2026-01-22'
complaint_rate:
type: number
example: 0.1
404:
description: ''
content:
application/json:
schema:
type: object
example:
success: false
message: 'Spam identifier not found for accessible domains in the selected date range.'
data: []
properties:
success:
type: boolean
example: false
message:
type: string
example: 'Spam identifier not found for accessible domains in the selected date range.'
data:
type: array
example: []
tags:
- 'Spam Identifiers'
parameters:
-
in: path
name: identifier
description: 'The Gmail Postmaster Tools v2 spam (feedback loop) identifier.'
example: '66189376'
required: true
schema:
type: string
/api/v1/screenshot/take:
post:
summary: 'Take Screenshot.'
operationId: takeScreenshot
description: 'Take a screenshot of a URL or HTML content.'
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 01kzbqcfcvv6024pw79n8d297q
url: 'https://assets.optipub.com/postmaster/screenshots/01kzbqcfcnw7xyx8d4st3qqdet/01kzbqcfcvv6024pw79n8d297q.png'
format: png
width: 1024
height: 600
device_scale: 3
credits_used: 1
started_at: '2026-07-27T08:26:12+00:00'
completed_at: '2026-07-27T08:26:25+00:00'
created_at: '2026-08-06T14:24:38+00:00'
success: true
message: 'Screenshot taken successfully.'
properties:
data:
type: object
properties:
id:
type: string
example: 01kzbqcfcvv6024pw79n8d297q
description: 'The unique identifier for the screenshot.'
url:
type: string
example: 'https://assets.optipub.com/postmaster/screenshots/01kzbqcfcnw7xyx8d4st3qqdet/01kzbqcfcvv6024pw79n8d297q.png'
description: 'The URL of the screenshot image.'
format:
type: string
example: png
description: 'The format of the screenshot image. Example: `png`, `jpeg`'
width:
type: integer
example: 1024
description: 'The width of the screenshot in pixels.'
height:
type: integer
example: 600
description: 'The height of the screenshot in pixels.'
device_scale:
type: integer
example: 3
description: 'The device scale factor used (1-3). Higher values produce sharper images.'
credits_used:
type: integer
example: 1
description: 'The number of credits used for this screenshot.'
started_at:
type: string
example: '2026-07-27T08:26:12+00:00'
description: 'The date and time when the screenshot capture started.'
completed_at:
type: string
example: '2026-07-27T08:26:25+00:00'
description: 'The date and time when the screenshot capture completed.'
created_at:
type: string
example: '2026-08-06T14:24:38+00:00'
description: 'The date and time the screenshot was created.'
required:
- id
- url
- format
- width
- height
- device_scale
- credits_used
- started_at
- completed_at
- created_at
success:
type: boolean
example: true
message:
type: string
example: 'Screenshot taken successfully.'
tags:
- Tools
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
url:
type: string
description: 'URL to screenshot (required if html is not provided).'
example: '"https://example.com"'
nullable: true
html:
type: string
description: 'HTML content to screenshot (required if url is not provided).'
example: null
nullable: true
width:
type: integer
description: 'optional Viewport width in pixels (320-1920). Defaults to 1280.'
example: 1280
nullable: true
height:
type: integer
description: 'optional Viewport height in pixels (240-1080). Defaults to 720.'
example: 720
nullable: true
format:
type: string
description: 'optional Image format (png, jpeg, or webp). Defaults to png.'
example: '"png"'
nullable: true
device_scale:
type: integer
description: 'optional Device scale factor for higher resolution (1-3). Defaults to 1 for retina-quality images.'
example: 1
nullable: true
/api/v1/screenshots:
get:
summary: 'List Screenshots.'
operationId: listScreenshots
description: 'Retrieve a paginated list of screenshots for the current team.'
parameters:
-
in: query
name: per_page
description: 'The number of screenshots per page (1-100). Defaults to 15. Must be at least 1. Must not be greater than 100.'
example: 15
required: false
schema:
type: integer
description: 'The number of screenshots per page (1-100). Defaults to 15. Must be at least 1. Must not be greater than 100.'
example: 15
-
in: query
name: page
description: 'The page number. Must be at least 1.'
example: 1
required: false
schema:
type: integer
description: 'The page number. Must be at least 1.'
example: 1
-
in: query
name: sort
description: 'Sort order. Use `-` prefix for descending. Options: `created_at`, `-created_at`, `format`, `-format`. Defaults to `-created_at`.'
example: '-created_at'
required: false
schema:
type: string
description: 'Sort order. Use `-` prefix for descending. Options: `created_at`, `-created_at`, `format`, `-format`. Defaults to `-created_at`.'
example: '-created_at'
enum:
- created_at
- '-created_at'
- format
- '-format'
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
success: true
message: 'Screenshots retrieved successfully.'
data:
-
id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
url: 'https://assets.optipub.com/postmaster/screenshots/01arz3ndektsv4rrffq69g5fav/01arz3ndektsv4rrffq69g5fav.png'
format: png
width: 1280
height: 720
credits_used: 1
created_at: '2024-01-15T10:30:00Z'
meta:
current_page: 1
from: 1
last_page: 5
per_page: 15
to: 15
total: 75
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Screenshots retrieved successfully.'
data:
type: array
example:
- id: 01ARZ3NDEKTSV4RRFFQ69G5FAV
url: 'https://assets.optipub.com/postmaster/screenshots/01arz3ndektsv4rrffq69g5fav/01arz3ndektsv4rrffq69g5fav.png'
format: png
width: 1280
height: 720
credits_used: 1
created_at: '2024-01-15T10:30:00Z'
items:
type: object
properties:
id:
type: string
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
url:
type: string
example: 'https://assets.optipub.com/postmaster/screenshots/01arz3ndektsv4rrffq69g5fav/01arz3ndektsv4rrffq69g5fav.png'
format:
type: string
example: png
width:
type: integer
example: 1280
height:
type: integer
example: 720
credits_used:
type: integer
example: 1
created_at:
type: string
example: '2024-01-15T10:30:00Z'
meta:
type: object
properties:
current_page:
type: integer
example: 1
from:
type: integer
example: 1
last_page:
type: integer
example: 5
per_page:
type: integer
example: 15
to:
type: integer
example: 15
total:
type: integer
example: 75
tags:
- Tools
'/api/v1/screenshot/{id}':
get:
summary: 'Get Screenshot.'
operationId: getScreenshot
description: 'Retrieve details of a specific screenshot by its ID.'
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 01kzbqcfdg45vbz3srh76hngnv
url: 'https://assets.optipub.com/postmaster/screenshots/01kzbqcfdb2gan5pw88jsajkfx/01kzbqcfdg45vbz3srh76hngnv.png'
format: png
width: 800
height: 600
device_scale: 2
credits_used: 1
started_at: '2026-07-27T05:07:02+00:00'
completed_at: '2026-07-27T05:07:32+00:00'
created_at: '2026-08-06T14:24:38+00:00'
success: true
message: 'Screenshot retrieved successfully.'
properties:
data:
type: object
properties:
id:
type: string
example: 01kzbqcfdg45vbz3srh76hngnv
description: 'The unique identifier for the screenshot.'
url:
type: string
example: 'https://assets.optipub.com/postmaster/screenshots/01kzbqcfdb2gan5pw88jsajkfx/01kzbqcfdg45vbz3srh76hngnv.png'
description: 'The URL of the screenshot image.'
format:
type: string
example: png
description: 'The format of the screenshot image. Example: `png`, `jpeg`'
width:
type: integer
example: 800
description: 'The width of the screenshot in pixels.'
height:
type: integer
example: 600
description: 'The height of the screenshot in pixels.'
device_scale:
type: integer
example: 2
description: 'The device scale factor used (1-3). Higher values produce sharper images.'
credits_used:
type: integer
example: 1
description: 'The number of credits used for this screenshot.'
started_at:
type: string
example: '2026-07-27T05:07:02+00:00'
description: 'The date and time when the screenshot capture started.'
completed_at:
type: string
example: '2026-07-27T05:07:32+00:00'
description: 'The date and time when the screenshot capture completed.'
created_at:
type: string
example: '2026-08-06T14:24:38+00:00'
description: 'The date and time the screenshot was created.'
required:
- id
- url
- format
- width
- height
- device_scale
- credits_used
- started_at
- completed_at
- created_at
success:
type: boolean
example: true
message:
type: string
example: 'Screenshot retrieved successfully.'
tags:
- Tools
parameters:
-
in: path
name: id
description: 'The ULID of the screenshot.'
example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
required: true
schema:
type: string