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

# Create a contact

> Creates a contact together with any email, SMS, WhatsApp, Telegram, iMessage and push records supplied, and links the tag names given, creating tags that do not exist yet. At least one contact channel is required. The contact is returned at `data.contact` with its channel records preloaded. Requires the `contacts:write` scope.



## OpenAPI

````yaml /api-reference/openapi.json post /api/v1/user/contacts
openapi: 3.0.0
info:
  title: Brudcast API
  version: 1.0.0
servers:
  - url: https://core-service.prod.brudcast.com
    description: Production
security: []
tags:
  - name: Analytics
    x-displayName: Analytics
  - name: Campaigns
    x-displayName: Campaigns
  - name: Contacts
    x-displayName: Contacts
  - name: Mailboxes
    x-displayName: Mailboxes
  - name: Messages
    x-displayName: Messages
  - name: Sender Identities
    x-displayName: Sender Identities
  - name: Sending Domains
    x-displayName: Sending Domains
  - name: Templates
    x-displayName: Templates
  - name: Webhooks
    x-displayName: Webhooks
paths:
  /api/v1/user/contacts:
    post:
      tags:
        - Contacts
      summary: Create a contact
      description: >-
        Creates a contact together with any email, SMS, WhatsApp, Telegram,
        iMessage and push records supplied, and links the tag names given,
        creating tags that do not exist yet. At least one contact channel is
        required. The contact is returned at `data.contact` with its channel
        records preloaded. Requires the `contacts:write` scope.
      parameters:
        - in: header
          name: X-Organization-Id
          required: false
          description: >-
            Required when authenticating with an access token. Optional with an
            API key, whose own organization binding is authoritative; a value
            contradicting it is refused with 403.
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                firstName:
                  type: string
                  minLength: 1
                  maxLength: 255
                lastName:
                  type: string
                  minLength: 1
                  maxLength: 255
                displayName:
                  type: string
                  minLength: 1
                  maxLength: 255
                timezone:
                  type: string
                  maxLength: 50
                language:
                  type: string
                  maxLength: 10
                status:
                  enum:
                    - active
                    - inactive
                    - archived
                tags:
                  type: array
                  items:
                    type: string
                customFields:
                  type: object
                  additionalProperties:
                    anyOf:
                      - type: string
                      - type: number
                      - type: boolean
                      - type: array
                      - type: object
                notes:
                  type: string
                  maxLength: 5000
                emails:
                  type: array
                  items:
                    type: object
                    properties:
                      email:
                        type: string
                        format: email
                      isPrimary:
                        type: boolean
                    required:
                      - email
                    additionalProperties: false
                smsNumbers:
                  type: array
                  items:
                    type: object
                    properties:
                      phoneNumber:
                        type: string
                        minLength: 10
                        maxLength: 20
                      countryCode:
                        type: string
                        minLength: 1
                        maxLength: 3
                      isPrimary:
                        type: boolean
                    required:
                      - phoneNumber
                      - countryCode
                    additionalProperties: false
                whatsappAccounts:
                  type: array
                  items:
                    type: object
                    properties:
                      phoneNumber:
                        type: string
                        minLength: 1
                      countryCode:
                        type: string
                        minLength: 1
                      status:
                        enum:
                          - verified
                          - unverified
                          - blocked
                      isPrimary:
                        type: boolean
                      isBusinessAccount:
                        type: boolean
                    required:
                      - phoneNumber
                      - countryCode
                    additionalProperties: false
                telegramAccounts:
                  type: array
                  items:
                    type: object
                    properties:
                      phoneNumber:
                        type: string
                        minLength: 1
                      countryCode:
                        type: string
                        minLength: 1
                      username:
                        type: string
                        minLength: 1
                      isPrimary:
                        type: boolean
                    required:
                      - phoneNumber
                      - countryCode
                    additionalProperties: false
                imessageAccounts:
                  type: array
                  items:
                    type: object
                    properties:
                      appleId:
                        type: string
                        format: email
                      phoneNumber:
                        type: string
                      isPrimary:
                        type: boolean
                    required:
                      - appleId
                    additionalProperties: false
                pushNotifications:
                  type: array
                  items:
                    type: object
                    properties:
                      deviceToken:
                        type: string
                      platform:
                        enum:
                          - ios
                          - android
                          - web
                      appVersion:
                        type: string
                      deviceInfo:
                        type: object
                        additionalProperties:
                          anyOf:
                            - type: string
                            - type: number
                            - type: boolean
                            - type: array
                            - type: object
                      isPrimary:
                        type: boolean
                    required:
                      - deviceToken
                      - platform
                    additionalProperties: false
              additionalProperties: false
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      contact:
                        $ref: '#/components/schemas/ContactObject'
                    required:
                      - contact
                required:
                  - success
                  - message
                  - data
        '401':
          description: The credential is missing, malformed, revoked or expired
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: >-
            The key lacks the scope the endpoint requires, or the organization
            does not match the credential
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: The payload or query string failed validation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
        '429':
          description: >-
            Rate limit exceeded; retry after the number of seconds in
            `retryAfter`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitErrorResponse'
      security:
        - apiKey: []
        - apiKeyBearer: []
