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

# Send a direct email to a contact

> **Send a campaign-less 1:1 email to a contact**

Compose and send a personal email straight to a contact, with no campaign
behind it. The send is anchored to a campaign-less external lead so a reply
threads into your inbox out-of-band -- it never changes campaign status,
counts or follow-ups.

## Cost

Each send deducts **1 credit** from the team balance. This is the only public
endpoint that spends credits, so it is also the only one that can return
**402 Payment Required** with `{message, required, available}`.

## Rejections

- **409 Conflict** -- the contact is suppressed (blocklisted by email or
domain, unsubscribed, or bounced). Detail carries `reason`, `block_type`,
`blocked_value` and `email`. Nothing is charged.
- **402 Payment Required** -- the team is out of credits. Nothing is sent.
- **404 Not Found** -- the contact, or the sending inbox, does not exist in
this team.
- **400 Bad Request** -- the inbox exists but is not ACTIVE.

## Choosing `inbox_id`

Look it up with `GET /sender-accounts?status=ACTIVE` and use the returned
`inbox_id`. Note that inbox resolution for this endpoint is **team-scoped**,
while `GET /sender-accounts` is **workspace-scoped**: an API key pinned to one
workspace may therefore be able to send from an inbox that the sender-accounts
list does not show. Prefer an inbox that appears in both.

## Response identifiers

- `message_id` is `<direct_<lead-hex8>@domain>`, the Message-ID stamped on the
  outbound email. Reply ingestion resolves that lead-hex on its own, which is
  what keeps a direct conversation separate from a campaign conversation with
  the same address.
- `thread_id` is the UUID of the campaign-less external thread the send -- and
  any reply -- consolidates into.
- The send is queued, not awaited: `message` reads `Email queued successfully`
  and delivery/bounce outcomes arrive later through webhooks.

## Example Usage

```python
import requests

contact_id = "550e8400-e29b-41d4-a716-446655440000"

response = requests.post(
    f"https://api.coldsend.pro/api/public/v1/contacts/{contact_id}/send-email",
    headers={"X-API-Key": "your-api-key"},
    json={
        "inbox_id": "650e8400-e29b-41d4-a716-446655440000",
        "subject": "Following up on our call",
        "body_text": "Hi -- wanted to send over the notes we discussed.",
    }
)

print(response.json())
# {
#   "success": true,
#   "message": "Email queued successfully",
#   "inbox_id": "650e8400-e29b-41d4-a716-446655440000",
#   "inbox_email": "john@yourdomain.com",
#   "recipient_email": "alice@prospect.com",
#   "message_id": "<direct_1a2b3c4d@yourdomain.com>",
#   "thread_id": "7a0e8400-e29b-41d4-a716-446655440000",
#   "credits_remaining": 1499
# }
```



## OpenAPI

````yaml /public_openapi.json post /api/public/v1/contacts/{contact_id}/send-email
openapi: 3.0.3
info:
  title: ColdSend Public API
  description: >-
    Programmatic access to ColdSend for managing cold email campaigns and sender
    accounts.
  version: 1.0.0
  contact:
    name: ColdSend Support
    email: support@coldsend.pro
    url: https://coldsend.pro
