politicalcomms-com Billing API

Usage and billing data across your organization.

Operations 2

GET /ledger/usage Get Usage #
GET /ledger/usage/by-initiator Get Usage by Initiator #

Work with this as data

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-billing-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 Specification

politicalcomms-com-billing-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Political Comms Billing 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: Billing
  description: Usage and billing data across your organization.
paths:
  /ledger/usage:
    get:
      tags:
      - Billing
      summary: Get Usage
      description: 'Ledger usage aggregated per organization for a date range. The range must be 31 days or less and may not start more than 180 days in the past or end in the future. Charge amounts are signed: usage charges are negative. A `brandId` or `campaignId` outside your organizations returns 404 BRAND_NOT_FOUND or CAMPAIGN_NOT_FOUND, the same as an unknown id.'
      operationId: getLedgerUsage
      parameters:
      - $ref: '#/components/parameters/StartDate'
      - $ref: '#/components/parameters/EndDate'
      - $ref: '#/components/parameters/OrganizationIdCamel'
      - $ref: '#/components/parameters/BrandIdCamel'
      - $ref: '#/components/parameters/CampaignIdCamel'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      startDate:
                        type: string
                      endDate:
                        type: string
                      organizations:
                        type: array
                        items:
                          type: object
                          properties:
                            organizationId:
                              type: string
                            organizationName:
                              type: string
                            stripeCustomerId:
                              type:
                              - string
                              - 'null'
                            accountRep:
                              type:
                              - string
                              - 'null'
                            tier:
                              type:
                              - integer
                              - 'null'
                            usage:
                              type: array
                              items:
                                type: object
                                properties:
                                  productCode:
                                    type: string
                                  eventType:
                                    type: string
                                    enum:
                                    - charge_success
                                    - charge_failure
                                    - admin_adjustment
                                  quantity:
                                    type: integer
                                    description: 'Billable segments, not messages: an SMS over 160 characters bills as more than one segment, so a message count is always less than or equal to this.'
                                  unitPrice:
                                    type: number
                                    description: Positive unit rate; direction lives on totalAmount.
                                  totalAmount:
                                    type: number
                                    description: Signed amount in dollars; charges are negative.
                                  transactionCount:
                                    type: integer
                                additionalProperties: true
                            payments:
                              type: array
                              items:
                                type: object
                                properties: {}
                                additionalProperties: true
                              description: Always empty on this endpoint.
                            adjustments:
                              type: array
                              items:
                                type: object
                                properties: {}
                                additionalProperties: true
                              description: Always empty on this endpoint.
                            totalUsageAmount:
                              type: number
                              description: Signed sum of usage charges.
                            totalPaymentAmount:
                              type: number
                              description: Always 0 on this endpoint.
                          additionalProperties: true
                      totalUsageAmount:
                        type: number
                      totalPaymentAmount:
                        type: number
                        description: Always 0 on this endpoint.
                      totalQuantity:
                        type: integer
                        description: Total billable segments across the response.
                      serviceTotals:
                        type: object
                        description: Total billable segments per product code across all organizations.
                        additionalProperties:
                          type: integer
                    additionalProperties: true
                required:
                - success
                - data
                additionalProperties: true
              example:
                success: true
                data:
                  startDate: '2025-07-01'
                  endDate: '2025-07-31'
                  organizations:
                  - organizationId: 0d9f6a2e-1b34-4c8e-9f21-3e7a8b5c4d10
                    organizationName: Smith Campaign 2024
                    stripeCustomerId: cus_QWERty123456
                    accountRep: null
                    tier: 1
                    usage:
                    - productCode: sms_outbound
                      eventType: charge_success
                      quantity: 11800
                      unitPrice: 0.03
                      totalAmount: -354.0
                      transactionCount: 11800
                    payments: []
                    adjustments: []
                    totalUsageAmount: -354.0
                    totalPaymentAmount: 0
                  totalUsageAmount: -354.0
                  totalPaymentAmount: 0
                  totalQuantity: 11800
                  serviceTotals:
                    sms_outbound: 11800
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
  /ledger/usage/by-initiator:
    get:
      tags:
      - Billing
      summary: Get Usage by Initiator
      description: 'Ledger usage grouped by the organization that initiated each charge, for a date range (max 31 days, no older than 180 days). Amounts are signed: charges are negative. Initiators are sorted by totalAmount descending.'
      operationId: getLedgerUsageByInitiator
      parameters:
      - $ref: '#/components/parameters/StartDate'
      - $ref: '#/components/parameters/EndDate'
      - $ref: '#/components/parameters/OrganizationIdCamel'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      startDate:
                        type: string
                      endDate:
                        type: string
                      initiators:
                        type: array
                        items:
                          type: object
                          properties:
                            initiatingOrganizationId:
                              type: string
                            initiatingOrganizationName:
                              type:
                              - string
                              - 'null'
                            usage:
                              type: array
                              items:
                                type: object
                                properties:
                                  date:
                                    type: string
                                  productCode:
                                    type: string
                                  eventType:
                                    type: string
                                  quantity:
                                    type: integer
                                    description: 'Billable segments, not messages: an SMS over 160 characters bills as more than one segment, so a message count is always less than or equal to this.'
                                  totalAmount:
                                    type: number
                                    description: Signed amount in dollars; charges are negative.
                                  transactionCount:
                                    type: integer
                                additionalProperties: true
                            totalAmount:
                              type: number
                            totalQuantity:
                              type: integer
                            transactionCount:
                              type: integer
                          additionalProperties: true
                      totalAmount:
                        type: number
                      totalQuantity:
                        type: integer
                        description: Total billable segments across the response.
                      totalTransactionCount:
                        type: integer
                    additionalProperties: true
                required:
                - success
                - data
                additionalProperties: true
              example:
                success: true
                data:
                  startDate: '2025-07-01'
                  endDate: '2025-07-31'
                  initiators:
                  - initiatingOrganizationId: 9e4c7b2a-5f18-4d3e-a6b9-1c8f4e7a2d55
                    initiatingOrganizationName: Regional Office East
                    usage:
                    - date: '2025-07-02T00:00:00.000Z'
                      productCode: sms_outbound
                      eventType: charge_success
                      quantity: 4200
                      totalAmount: -126.0
                      transactionCount: 4200
                    totalAmount: -126.0
                    totalQuantity: 4200
                    transactionCount: 4200
                  totalAmount: -126.0
                  totalQuantity: 4200
                  totalTransactionCount: 4200
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '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
    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
    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
  parameters:
    StartDate:
      name: startDate
      in: query
      required: true
      description: Start date in YYYY-MM-DD format
      schema:
        type: string
        format: date
        example: '2026-01-01'
    CampaignIdCamel:
      name: campaignId
      in: query
      required: false
      description: Filter to a specific campaign
      schema:
        type: string
    OrganizationIdCamel:
      name: organizationId
      in: query
      required: false
      description: Filter to a specific descendant organization
      schema:
        type: string
    EndDate:
      name: endDate
      in: query
      required: true
      description: End date in YYYY-MM-DD format
      schema:
        type: string
        format: date
        example: '2026-01-31'
    BrandIdCamel:
      name: brandId
      in: query
      required: false
      description: Filter to a specific brand
      schema:
        type: string
  schemas:
    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
    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.
  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.