components:
  schemas:
    ContactObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organizationId:
          type: string
          format: uuid
        firstName:
          type: string
          nullable: true
        lastName:
          type: string
          nullable: true
        displayName:
          type: string
          nullable: true
          description: >-
            Derived on create from the first and last name, then the first email
            address, falling back to "Unnamed Contact"
        timezone:
          type: string
          nullable: true
          example: Africa/Lagos
        language:
          type: string
          nullable: true
          example: en
        status:
          type: string
          enum:
            - active
            - inactive
            - archived
          nullable: true
        customFields:
          type: object
          additionalProperties: true
          nullable: true
          description: Values keyed by the organization's custom field keys
        notes:
          type: string
          nullable: true
        lastActivityAt:
          type: string
          format: date-time
          nullable: true
        tags:
          type: array
          items:
            type: string
          description: >-
            Tag names, kept for compatibility with the tag records. Empty when
            the query did not load the tags
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        emails:
          type: array
          items:
            $ref: '#/components/schemas/ContactEmailObject'
        smsNumbers:
          type: array
          items:
            $ref: '#/components/schemas/ContactSmsObject'
        whatsappAccounts:
          type: array
          items:
            $ref: '#/components/schemas/ContactWhatsappObject'
        telegramAccounts:
          type: array
          items:
            $ref: '#/components/schemas/ContactTelegramObject'
        imessageAccounts:
          type: array
          items:
            $ref: '#/components/schemas/ContactImessageObject'
        pushNotifications:
          type: array
          items:
            $ref: '#/components/schemas/ContactPushNotificationObject'
        tagRecords:
          type: array
          items:
            $ref: '#/components/schemas/ContactTagObject'
        listMemberships:
          type: array
          items:
            $ref: '#/components/schemas/ContactListMembershipObject'
      required:
        - id
        - organizationId
        - firstName
        - lastName
        - displayName
        - timezone
        - language
        - status
        - customFields
        - notes
        - lastActivityAt
        - tags
        - createdAt
        - updatedAt
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string
          example: Resource not found
        code:
          type: string
          enum:
            - E_VALIDATION_ERROR
            - E_UNAUTHORIZED_ACCESS
            - E_UNAUTHORIZED
            - E_FORBIDDEN
            - E_INSUFFICIENT_SCOPE
            - E_ROW_NOT_FOUND
            - E_TOO_MANY_REQUESTS
            - E_BUSINESS_RULE_VIOLATION
            - E_CAMPAIGN_NOT_SENDABLE
            - INSUFFICIENT_CREDITS
            - SUBSCRIPTION_REQUIRED
          example: E_ROW_NOT_FOUND
      required:
        - success
        - message
        - code
    ValidationErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string
          example: The payload is invalid
        code:
          type: string
          enum:
            - E_VALIDATION_ERROR
            - E_UNAUTHORIZED_ACCESS
            - E_UNAUTHORIZED
            - E_FORBIDDEN
            - E_INSUFFICIENT_SCOPE
            - E_ROW_NOT_FOUND
            - E_TOO_MANY_REQUESTS
            - E_BUSINESS_RULE_VIOLATION
            - E_CAMPAIGN_NOT_SENDABLE
            - INSUFFICIENT_CREDITS
            - SUBSCRIPTION_REQUIRED
          example: E_VALIDATION_ERROR
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ValidationErrorItem'
      required:
        - success
        - message
        - code
        - errors
    RateLimitErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string
          example: Too many requests
        code:
          type: string
          enum:
            - E_VALIDATION_ERROR
            - E_UNAUTHORIZED_ACCESS
            - E_UNAUTHORIZED
            - E_FORBIDDEN
            - E_INSUFFICIENT_SCOPE
            - E_ROW_NOT_FOUND
            - E_TOO_MANY_REQUESTS
            - E_BUSINESS_RULE_VIOLATION
            - E_CAMPAIGN_NOT_SENDABLE
            - INSUFFICIENT_CREDITS
            - SUBSCRIPTION_REQUIRED
          example: E_TOO_MANY_REQUESTS
        retryAfter:
          type: number
          example: 60
      required:
        - success
        - message
        - code
        - retryAfter
    ContactEmailObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        organizationId:
          type: string
          format: uuid
        email:
          type: string
          format: email
          description: Stored encrypted at rest and returned in the clear
        status:
          type: string
          enum:
            - verified
            - unverified
            - bounced
            - complained
            - suppressed
        isPrimary:
          type: boolean
          description: >-
            Setting this does not demote the contact's other records on the same
            channel, so more than one can be primary at once
        bounceCount:
          type: number
        complaintCount:
          type: number
        verifiedAt:
          type: string
          format: date-time
          nullable: true
        lastBouncedAt:
          type: string
          format: date-time
          nullable: true
        lastComplainedAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - contactId
        - organizationId
        - email
        - status
        - isPrimary
        - bounceCount
        - complaintCount
        - verifiedAt
        - lastBouncedAt
        - lastComplainedAt
        - createdAt
        - updatedAt
    ContactSmsObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        phoneNumber:
          type: string
          example: '+2348012345678'
          description: Stored encrypted at rest and returned in the clear
        countryCode:
          type: string
          example: NG
        status:
          type: string
          enum:
            - verified
            - unverified
            - invalid
            - opted_out
        isPrimary:
          type: boolean
          description: >-
            Setting this does not demote the contact's other records on the same
            channel, so more than one can be primary at once
        verifiedAt:
          type: string
          format: date-time
          nullable: true
        optedOutAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - contactId
        - phoneNumber
        - countryCode
        - status
        - isPrimary
        - verifiedAt
        - optedOutAt
        - createdAt
        - updatedAt
    ContactWhatsappObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        phoneNumber:
          type: string
          example: '+2348012345678'
          description: Stored encrypted at rest and returned in the clear
        countryCode:
          type: string
          example: NG
        status:
          type: string
          enum:
            - verified
            - unverified
            - blocked
        isPrimary:
          type: boolean
          description: >-
            Setting this does not demote the contact's other records on the same
            channel, so more than one can be primary at once
        isBusinessAccount:
          type: boolean
        lastSeenAt:
          type: string
          format: date-time
          nullable: true
        verifiedAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - contactId
        - phoneNumber
        - countryCode
        - status
        - isPrimary
        - isBusinessAccount
        - lastSeenAt
        - verifiedAt
        - createdAt
        - updatedAt
    ContactTelegramObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        phoneNumber:
          type: string
          example: '+2348012345678'
          description: Stored encrypted at rest and returned in the clear
        countryCode:
          type: string
          example: NG
        username:
          type: string
          nullable: true
          description: >-
            The Telegram handle, stored encrypted at rest and returned in the
            clear
        status:
          type: string
          enum:
            - active
            - inactive
            - blocked
        isPrimary:
          type: boolean
          description: >-
            Setting this does not demote the contact's other records on the same
            channel, so more than one can be primary at once
        lastActiveAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - contactId
        - phoneNumber
        - countryCode
        - username
        - status
        - isPrimary
        - lastActiveAt
        - createdAt
        - updatedAt
    ContactImessageObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        appleId:
          type: string
          format: email
          description: Stored encrypted at rest and returned in the clear
        phoneNumber:
          type: string
          nullable: true
          example: '+2348012345678'
          description: Stored encrypted at rest and returned in the clear
        status:
          type: string
          enum:
            - verified
            - unverified
            - invalid
        isPrimary:
          type: boolean
          description: >-
            Setting this does not demote the contact's other records on the same
            channel, so more than one can be primary at once
        verifiedAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - contactId
        - appleId
        - phoneNumber
        - status
        - isPrimary
        - verifiedAt
        - createdAt
        - updatedAt
    ContactPushNotificationObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        deviceToken:
          type: string
          description: The APNs, FCM or web push registration token
        platform:
          type: string
          enum:
            - ios
            - android
            - web
        status:
          type: string
          enum:
            - active
            - inactive
            - expired
        appVersion:
          type: string
          nullable: true
          example: 3.4.1
        deviceInfo:
          type: object
          additionalProperties: true
          nullable: true
          description: Free-form device metadata supplied when the device was registered
        isPrimary:
          type: boolean
          description: >-
            Setting this does not demote the contact's other records on the same
            channel, so more than one can be primary at once
        lastUsedAt:
          type: string
          format: date-time
          nullable: true
        expiresAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - contactId
        - deviceToken
        - platform
        - status
        - appVersion
        - deviceInfo
        - isPrimary
        - lastUsedAt
        - expiresAt
        - createdAt
        - updatedAt
    ContactTagObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organizationId:
          type: string
          format: uuid
          description: >-
            Absent from the unpaginated listing, which selects the id and name
            only
        name:
          type: string
          example: newsletter
        contactCount:
          type: number
          description: >-
            Contacts carrying the tag. Reported as 0 wherever the tag is
            returned without the aggregate, which includes the unpaginated
            listing and every tag embedded in a contact or contact list
          example: 42
        createdAt:
          type: string
          format: date-time
          description: >-
            Absent from the unpaginated listing, which selects the id and name
            only
        updatedAt:
          type: string
          format: date-time
          description: >-
            Absent from the unpaginated listing, which selects the id and name
            only
      required:
        - id
        - name
        - contactCount
    ContactListMembershipObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        contactId:
          type: string
          format: uuid
        contactListId:
          type: string
          format: uuid
        status:
          type: string
          enum:
            - subscribed
            - unsubscribed
        subscribedAt:
          type: string
          format: date-time
          nullable: true
        unsubscribedAt:
          type: string
          format: date-time
          nullable: true
        unsubscribeReason:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        contact:
          $ref: '#/components/schemas/ContactSummary'
        contactList:
          $ref: '#/components/schemas/ContactListSummary'
      required:
        - id
        - contactId
        - contactListId
        - status
        - subscribedAt
        - unsubscribedAt
        - unsubscribeReason
        - createdAt
        - updatedAt
    ValidationErrorItem:
      type: object
      properties:
        field:
          type: string
          example: emailAddress
        rule:
          type: string
          example: email
        message:
          type: string
          example: The emailAddress field must be a valid email address
      required:
        - field
        - rule
        - message
    ContactSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organizationId:
          type: string
          format: uuid
        firstName:
          type: string
          nullable: true
        lastName:
          type: string
          nullable: true
        displayName:
          type: string
          nullable: true
          description: >-
            Derived on create from the first and last name, then the first email
            address, falling back to "Unnamed Contact"
        status:
          type: string
          enum:
            - active
            - inactive
            - archived
          nullable: true
        tags:
          type: array
          items:
            type: string
          description: >-
            Tag names, kept for compatibility with the tag records. Empty when
            the query did not load the tags
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        emails:
          type: array
          items:
            $ref: '#/components/schemas/ContactEmailObject'
      required:
        - id
        - organizationId
        - firstName
        - lastName
        - displayName
        - status
        - tags
        - createdAt
        - updatedAt
    ContactListSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        cuid:
          type: string
          description: Stable public identifier for the list
        organizationId:
          type: string
          format: uuid
        name:
          type: string
          example: Product announcements
        description:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - active
            - inactive
            - archived
        preferredChannels:
          type: array
          items:
            type: string
            enum:
              - email
              - sms
              - imessage
              - telegram
              - push
              - whatsapp
          description: Channels a campaign should prefer when sending to this list
        tags:
          type: array
          items:
            type: string
          description: >-
            Tag names, kept for compatibility with the tag records. Empty when
            the query did not load the tags
        isDefault:
          type: boolean
          description: Whether this is the organization's default list
        subscriberCount:
          type: number
          description: >-
            Subscribed memberships, maintained incrementally as contacts join
            and leave
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - cuid
        - organizationId
        - name
        - description
        - status
        - preferredChannels
        - tags
        - isDefault
        - subscriberCount
        - createdAt
        - updatedAt
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: >-
        An organization API key, prefixed `bk_live_`. Takes precedence over
        `Authorization` when both are sent. The key is bound to one
        organization, and the scopes it was issued with are enforced per
        endpoint.
    apiKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: bk_live_...
      description: >-
        The same organization API key sent as `Authorization: Bearer
        bk_live_...`. Accepted only when the value begins with `bk_` and no
        `X-API-Key` header is present.

````