Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/politicalcomms-com:politicalcomms-com-email-templates-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Political Comms Email Templates API
summary: Direct-to-carrier political texting API for campaigns, PACs, advocacy organizations, fundraisers, and elected officials.
description: 'Public REST API for the Political Comms platform. Surfaces include Projects (compose, test, schedule, send), Conversations (read inbound threads and reply inside them), Contact Lists (S3 import and analysis), Media Files, Organizations and hierarchy, Brands, Campaigns, Tracking Domains, Phone Numbers, Analytics, and Billing.
Authentication is an API key passed in the `X-API-Key` header. Keys are generated from the dashboard at Admin → API and are prefixed `pc_live_`. All POST and PATCH endpoints that mutate state are designed to be safe to retry, with optional `Idempotency-Key` headers for stronger guarantees. Rate limit is 600 requests per minute per key (bursts up to 600, refilling at 10 per second, the same for every scope; the `X-RateLimit-Limit` header reports your key''s exact limit, and `Retry-After` on a 429 is the seconds until your next request is allowed).
Webhooks emit `message.sent`, `message.delivered`, `message.failed`, `message.replied`, and `link.clicked` events. Payloads are HMAC-signed; validate the signature before trusting any payload.
A Model Context Protocol (MCP) server is available at https://docs.politicalcomms.com/mcp for AI agents that need to search the documentation programmatically. The developer hub at https://politicalcomms.com/developers/ has quickstart examples in cURL, raw HTTP, and Python.'
version: 1.4.1
termsOfService: https://politicalcomms.com/terms/
contact:
name: Political Comms Support
email: support@politicalcomms.com
url: https://docs.politicalcomms.com
license:
name: Proprietary
url: https://politicalcomms.com/terms/
x-logo:
url: https://politicalcomms.com/images/brand/pcomms-logo-left-of-text.png
altText: Political Comms
backgroundColor: '#ffffff'
href: https://politicalcomms.com/
x-mcp:
url: https://docs.politicalcomms.com/mcp
discovery_url: https://docs.politicalcomms.com/.well-known/mcp
transport: http
auth: none
tools:
- search_political_comms
- query_docs_filesystem_political_comms
- submit_feedback
servers:
- url: https://api.politicalcomms.com/v1
description: Production
security:
- ApiKeyAuth: []
tags:
- name: Email Templates
description: Create and read saved email templates.
paths:
/email/templates:
get:
tags:
- Email Templates
summary: List Email Templates
description: List the organization's email templates, newest first.
operationId: listEmailTemplates
parameters:
- $ref: '#/components/parameters/EmailLimit'
- $ref: '#/components/parameters/EmailCursor'
- $ref: '#/components/parameters/EmailSearch'
responses:
'200':
description: A page of templates.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/EmailTemplate'
has_more:
type: boolean
next_cursor:
type:
- string
- 'null'
required:
- data
- has_more
- next_cursor
additionalProperties: true
required:
- success
- data
additionalProperties: true
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
post:
tags:
- Email Templates
summary: Create Email Template
description: 'Create a template from raw HTML. The response carries a `lint` object beside the template: a template with lint errors saves, but a campaign using it will not schedule.'
operationId: createEmailTemplate
parameters:
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 255
description:
type: string
maxLength: 2000
content:
type: object
properties:
subject:
type: string
minLength: 1
maxLength: 900
preheader:
type: string
maxLength: 255
html:
type: string
minLength: 1
maxLength: 2097152
text:
type: string
description: Plain-text alternative. Generated from the HTML when omitted.
maxLength: 512000
required:
- subject
- html
description: The full body. On update this object replaces the stored content rather than merging into it.
additionalProperties: false
required:
- name
- content
additionalProperties: false
example:
name: Fall fundraising
description: Evergreen ask, brand colors
content:
subject: Can you chip in before Friday?
preheader: Every gift is matched through midnight.
html: <html><body><h1>Hi {first_name|Friend}</h1><p>Chip in today.</p></body></html>
responses:
'201':
description: Template created.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
allOf:
- $ref: '#/components/schemas/EmailTemplate'
- type: object
properties:
lint:
$ref: '#/components/schemas/EmailTemplateLint'
required:
- success
- data
additionalProperties: true
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: The API key lacks the required permission scope, the requested resource belongs to an organization outside the key's hierarchy, or the organization is not entitled to this feature.
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/AuthErrorResponse'
- $ref: '#/components/schemas/ErrorResponse'
examples:
missingScope:
summary: Key lacks the required permission scope
value:
error: Insufficient permissions
message: 'This API key does not have the required permissions: public:read'
orgAccessDenied:
summary: Resource outside the key's organization hierarchy
value:
error: 'Access denied: You do not have permission to access this organization''s data'
code: ORG_ACCESS_DENIED
correlationId: de038205-7c9c-4d4a-99bc-d7275a52f07e
entitlementRequired:
summary: Organization is not entitled to this feature
value:
error: This feature requires enablement by Political Comms
code: ENTITLEMENT_REQUIRED
details:
entitlement: email
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'400':
$ref: '#/components/responses/BadRequest'
/email/templates/{id}:
get:
tags:
- Email Templates
summary: Get Email Template
description: Get one template, including its HTML.
operationId: getEmailTemplate
parameters:
- $ref: '#/components/parameters/IdPath'
responses:
'200':
description: The template.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
$ref: '#/components/schemas/EmailTemplate'
required:
- success
- data
additionalProperties: true
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
components:
responses:
Forbidden:
description: The API key lacks the required permission scope, or the requested resource belongs to an organization outside the key's hierarchy.
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/AuthErrorResponse'
- $ref: '#/components/schemas/ErrorResponse'
examples:
missingScope:
summary: Key lacks the required permission scope
value:
error: Insufficient permissions
message: 'This API key does not have the required permissions: public:read'
orgAccessDenied:
summary: Resource outside the key's organization hierarchy
value:
error: 'Access denied: You do not have permission to access this organization''s data'
code: ORG_ACCESS_DENIED
correlationId: de038205-7c9c-4d4a-99bc-d7275a52f07e
BadRequest:
description: Invalid request (validation failure, malformed parameters, or a request the resource state does not allow).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error: Validation failed
code: VALIDATION_ERROR
correlationId: 030bf857-922f-4b82-8fca-c5b0769c1590
details:
- field: organization_id
message: Invalid UUID
code: invalid_format
Unauthorized:
description: Missing, malformed, revoked, or expired API key.
content:
application/json:
schema:
$ref: '#/components/schemas/AuthErrorResponse'
example:
error: API key required
message: Please provide an API key in the X-API-Key header
InternalError:
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error: An unexpected error occurred. Please try again later.
code: INTERNAL_ERROR
correlationId: de038205-7c9c-4d4a-99bc-d7275a52f07e
RateLimited:
description: Rate limit exceeded. Check the Retry-After header.
headers:
Retry-After:
description: Seconds until the window resets.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitErrorResponse'
example:
success: false
error: Rate limit exceeded
message: Maximum 600 requests per 60 seconds
code: RATE_LIMIT_EXCEEDED
statusCode: 429
retryAfter: 3
NotFound:
description: Resource not found or not visible to this API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error: Project not found
code: PROJECT_NOT_FOUND
correlationId: de038205-7c9c-4d4a-99bc-d7275a52f07e
schemas:
EmailTemplate:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
maxLength: 255
description:
type:
- string
- 'null'
maxLength: 2000
content:
$ref: '#/components/schemas/EmailTemplateContent'
thumbnail_url:
type:
- string
- 'null'
description: Preview image rendered by a background job. Null until it has run.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
required:
- id
- name
- content
description: A reusable email design in the organization's template library.
additionalProperties: true
RateLimitErrorResponse:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: string
message:
type: string
code:
type: string
enum:
- RATE_LIMIT_EXCEEDED
statusCode:
type: integer
enum:
- 429
retryAfter:
type: integer
description: Seconds until the rate-limit window resets. Also sent as the Retry-After header.
required:
- success
- error
- code
- statusCode
- retryAfter
additionalProperties: true
EmailTemplateContent:
type: object
properties:
subject:
type:
- string
- 'null'
maxLength: 900
preheader:
type:
- string
- 'null'
maxLength: 255
html:
type:
- string
- 'null'
maxLength: 2097152
text:
type:
- string
- 'null'
description: Plain-text alternative. Generated from the HTML when omitted.
maxLength: 512000
editor:
type: string
enum:
- html
- document
description: '`html` for a template imported or hand-written as HTML; `document` for one built in the dashboard''s document editor. Both are returned as rendered HTML here. This surface only accepts HTML content on create. Updating the `content` of a `document` template returns `409 CONFLICT` with `details.reason` set to `TEMPLATE_IS_DOCUMENT`: edit it in the dashboard, or convert it to an HTML template first.'
description: The renderable body of a template.
additionalProperties: true
EmailTemplateLint:
type: object
properties:
errors:
type: array
items:
type: object
additionalProperties: true
warnings:
type: array
items:
type: object
additionalProperties: true
description: Content lint result returned alongside every template write. A template with lint errors saves, but a campaign using it will not schedule, so read this on the write rather than discovering it at schedule time. Warnings do not block.
additionalProperties: true
AuthErrorResponse:
type: object
properties:
error:
type: string
description: Short error summary.
message:
type: string
description: Human-readable detail.
required:
- error
- message
additionalProperties: true
description: Error body returned by the API-key authentication layer (401 and permission 403s).
ErrorResponse:
type: object
properties:
error:
type: string
description: Human-readable error message.
code:
type: string
description: Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.
correlationId:
type: string
description: Request correlation ID; include it in support requests.
details:
type:
- array
- object
description: Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).
required:
- error
- code
additionalProperties: true
description: Standard error body produced by the API error handler for 4xx/5xx responses.
parameters:
IdPath:
name: id
in: path
required: true
description: Resource ID
schema:
type: string
EmailCursor:
name: cursor
in: query
required: false
description: Opaque cursor from the previous page's `next_cursor`.
schema:
type: string
maxLength: 4096
EmailSearch:
name: search
in: query
required: false
description: Case-insensitive substring match.
schema:
type: string
maxLength: 255
EmailLimit:
name: limit
in: query
required: false
description: Rows per page, 1-200.
schema:
type: integer
minimum: 1
maximum: 200
default: 50
IdempotencyKeyHeader:
name: Idempotency-Key
in: header
required: false
schema:
type: string
minLength: 16
maxLength: 200
description: 'Optional idempotency key: a unique string of 16-200 printable ASCII characters (a UUID is recommended). Retrying the write with the same key within 24 hours returns the stored response of the first call with an `X-Idempotent-Replayed: true` response header instead of executing it again. Reusing a key with a different request body returns `422` (`IDEMPOTENCY_MISMATCH`); a duplicate sent while the first call is still running returns `409` with a `Retry-After` header. Keys are scoped per endpoint and organization.'
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: Authenticate every request by passing your API key in the X-API-Key header. Keys are scoped to your organization hierarchy.