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

# Create a composition

> Saves a new composition and records it as its first version. It sends nothing; set where it goes with `POST /v1/composition_deliveries` and send it with `deliver`. It is shared with every Studio user as an editor and has no owner, so anyone who uses Message Blaster can open, change and send it, and the API cannot make it private. A block with a link using an unsafe scheme, such as `javascript:`, is a 400 naming each problem; the full Block Kit check runs when it is sent.



## OpenAPI

````yaml /openapi-v1.json post /v1/compositions
openapi: 3.1.0
info:
  title: Tightknit Admin API
  version: 1.0.0
  description: Administrative access to a Tightknit community.
servers:
  - url: https://api.tightknit.ai
security:
  - Bearer: []
tags:
  - name: API keys
    description: Inspect the key a request authenticated with.
  - name: Awards
    description: Badges and certificates a community grants its members.
  - name: Events
    description: Read, create, update and delete events on the community calendar.
  - name: Journeys
    description: Read multi-step member programs and their milestones.
  - name: Tags
    description: The labels that classify events and content resources.
  - name: Groups
    description: The segments a community sorts its members into.
  - name: Content
    description: >-
      The collections a community files its content under, and the links and
      events in them.
  - name: Feeds
    description: The Slack channels and site-only spaces a community posts in.
  - name: Files
    description: Images and documents a community has uploaded.
  - name: Messages
    description: What a community has published.
  - name: Members
    description: The people in a community.
  - name: Slack messages
    description: >-
      Messages sent to Slack. Sending is the only operation: they cannot be
      read, edited or deleted here.
  - name: Compositions
    description: >-
      Message Blaster drafts: messages saved in Studio before, and kept after,
      they are sent to Slack channels and members. An API key sees only the
      compositions shared with every Studio user.
  - name: Follows
    description: What a member follows.
  - name: Polls
    description: The questions a community puts to its members in Slack.
  - name: Activity logs
    description: What members did in the community, and when.
  - name: System
    description: Service health.
