> ## Documentation Index
> Fetch the complete documentation index at: https://docs.politicalcomms.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Project

> Create a new project in draft status. Broadcast type only.

**Phone numbers.** Assign one or more sending numbers via `phone_number_ids` (up to 49). The project spreads new conversations randomly across the assigned numbers, and once a recipient has been messaged from a given number every later message to that recipient comes from the same number (sticky sender). A single legacy `phone_number_id` is still accepted and is treated as a one-element `phone_number_ids`.

**Channel.** `channel` defaults to `10dlc`. A `10dlc` project routes through a brand + campaign, so `brand_id` and `campaign_id` are required (and `toll_free_verification_id` must be omitted). A `toll-free` project has no brand/campaign; instead `toll_free_verification_id` is required and the chosen `phone_number_ids` must be toll-free numbers belonging to that verification (`brand_id`/`campaign_id` must be omitted).

When `link_tracking_enabled` is `true`, `link_tracking_destination_url` and `link_tracking_domain_id` become required.



## OpenAPI

````yaml /api-reference/openapi.json post /projects
openapi: 3.1.0
info:
  title: Political Comms 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), 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 Keys 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 100 requests per hour per key.


    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.0.0
  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
servers:
  - url: https://api.politicalcomms.com/v1
    description: Production
security:
  - ApiKeyAuth: []
tags:
  - name: Organizations
    description: List descendant organizations and hierarchy.
  - name: Brands
    description: List brands across your organization hierarchy.
  - name: Campaigns
    description: List campaigns across your organization hierarchy.
  - name: Tracking Domains
    description: >-
      List active link-tracking domains. Use the returned ids as
      `link_tracking_domain_id` on project create/update.
  - name: Phone Numbers
    description: List phone numbers across 10DLC campaigns and toll-free verifications.
  - name: Toll-Free Verifications
    description: >-
      List toll-free verifications (carrier registrations) across your
      organization hierarchy.
  - name: Contact Lists
    description: List, import, and analyze contact lists.
  - name: Media Files
    description: List, import, and fetch media files.
  - name: Projects
    description: Create, edit, test, schedule, and inspect projects.
  - name: Analytics
    description: Message statistics and delivery performance.
  - name: Billing
    description: Usage and billing data across your organization.