servers:
  - url: https://api.coldsend.pro
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /api/public/v1/contacts/{contact_id}/send-email:
    post:
      tags:
        - Contacts
      summary: Send a direct email to a contact
      description: >-
        **Send a campaign-less 1:1 email to a contact**


        Compose and send a personal email straight to a contact, with no
        campaign

        behind it. The send is anchored to a campaign-less external lead so a
        reply

        threads into your inbox out-of-band -- it never changes campaign status,

        counts or follow-ups.


        ## Cost


        Each send deducts **1 credit** from the team balance. This is the only
        public

        endpoint that spends credits, so it is also the only one that can return

        **402 Payment Required** with `{message, required, available}`.


        ## Rejections


        - **409 Conflict** -- the contact is suppressed (blocklisted by email or

        domain, unsubscribed, or bounced). Detail carries `reason`,
        `block_type`,

        `blocked_value` and `email`. Nothing is charged.

        - **402 Payment Required** -- the team is out of credits. Nothing is
        sent.

        - **404 Not Found** -- the contact, or the sending inbox, does not exist
        in

        this team.

        - **400 Bad Request** -- the inbox exists but is not ACTIVE.


        ## Choosing `inbox_id`


        Look it up with `GET /sender-accounts?status=ACTIVE` and use the
        returned

        `inbox_id`. Note that inbox resolution for this endpoint is
        **team-scoped**,

        while `GET /sender-accounts` is **workspace-scoped**: an API key pinned
        to one

        workspace may therefore be able to send from an inbox that the
        sender-accounts

        list does not show. Prefer an inbox that appears in both.


        ## Response identifiers


        - `message_id` is `<direct_<lead-hex8>@domain>`, the Message-ID stamped
        on the
          outbound email. Reply ingestion resolves that lead-hex on its own, which is
          what keeps a direct conversation separate from a campaign conversation with
          the same address.
        - `thread_id` is the UUID of the campaign-less external thread the send
        -- and
          any reply -- consolidates into.
        - The send is queued, not awaited: `message` reads `Email queued
        successfully`
          and delivery/bounce outcomes arrive later through webhooks.

        ## Example Usage


        ```python

        import requests


        contact_id = "550e8400-e29b-41d4-a716-446655440000"


        response = requests.post(
            f"https://api.coldsend.pro/api/public/v1/contacts/{contact_id}/send-email",
            headers={"X-API-Key": "your-api-key"},
            json={
                "inbox_id": "650e8400-e29b-41d4-a716-446655440000",
                "subject": "Following up on our call",
                "body_text": "Hi -- wanted to send over the notes we discussed.",
            }
        )


        print(response.json())

        # {

        #   "success": true,

        #   "message": "Email queued successfully",

        #   "inbox_id": "650e8400-e29b-41d4-a716-446655440000",

        #   "inbox_email": "john@yourdomain.com",

        #   "recipient_email": "alice@prospect.com",

        #   "message_id": "<direct_1a2b3c4d@yourdomain.com>",

        #   "thread_id": "7a0e8400-e29b-41d4-a716-446655440000",

        #   "credits_remaining": 1499

        # }

        ```
      operationId: send_contact_email_api_public_v1_contacts__contact_id__send_email_post
      parameters:
        - name: contact_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            title: Contact Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendContactEmailRequest'
      responses:
        '200':
          description: Email accepted and queued for sending
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendContactEmailResponse'
        '401':
          description: Missing or invalid API key
        '402':
          description: Insufficient credits
        '403':
          description: Insufficient permissions - requires 'contacts:send_email' scope
        '404':
          description: Contact or sending inbox not found in this team
        '409':
          description: Contact is suppressed and cannot be emailed
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    SendContactEmailRequest:
      properties:
        inbox_id:
          type: string
          format: uuid
          title: Inbox Id
          description: Team inbox to send from (must be ACTIVE)
        subject:
          type: string
          maxLength: 500
          title: Subject
          description: Email subject
        body_text:
          type: string
          nullable: true
          title: Body Text
          description: Plain-text body (optional if body_html provided)
        body_html:
          type: string
          nullable: true
          title: Body Html
          description: HTML body (optional if body_text provided)
        cc:
          items:
            type: string
          type: array
          nullable: true
          title: Cc
          description: CC recipients
        bcc:
          items:
            type: string
          type: array
          nullable: true
          title: Bcc
          description: BCC recipients
        attachments:
          items:
            $ref: '#/components/schemas/AttachmentItem'
          type: array
          nullable: true
          title: Attachments
          description: >-
            File attachments, base64-encoded. At most 5 files -- enforced here
            with a 422. Total size is not validated by this schema; keep it
            within what the sending provider accepts.
      additionalProperties: false
      type: object
      required:
        - inbox_id
        - subject
      title: SendContactEmailRequest
      description: >-
        Compose and send a personal 1:1 email straight to a contact.


        No campaign is involved: the send is anchored to a campaign-less
        external

        lead so the reply threads into unibox out-of-band. `body_text` or
        `body_html`

        must be provided (the service derives one from the other when only HTML
        is

        sent). Attachments reuse the reply pipeline's base64 -> GCS path.
    SendContactEmailResponse:
      properties:
        success:
          type: boolean
          title: Success
        message:
          type: string
          title: Message
        inbox_id:
          type: string
          format: uuid
          title: Inbox Id
        inbox_email:
          type: string
          title: Inbox Email
        recipient_email:
          type: string
          title: Recipient Email
        message_id:
          type: string
          title: Message Id
        thread_id:
          type: string
          format: uuid
          nullable: true
          title: Thread Id
        credits_remaining:
          type: integer
          title: Credits Remaining
          default: 0
      type: object
      required:
        - success
        - message
        - inbox_id
        - inbox_email
        - recipient_email
        - message_id
      title: SendContactEmailResponse
      description: >-
        Outcome of a direct email send.


        `message_id` is the ``<direct_<leadhex>@domain>`` stamped on the
        outbound

        email; `thread_id` is the campaign-less external thread the send (and
        any

        reply) consolidates into. `credits_remaining` is the team balance after
        the

        1-credit charge.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    AttachmentItem:
      properties:
        filename:
          type: string
          maxLength: 256
          title: Filename
          description: Attachment file name
        content_base64:
          type: string
          title: Content Base64
          description: Base64-encoded file content
        content_type:
          type: string
          maxLength: 256
          title: Content Type
          description: MIME content type
          default: application/octet-stream
      type: object
      required:
        - filename
        - content_base64
      title: AttachmentItem
      description: Schema for a single file attachment (base64-encoded).
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key with format cs_live_xxx

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.