Hail Sms API

The sms API from Hail — 5 operation(s) for sms.

GitHub OpenAPI

Operations 7

POST /v1/sms Create Sms #
GET /v1/sms List Sms #
GET /v1/sms/suppressions List Sms Suppressions #
DELETE /v1/sms/suppressions/{number} Delete Sms Suppression #
GET /v1/sms/sender-id Get Sender Id #
PATCH /v1/sms/sender-id Patch Sender Id #
GET /v1/sms/{sms_id} Get Sms #

Specifications

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/hail-so:hail-so-sms-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

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

hail-so-sms-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Hail Sms API
  description: 'Give your AI agent a voice, a real phone number, and an inbox.


    This file is the source of truth for the Go CLI. Regenerate it after

    changing API routes — see docs/public/contributing.md.'
  version: 0.1.0
servers:
- url: https://api.hail.so
  description: Hail Cloud
tags:
- name: SMS
paths:
  /v1/sms:
    post:
      tags:
      - SMS
      summary: Create Sms
      description: 'Send an outbound SMS.


        Sends synchronously — the response reports the final status (sent or

        failed), not a queued placeholder, though delivery confirmation from

        the carrier can still arrive later as a webhook or GET /v1/sms/{sms_id}

        update. An explicit from resolves a dedicated number; otherwise Hail

        picks an alphanumeric sender ID where the destination corridor allows

        it, or requires a dedicated SMS-capable number otherwise. Requires

        recipient_consent=true on the request body; Hail does not verify

        lawful basis to contact the recipient, the caller warrants it.'
      operationId: create_sms_v1_sms_post
      parameters:
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Idempotency-Key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SmsCreate'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SmsResponse'
        '429':
          description: Rate limited. The agent-origin workspace exceeded a per-channel velocity cap, or the platform kill switch is on. Retry after the Retry-After header (seconds). Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '402':
          description: insufficient credits; top up at https://hail.so/console/billing
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    get:
      tags:
      - SMS
      summary: List Sms
      description: 'List SMS messages for the caller''s organization, newest first.


        Cursor-paginated: pass the returned next_cursor to fetch the next page;

        a null next_cursor means there are no more results. Filter by status or

        destination number (to) to narrow the list.'
      operationId: list_sms_v1_sms_get
      parameters:
      - name: cursor
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Cursor
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - enum:
            - queued
            - sent
            - delivered
            - failed
            - undelivered
            - received
            type: string
          - type: 'null'
          title: Status
      - name: to
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: To
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SmsListResponse'
        '429':
          description: Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/sms/suppressions:
    get:
      tags:
      - SMS
      summary: List Sms Suppressions
      description: 'List SMS numbers suppressed from receiving messages, newest first.


        Cursor-paginated. A suppressed number blocks POST /v1/sms sends to it

        with a 403 until removed via DELETE /v1/sms/suppressions/{number}.'
      operationId: list_sms_suppressions_v1_sms_suppressions_get
      parameters:
      - name: cursor
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Cursor
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuppressionListResponse'
        '429':
          description: Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/sms/suppressions/{number}:
    delete:
      tags:
      - SMS
      summary: Delete Sms Suppression
      description: 'Remove one number from the SMS suppression list, re-allowing sends to it.


        Does not itself constitute renewed consent — the caller is responsible

        for having a lawful basis (e.g. a fresh opt-in) before sending again.

        Returns 404 if the number was not suppressed.'
      operationId: delete_sms_suppression_v1_sms_suppressions__number__delete
      parameters:
      - name: number
        in: path
        required: true
        schema:
          type: string
          title: Number
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '204':
          description: Successful Response
        '429':
          description: Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/sms/sender-id:
    get:
      tags:
      - SMS
      summary: Get Sender Id
      description: 'Get the org''s custom alphanumeric SMS sender ID, if any is set.


        effective_default is the platform sender id used for

        alphanumeric-eligible corridors when custom_sender_id is null.'
      operationId: get_sender_id_v1_sms_sender_id_get
      parameters:
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SenderIdResponse'
        '429':
          description: Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    patch:
      tags:
      - SMS
      summary: Patch Sender Id
      description: 'Set or clear the org''s custom alphanumeric SMS sender ID.


        Pass custom_sender_id=null to clear it and fall back to the platform

        default sender id. Only affects alphanumeric-eligible corridors — a

        corridor requiring a dedicated number is unaffected.'
      operationId: patch_sender_id_v1_sms_sender_id_patch
      parameters:
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SenderIdPatch'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SenderIdResponse'
        '429':
          description: Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/sms/{sms_id}:
    get:
      tags:
      - SMS
      summary: Get Sms
      description: 'Fetch one SMS by id, including its current status.


        Org-scoped: returns 404 for an SMS belonging to a different

        organization.'
      operationId: get_sms_v1_sms__sms_id__get
      parameters:
      - name: sms_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Sms Id
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SmsResponse'
        '429':
          description: Rate limited. This caller exceeded the general request-rate ceiling. Retry after the Retry-After header (seconds).
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            RateLimit-Limit:
              description: The request ceiling for the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    SmsCreate:
      properties:
        recipient_consent:
          type: boolean
          title: Recipient Consent
          description: Attestation that you have obtained the lawful consent required to contact this recipient. Hail does not verify consent itself — you are responsible for a lawful basis under TCPA/ePrivacy/PECR/CAN-SPAM/GDPR as applicable. Rejected (422) if not true.
        consent_source:
          anyOf:
          - type: string
          - type: 'null'
          title: Consent Source
          description: Where/how consent was obtained (e.g. 'signup form', 'prior customer relationship'). Required (non-empty) when message_type is 'marketing'.
        consent_obtained_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Consent Obtained At
          description: When consent was obtained, if known.
        message_type:
          type: string
          enum:
          - marketing
          - informational
          title: Message Type
          description: '''marketing'' additionally requires a non-empty consent_source. Use ''informational'' for transactional/service communications.'
          default: informational
        to:
          type: string
          title: To
          description: Recipient phone number, E.164 format (e.g. +14155551234).
        from:
          anyOf:
          - type: string
          - type: 'null'
          title: From
          description: 'Sender phone number, E.164 format. Must be an active number owned by the organization with the SMS capability. Omitted: destinations where the sender-ID carrier delivers a dynamic alphanumeric sender ID unchanged (about 110 countries: most of Europe, Africa, the Middle East, Asia-Pacific and the Caribbean; one table per carrier in core/hailhq/core/sender_id_corridors.py) use the organization''s sender ID, or the platform default ''HAIL'' when none is set; Australia (+61) may always use ''HAIL'', depending on the carrier. Every other destination, including the US and Canada, uses the organization''s oldest active SMS-capable number; if none exists the request fails with 422. SMS never uses the shared pool.'
        body:
          type: string
          maxLength: 1600
          minLength: 1
          title: Body
          description: Message text. Long bodies are split into multiple carrier segments.
        metadata:
          additionalProperties: true
          type: object
          title: Metadata
          description: Free-form JSON object attached to the message and echoed back on reads. Not interpreted by Hail.
      additionalProperties: false
      type: object
      required:
      - recipient_consent
      - to
      - body
      title: SmsCreate
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
          description: Path to the invalid field within the request, as a list of keys/indices (e.g. ['body', 'to']).
        msg:
          type: string
          title: Message
          description: Human-readable description of the validation failure.
        type:
          type: string
          title: Error Type
          description: Machine-readable error type code (e.g. 'missing', 'string_type').
        input:
          title: Input
          description: The value that was actually provided and failed validation.
        ctx:
          type: object
          title: Context
          description: Additional machine-readable context for the error, when the error type provides one.
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
          description: 'List of validation errors: each entry gives the field location (loc), the problem (msg), and the error type (type).'
      type: object
      title: HTTPValidationError
    SenderIdPatch:
      properties:
        custom_sender_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Custom Sender Id
          description: Alphanumeric sender id (2-11 characters, letters/digits only) to use on alphanumeric-eligible corridors instead of a phone number. Explicit null clears it, reverting to the platform default.
      additionalProperties: false
      type: object
      title: SenderIdPatch
    SmsResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
          description: Unique identifier for this message.
        organization_id:
          type: string
          format: uuid
          title: Organization Id
          description: Organization that sent or received this message.
        from_e164:
          type: string
          title: From E164
          description: Sender phone number, E.164 format.
        to_e164:
          type: string
          title: To E164
          description: Recipient phone number, E.164 format.
        direction:
          type: string
          enum:
          - outbound
          - inbound
          title: Direction
          description: '''outbound'' for messages Hail sent, ''inbound'' for messages received.'
        agent_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Agent Id
          description: 'The agent this text belongs to: the number''s text agent on inbound texts, the agent that wrote it on outbound texts. Null when no agent is involved.'
        status:
          type: string
          enum:
          - queued
          - sent
          - delivered
          - failed
          - undelivered
          - received
          title: Status
          description: 'Delivery status: ''queued'', ''sent'', ''delivered'', ''failed'', ''undelivered'', or ''received'' (inbound messages).'
        body:
          type: string
          title: Body
          description: Message text.
        provider_message_sid:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Message Sid
          description: The carrier/provider's identifier for this message, if assigned.
        segment_count:
          type: integer
          title: Segment Count
          description: Number of carrier SMS segments the body was split into.
        error_code:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Code
          description: Carrier error code if delivery failed. Null on success or while pending.
        requested_at:
          type: string
          format: date-time
          title: Requested At
          description: When the send was requested, ISO 8601 timestamp.
        sent_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Sent At
          description: When the message was handed to the carrier, ISO 8601 timestamp. Null until sent.
      type: object
      required:
      - id
      - organization_id
      - from_e164
      - to_e164
      - direction
      - status
      - body
      - provider_message_sid
      - segment_count
      - error_code
      - requested_at
      - sent_at
      title: SmsResponse
    SenderIdResponse:
      properties:
        custom_sender_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Custom Sender Id
          description: The organization's configured alphanumeric sender id. Null if none is set.
        effective_default:
          type: string
          title: Effective Default
          description: The platform's alphanumeric sender id, used on eligible corridors when custom_sender_id is null.
          default: HAIL
      type: object
      required:
      - custom_sender_id
      title: SenderIdResponse
    SuppressionListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/SuppressionResponse'
          type: array
          title: Items
          description: Suppressed recipients in this page.
        next_cursor:
          anyOf:
          - type: string
          - type: 'null'
          title: Next Cursor
          description: Opaque cursor for the next page. Null when there are no more results.
      type: object
      required:
      - items
      title: SuppressionListResponse
    SmsListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/SmsResponse'
          type: array
          title: Items
          description: Messages in this page, newest first.
        next_cursor:
          anyOf:
          - type: string
          - type: 'null'
          title: Next Cursor
          description: Opaque cursor for the next page. Null when there are no more results.
      type: object
      required:
      - items
      title: SmsListResponse
    SuppressionResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
          description: Unique identifier for this suppression entry.
        recipient:
          type: string
          title: Recipient
          description: The suppressed recipient — E.164 phone number for voice/sms, lowercased email address for email.
        channel:
          type: string
          title: Channel
          description: 'Channel this entry blocks sends on: ''voice'', ''email'', ''sms'', or ''all'' (every channel).'
        reason:
          type: string
          title: Reason
          description: Why the recipient was suppressed (e.g. an unsubscribe or a bounce).
        source:
          type: string
          title: Source
          description: 'How this entry was created: ''unsubscribe_link'' (email unsubscribe link) or ''stop_keyword'' (recipient replied STOP by SMS). ''manual'' (operator action) and ''bounce'' (bounce handler) are reserved; nothing writes them yet.'
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this entry was created, ISO 8601 timestamp.
      type: object
      required:
      - id
      - recipient
      - channel
      - reason
      - source
      - created_at
      title: SuppressionResponse