paths:
  /projects:
    post:
      tags:
        - Projects
      summary: Create Project
      description: >-
        Create a new project in draft status. Broadcast type only.


        **Phone numbers.** Assign one or more sending numbers via
        `phone_number_ids` (up to 49). The project spreads new conversations
        randomly across the assigned numbers, and once a recipient has been
        messaged from a given number every later message to that recipient comes
        from the same number (sticky sender). A single legacy `phone_number_id`
        is still accepted and is treated as a one-element `phone_number_ids`.


        **Channel.** `channel` defaults to `10dlc`. A `10dlc` project routes
        through a brand + campaign, so `brand_id` and `campaign_id` are required
        (and `toll_free_verification_id` must be omitted). A `toll-free` project
        has no brand/campaign; instead `toll_free_verification_id` is required
        and the chosen `phone_number_ids` must be toll-free numbers belonging to
        that verification (`brand_id`/`campaign_id` must be omitted).


        When `link_tracking_enabled` is `true`, `link_tracking_destination_url`
        and `link_tracking_domain_id` become required.
      operationId: createProject
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - organization_id
                - phone_number_ids
                - name
                - protocol
                - contact_list_ids
                - message_text
              properties:
                organization_id:
                  type: string
                channel:
                  type: string
                  enum:
                    - 10dlc
                    - toll-free
                  default: 10dlc
                  description: Messaging channel. Defaults to 10dlc.
                brand_id:
                  type: string
                  description: Required when channel=10dlc; omit when channel=toll-free.
                campaign_id:
                  type: string
                  description: Required when channel=10dlc; omit when channel=toll-free.
                toll_free_verification_id:
                  type: string
                  description: >-
                    Required when channel=toll-free; omit when channel=10dlc.
                    Must match the verification behind the chosen
                    phone_number_ids.
                phone_number_ids:
                  type: array
                  items:
                    type: string
                  minItems: 1
                  maxItems: 49
                  description: >-
                    Sending phone number IDs (1-49). New conversations are
                    spread randomly across them; each recipient is then pinned
                    to one number (sticky sender).
                phone_number_id:
                  type: string
                  deprecated: true
                  description: >-
                    Deprecated — use phone_number_ids. A single id is accepted
                    and treated as a one-element phone_number_ids. Provide one
                    of phone_number_ids or phone_number_id.
                name:
                  type: string
                protocol:
                  type: string
                  enum:
                    - sms
                    - mms
                contact_list_ids:
                  type: array
                  items:
                    type: string
                suppression_list_ids:
                  type: array
                  items:
                    type: string
                message_text:
                  type: string
                media_ids:
                  type: array
                  items:
                    type: string
                link_tracking_enabled:
                  type: boolean
                link_tracking_destination_url:
                  type: string
                  format: uri
                link_tracking_domain_id:
                  type: string
                link_tracking_param_field:
                  type: string
                  maxLength: 64
                  description: >-
                    Contact field appended as a redirect query param on tracking
                    links. Use 'phone', a contact custom-field name, or omit for
                    no param (default). The field's name becomes the query-param
                    key; the contact's value is the value.
            examples:
              10dlc:
                summary: 10DLC project (brand + campaign)
                value:
                  organization_id: 01HX0000000000000000000000
                  channel: 10dlc
                  brand_id: 01HX0000000000000000000001
                  campaign_id: 01HX0000000000000000000002
                  phone_number_ids:
                    - 01HX0000000000000000000003
                    - 01HX0000000000000000000006
                  name: Spring Outreach
                  protocol: sms
                  contact_list_ids:
                    - 01HX0000000000000000000004
                  suppression_list_ids: []
                  message_text: >-
                    Hi {first_name}, early voting starts Monday. More info:
                    {link}
                  media_ids: []
                  link_tracking_enabled: true
                  link_tracking_destination_url: https://example.com/vote
                  link_tracking_domain_id: 01HX0000000000000000000005
                  link_tracking_param_field: voter_id
              toll-free:
                summary: Toll-free project (verification)
                value:
                  organization_id: 01HX0000000000000000000000
                  channel: toll-free
                  toll_free_verification_id: 01HX00000000000000000000T0
                  phone_number_ids:
                    - 01HX00000000000000000000T1
                  name: Spring Outreach (TFN)
                  protocol: sms
                  contact_list_ids:
                    - 01HX0000000000000000000004
                  suppression_list_ids: []
                  message_text: Hi {first_name}, early voting starts Monday.
                  media_ids: []
      responses:
        '200':
          description: Project created (in draft status)
          content:
            application/json:
              example:
                success: true
                data:
                  id: proj_new123
                  name: Spring Outreach
                  status: draft
                  channel: 10dlc
                  organization_id: 01HX0000000000000000000000
                  brand_id: 01HX0000000000000000000001
                  campaign_id: 01HX0000000000000000000002
                  toll_free_verification_id: null
                  phone_number_ids:
                    - 01HX0000000000000000000003
                    - 01HX0000000000000000000006
                  protocol: sms
                  message_text: >-
                    Hi {first_name}, early voting starts Monday. More info:
                    {link}
                  created_at: '2026-03-20T11:00:00Z'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  responses:
    BadRequest:
      description: Invalid parameters or malformed request
      content:
        application/json:
          example:
            success: false
            error: Invalid request parameters
            code: BAD_REQUEST
            statusCode: 400
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          example:
            success: false
            error: The provided API key is invalid or has been revoked
            code: INVALID_API_KEY
            statusCode: 401
    RateLimited:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          description: Maximum requests allowed in the current window
          schema:
            type: integer
        X-RateLimit-Remaining:
          description: Requests remaining in the current window
          schema:
            type: integer
        X-RateLimit-Reset:
          description: Unix timestamp (seconds) when the limit resets
          schema:
            type: integer
      content:
        application/json:
          example:
            success: false
            error: >-
              Rate limit exceeded. Try again after the X-RateLimit-Reset
              timestamp.
            code: RATE_LIMIT_EXCEEDED
            statusCode: 429
  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.

````