paths:
  /v1/compositions:
    post:
      tags:
        - Compositions
      summary: Create a composition
      description: >-
        Saves a new composition and records it as its first version. It sends
        nothing; set where it goes with `POST /v1/composition_deliveries` and
        send it with `deliver`. It is shared with every Studio user as an editor
        and has no owner, so anyone who uses Message Blaster can open, change
        and send it, and the API cannot make it private. A block with a link
        using an unsafe scheme, such as `javascript:`, is a 400 naming each
        problem; the full Block Kit check runs when it is sent.
      operationId: createComposition
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompositionCreate'
      responses:
        '200':
          description: Success
          headers:
            Request-Id:
              description: Identifier for this request, quote it in support tickets.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Composition'
        default:
          description: Error
          headers:
            Request-Id:
              description: Identifier for this request, quote it in support tickets.
              schema:
                type: string
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - Bearer: []
components:
  schemas:
    CompositionCreate:
      type: object
      properties:
        label:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            The name the composition is listed under in Message Blaster. Members
            never see it.
        blocks:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                description: The Block Kit block type, such as `section`.
            required:
              - type
            additionalProperties: {}
          minItems: 1
          maxItems: 50
          description: >-
            The message, as a Slack Block Kit payload. Block types and URLs are
            checked when it is saved, and the whole payload against Slack’s
            schema before it is sent; a refusal names each problem by its block
            path.
      required:
        - label
        - blocks
      additionalProperties: false
    Composition:
      type: object
      properties:
        object:
          type: string
          enum:
            - composition
          description: Always `composition`.
        id:
          type: string
          description: Unique identifier for the object.
          example: cmps_7h2k9m4n1p6q
        created_at:
          type: string
          format: date-time
          description: When the object was created.
        updated_at:
          type: string
          format: date-time
          description: When the object was last changed.
        label:
          type: string
          description: >-
            The name the composition is listed under in Message Blaster. Members
            never see it.
        blocks:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                description: The Block Kit block type, such as `section`.
            required:
              - type
            additionalProperties: {}
          description: >-
            The message, as a Slack Block Kit payload. Each block carries a
            `block_id` once it is saved.
        status:
          type: string
          enum:
            - draft
            - scheduled
            - delivering
            - delivered
            - partially_delivered
            - failed
            - archived
          description: >-
            Where the composition is in its life. One of:

            - `draft`: not sent, and not scheduled.

            - `scheduled`: set to send at `scheduled_at`.

            - `delivering`: sending now; its deliveries report how it goes.

            - `delivered`: every delivery reached every recipient it could.

            - `partially_delivered`: some recipients were reached and some
            failed.

            - `failed`: no recipient was reached.

            - `archived`: put away in Studio.
        visibility:
          type: string
          enum:
            - studio
          description: >-
            Who can open it in Studio. Always `studio`, shared with every Studio
            user who can use Message Blaster: an API key never sees a
            composition its owner kept to themselves and the people they named.
        studio_role:
          type: string
          enum:
            - viewer
            - commenter
            - editor
          description: >-
            What every Studio user may do with it, and what an API key may do.
            One of:

            - `viewer`: read it.

            - `commenter`: read it and comment on it.

            - `editor`: also change it, set where it goes, and send it. A
            composition an API key creates is shared with `editor`.
        revision:
          type: integer
          minimum: 0
          description: >-
            A number every change increases. Send it back as `expected_revision`
            to refuse a change that would overwrite someone else’s with a 409.
        current_version_number:
          type: integer
          minimum: 0
          description: >-
            The number of its latest version: each deliberate save, and each
            send, records one.
        scheduled_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          description: >-
            When its scheduled send goes out, or went out. Null when it was
            never scheduled, was sent at once, or its schedule was canceled.
        owner_profile_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the profile that owns it in Studio. Null for one an API
            key created, or once its owner’s profile is deleted.
        owner:
          anyOf:
            - $ref: '#/components/schemas/Profile'
            - type: 'null'
          description: The profile that owns it. Present only when `owner` is expanded.
        scheduled_by_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the profile that scheduled its send. Null when it is not
            scheduled, when an API key scheduled it, or once that profile is
            deleted.
        scheduled_by:
          anyOf:
            - $ref: '#/components/schemas/Profile'
            - type: 'null'
          description: >-
            The profile that scheduled its send. Present only when
            `scheduled_by` is expanded.
        created_by_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the profile that created it. Null when an API key did, or
            once that profile is deleted.
        created_by:
          anyOf:
            - $ref: '#/components/schemas/Profile'
            - type: 'null'
          description: >-
            The profile that created it. Present only when `created_by` is
            expanded.
        updated_by_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the profile that last changed it. Null when an API key
            did, or once that profile is deleted.
        updated_by:
          anyOf:
            - $ref: '#/components/schemas/Profile'
            - type: 'null'
          description: >-
            The profile that last changed it. Present only when `updated_by` is
            expanded.
        deliveries:
          type: array
          items:
            $ref: '#/components/schemas/CompositionDelivery'
          description: >-
            Where it is set to go, and once sent, each send and how it went,
            oldest first. Present only when `deliveries` is expanded.
      required:
        - object
        - id
        - created_at
        - updated_at
        - label
        - blocks
        - status
        - visibility
        - studio_role
        - revision
        - current_version_number
        - scheduled_at
        - owner_profile_id
        - scheduled_by_id
        - created_by_id
        - updated_by_id
    Problem:
      type: object
      properties:
        type:
          type: string
          description: A URI naming the problem type. Always `about:blank`.
          example: about:blank
        title:
          type: string
          description: A short summary of the HTTP status.
          example: Not found
        status:
          type: integer
          description: The HTTP status code.
          example: 404
        detail:
          type: string
          description: What went wrong with this request, when there is more to say.
        code:
          type: string
          description: >-
            A stable, machine-readable error code to branch on, unlike `title`
            and `detail`.
          example: not_found
        param:
          type: string
          description: The request field or parameter the error is about, when one is.
        request_id:
          type: string
          description: >-
            The id of the request, also sent as the `Request-Id` header. Quote
            it in support tickets.
          example: req_9f2b8c1d4e5a6b7c8d9e0f1a2b3c4d5e
      required:
        - type
        - title
        - status
        - code
    Profile:
      type: object
      properties:
        object:
          type: string
          enum:
            - profile
          description: Always `profile`.
        id:
          type: string
          description: Unique identifier for the object.
          example: prof_9f2b8c1d4e5a
        created_at:
          type: string
          format: date-time
          description: When the object was created.
        updated_at:
          type: string
          format: date-time
          description: When the object was last changed.
        name:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The name the community shows for the member. With a linked Slack
            profile it follows the community’s name preference, or reads
            `🔒[private profile]` when `opt_out_of_public_profile` is true;
            without one it is `display_name`, falling back to `full_name`.
          example: Ada Lovelace
        full_name:
          type: string
          description: The member’s full name. Always set.
          example: Ada Lovelace
        display_name:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The shorter name the member goes by, when they set one. Null
            otherwise.
        first_name:
          anyOf:
            - type: string
            - type: 'null'
          description: The member’s first name, when known.
        last_name:
          anyOf:
            - type: string
            - type: 'null'
          description: The member’s last name, when known.
        avatar_url:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The URL of the member’s avatar, from their Slack profile when one is
            linked. Null when they have none, or when a member with a linked
            Slack profile has `opt_out_of_public_profile` on.
        email:
          anyOf:
            - type: string
            - type: 'null'
          description: The member’s email address. Null when it is not known.
          example: ada@example.com
        email_domain:
          anyOf:
            - type: string
            - type: 'null'
          description: The lowercased domain of `email`, maintained by the database.
          example: example.com
        locale:
          anyOf:
            - type: string
            - type: 'null'
          description: The member’s language and region, such as `en-US`, when known.
        is_team_member:
          type: boolean
          description: >-
            Whether the member is staff of the community rather than one of its
            people.
        is_deactivated:
          type: boolean
          description: Whether the member has been deactivated in the community.
        opt_out_of_public_profile:
          type: boolean
          description: >-
            Whether the member asked to be left out of the public member
            directory.
        member_since:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          description: >-
            When the member joined the community: their first site sign-in or
            Slack join. Null while they are invited and have not joined yet.
        invited_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          description: >-
            When an admin added the member before they joined (Studio, Admin
            API, MCP or CSV import), whether or not an invitation was sent. Kept
            after they join; null for members never added this way.
        signed_up_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          description: >-
            When the member first signed in to the community site. Unlike
            `member_since`, a Slack join never sets it. Null for members who
            have never signed in.
        source:
          type: string
          enum:
            - slack_sync
            - import
            - api
            - studio_signin
            - sso_signin
            - legacy
            - unknown
          description: >-
            How the profile was created. A Slack invitee who had not joined yet
            takes `api` or `import` when an admin then adds them. One of:

            - `slack_sync`: from Slack, through the member roster sync or the
            member joining or acting in the workspace.

            - `import`: from an admin’s bulk member import.

            - `api`: from the Admin API, Studio’s add-member form or the MCP
            server.

            - `studio_signin`: on an admin’s first Studio sign-in.

            - `sso_signin`: on a member’s first single sign-on (SSO) sign-in,
            where the site creates accounts automatically.

            - `legacy`: created before the origin was recorded.

            - `unknown`: created before the origin was recorded and before its
            Slack link, with no way left to tell how.
          example: slack_sync
        has_account:
          type: boolean
          description: >-
            Whether the member has a sign-in account. False for a Slack identity
            nobody has claimed.
        flair_group_id:
          anyOf:
            - type: string
            - type: 'null'
          description: The group whose flair the member shows beside their name.
          example: grup_7m3x9k4t8plz
        slack_profile_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Slack’s id for the member’s linked Slack profile. Null when the
            member has no Slack identity.
          example: U0BRY4S6LNQ
        integrations:
          type: object
          properties:
            slack:
              type: object
              properties:
                profile:
                  anyOf:
                    - $ref: '#/components/schemas/SlackProfile'
                    - type: 'null'
                  description: The linked Slack profile, or null when the member has none.
              required:
                - profile
              description: The member’s Slack identity.
          required:
            - slack
          description: >-
            Where the member connects to other platforms. Present only when
            `slack_profile` is expanded.
      required:
        - object
        - id
        - created_at
        - updated_at
        - name
        - full_name
        - display_name
        - first_name
        - last_name
        - avatar_url
        - email
        - email_domain
        - locale
        - is_team_member
        - is_deactivated
        - opt_out_of_public_profile
        - member_since
        - invited_at
        - signed_up_at
        - source
        - has_account
        - flair_group_id
        - slack_profile_id
    CompositionDelivery:
      type: object
      properties:
        object:
          type: string
          enum:
            - composition_delivery
          description: Always `composition_delivery`.
        id:
          type: string
          description: Unique identifier for the object.
          example: cpdl_4k8m2n6p9q3r
        created_at:
          type: string
          format: date-time
          description: When the object was created.
        updated_at:
          type: string
          format: date-time
          description: When the object was last changed.
        composition_id:
          type: string
          description: The id of the composition this delivery sends.
          example: cmps_7h2k9m4n1p6q
        composition_version_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the composition version this delivery sent. Null until the
            composition is sent, while it is only where the composition is set
            to go.
        destination:
          type: string
          enum:
            - slack_channel
            - slack_dm
          description: >-
            Where it goes. One of:

            - `slack_channel`: a post in each of `slack_channel.channel_ids`.

            - `slack_dm`: a direct message to each member `slack_dm` names,
            directly or through a group, feed or event.
        status:
          type: string
          enum:
            - pending
            - scheduled
            - delivering
            - delivered
            - partially_delivered
            - failed
            - canceled
          description: >-
            How the delivery stands. One of:

            - `pending`: set up, and not sent yet; or sent and waiting to start.

            - `scheduled`: set to go out at the composition’s `scheduled_at`.

            - `delivering`: sending now.

            - `delivered`: reached every recipient it could.

            - `partially_delivered`: reached some recipients, and some failed.

            - `failed`: reached nobody, because every recipient failed or the
            delivery could not start.

            - `canceled`: called off before it was sent.
        identity:
          anyOf:
            - type: string
              enum:
                - user
                - bot
                - community
            - type: 'null'
          description: >-
            Who it sends as. One of:

            - `bot`: the Tightknit app.

            - `community`: the app under the community name and logo; channel
            posts only.

            - `user`: the Studio user who sent it, from their own Slack account.
            An API key cannot send as one.


            Null when its settings cannot be read.
        unfurl_links:
          anyOf:
            - type: boolean
            - type: 'null'
          description: Whether Slack previews the message’s links. Null when left to Slack.
        slack_channel:
          anyOf:
            - $ref: '#/components/schemas/CompositionDeliverySlackChannel'
            - type: 'null'
          description: Where it posts. Null unless `destination` is `slack_channel`.
        slack_dm:
          anyOf:
            - $ref: '#/components/schemas/CompositionDeliverySlackDm'
            - type: 'null'
          description: Who it messages. Null unless `destination` is `slack_dm`.
        counts:
          $ref: '#/components/schemas/CompositionDeliveryCounts'
        error_code:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Why it failed as a whole, or the reason every recipient that failed
            shares, such as `outcome_unknown` when Slack could not say whether a
            message landed. Null otherwise.
        delivered_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          description: When it finished sending. Null until then.
        created_by_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the profile that set it up or sent it. Null when an API
            key did, or once that profile is deleted.
        created_by:
          anyOf:
            - $ref: '#/components/schemas/Profile'
            - type: 'null'
          description: >-
            The profile that set it up or sent it. Present only when
            `created_by` is expanded.
        updated_by_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The id of the profile that last changed it. Null when an API key or
            the send itself did, or once that profile is deleted.
        updated_by:
          anyOf:
            - $ref: '#/components/schemas/Profile'
            - type: 'null'
          description: >-
            The profile that last changed it. Present only when `updated_by` is
            expanded.
      required:
        - object
        - id
        - created_at
        - updated_at
        - composition_id
        - composition_version_id
        - destination
        - status
        - identity
        - unfurl_links
        - slack_channel
        - slack_dm
        - counts
        - error_code
        - delivered_at
        - created_by_id
        - updated_by_id
    SlackProfile:
      type: object
      properties:
        object:
          type: string
          enum:
            - slack_profile
          description: Always `slack_profile`.
        id:
          type: string
          description: Slack’s id for the member.
          example: U0BRY4S6LNQ
        created_at:
          type: string
          format: date-time
          description: When the object was created.
        updated_at:
          type: string
          format: date-time
          description: When the object was last changed.
        workspace_id:
          type: string
          description: Slack’s id for the workspace the member belongs to.
          example: T01ABC123
        display_name:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The display name the member set in Slack. Empty or null when they
            set none.
        real_name:
          anyOf:
            - type: string
            - type: 'null'
          description: The member’s full name in Slack. Null when Slack has none.
        email:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The email address on the Slack account. Null when Slack does not
            share it, as for bots.
          example: ada@example.com
        pronouns:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The pronouns the member set in Slack. Empty or null when they set
            none.
        avatar_url:
          anyOf:
            - type: string
            - type: 'null'
          description: The URL of the member’s Slack avatar. Null when Slack has none.
        locale:
          anyOf:
            - type: string
            - type: 'null'
          description: The member’s Slack language and region, such as `en-US`, when known.
        tz:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The member’s time zone in Slack, as an IANA name such as
            `America/New_York`, when known.
        is_bot:
          type: boolean
          description: Whether the account is a bot rather than a person.
        is_app_user:
          type: boolean
          description: >-
            Whether Slack reports the member as an authorized user of the
            Tightknit app.
        is_workflow_bot:
          type: boolean
          description: Whether the account is the bot behind a Slack workflow.
        is_admin:
          type: boolean
          description: Whether the member is an admin of the Slack workspace.
        is_owner:
          type: boolean
          description: Whether the member is an owner of the Slack workspace.
        is_restricted:
          type: boolean
          description: >-
            Whether the member is a Slack guest, limited to the channels they
            were invited to.
        is_invited_user:
          type: boolean
          description: Whether the member holds nothing but a still-open Slack invitation.
        is_deleted:
          type: boolean
          description: Whether Slack deactivated the account.
      required:
        - object
        - id
        - created_at
        - updated_at
        - workspace_id
        - display_name
        - real_name
        - email
        - pronouns
        - avatar_url
        - locale
        - tz
        - is_bot
        - is_app_user
        - is_workflow_bot
        - is_admin
        - is_owner
        - is_restricted
        - is_invited_user
        - is_deleted
    CompositionDeliverySlackChannel:
      type: object
      properties:
        channel_ids:
          type: array
          items:
            type: string
          description: The Slack channels it posts in, by Slack channel id.
        publish_to_site:
          type: boolean
          description: >-
            Whether each post is also published to its channel's feed on the
            community site.
        thread_ts:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The Slack message whose thread it replies in, by its `ts`. Null for
            a top-level post.
      required:
        - channel_ids
        - publish_to_site
        - thread_ts
      description: Where a channel delivery posts.
    CompositionDeliverySlackDm:
      type: object
      properties:
        member_ids:
          type: array
          items:
            type: string
          description: The ids of the profiles it messages directly.
        group_ids:
          type: array
          items:
            type: string
          description: The ids of the groups whose members it messages.
        feed_ids:
          type: array
          items:
            type: string
          description: The ids of the feeds whose members it messages.
        event_ids:
          type: array
          items:
            type: string
          description: The ids of the events whose registrants it messages.
      required:
        - member_ids
        - group_ids
        - feed_ids
        - event_ids
      description: >-
        Who a DM delivery messages. A member named several ways gets one
        message, and one since deleted is left out.
    CompositionDeliveryCounts:
      type: object
      properties:
        pending:
          type: integer
          minimum: 0
          description: How many recipients are waiting to be sent to.
        claimed:
          type: integer
          minimum: 0
          description: How many recipients are being sent to now.
        sent:
          type: integer
          minimum: 0
          description: How many recipients were sent to.
        failed:
          type: integer
          minimum: 0
          description: How many recipients could not be sent to.
        skipped:
          type: integer
          minimum: 0
          description: >-
            How many recipients were left out, such as a member who cannot get
            DMs.
      description: >-
        Its recipients by how their send stands, as last rolled up. Empty until
        the delivery starts; a status with none is absent.
  securitySchemes:
    Bearer:
      type: http
      scheme: bearer
      bearerFormat: Tightknit API key
      description: 'A Tightknit admin API key, sent as `Authorization: Bearer <key>`.'

````

## Related topics

- [Create a composition delivery](https://docs.tightknit.ai/v1/api-reference/compositions/create-a-composition-delivery.md)
- [MCP Server](https://docs.tightknit.ai/integrations/mcp.md)
- [Delete a composition delivery](https://docs.tightknit.ai/v1/api-reference/compositions/delete-a-composition-delivery.md)
- [List compositions](https://docs.tightknit.ai/v1/api-reference/compositions/list-compositions.md)
- [Update a composition](https://docs.tightknit.ai/v1/api-reference/compositions/update-a-composition.md)


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