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

# Update scheduled message

> You can only edit schedules that have not been sent yet:

| Status | Editable | Response |
| --- | --- | --- |
| `PENDENTE` | yes | Waiting for the scheduled time. |
| `ERRO` | yes | Sending failed. Editing reschedules it. |
| `AGENDADA` | no | `409 ERR_API_SCHEDULE_NOT_EDITABLE`. The message is already queued for sending. |
| `ENVIADA` | no | `409 ERR_API_SCHEDULE_ALREADY_SENT` |
| `CANCELADA` | no | `409 ERR_API_SCHEDULE_CANCELED`. Create a new schedule. |

If you change the channel of a schedule that uses a template, send `template` again. A template
approved on the old channel may not exist on the new one.

**Media:** on unofficial WhatsApp channels (`web_whatsapp`, `web_whatsapp_premium`), the
file can be sent along with the request, as `multipart/form-data` in the `file` field. On these channels the
file is the message itself and `body` becomes the caption. With an attachment, the text is no longer required.

On an official channel, an attachment is only accepted when the template has a media header. Otherwise
the response is `400 ERR_API_TEMPLATE_MEDIA_NOT_ALLOWED`, because Meta does not accept
standalone attachments.



## OpenAPI

````yaml /api-reference/openapi.en.yaml put /schedules/{id}
openapi: 3.0.3
info:
  title: Connecta DESK Public API
  version: 1.0.0
  description: >-
    Public API of Connecta DESK, available at `/api/v1`. Access uses a token
    generated in the tokens module. Each token has permissions per **module ×
    method**, and every list read is paginated.


    ## Authentication


    ```

    Authorization: Bearer sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

    ```


    The token belongs to a **company**, not to a user. The company used is
    always the token's company, so sending `companyId` in the body has no
    effect. A missing, invalid, revoked or expired token gets the same `401`
    response.


    ## Order of checks


    1. **token** → `401`

    2. **active company** → `403`

    3. **API enabled on the plan** → `403 ERR_API_NOT_ENABLED` (does not apply
    to on-premise)

    4. **company rate limit** → `429`

    5. **token permission** → `403 ERR_API_FORBIDDEN_SCOPE`


    ## User ids


    Every user id in the API is the user's id **in this company**, the same one
    `GET /users` returns. This applies to what the API returns (`user.id`,
    `assignedTo.id`, `userCreated.id`) and to what it accepts (`userId`,
    `userIds`, `assignedToUserId` and the `{id}` in user routes).


    The same person can work in several companies, with a different name and
    profile in each one, and has a different id in each company.


    An id that does not belong to this company returns `404`, with the same
    message as an id that does not exist.


    ## Pagination


    Every list `GET` is paginated. The `meta` contains only `page`, `perPage`
    and `hasMore`, without the total number of records. To go through
    everything, keep advancing `page` while `hasMore` is `true`.


    ## Idempotency


    Optional on `POST`/`PUT`, through the `Idempotency-Key` header. If you
    repeat the call with the same key and the same body, you get the stored
    response (with `Idempotent-Replay: true`). With the same key and a different
    body, the response is `409`.
servers:
  - url: https://api.connectadesk.com/api/v1
    description: Production
security:
  - apiToken: []
tags:
  - name: contacts
    description: Contact records, extra fields and marketing source.
  - name: tickets
    x-displayName: Tickets
    description: Opening, transferring, closing and wrap-up of tickets.
  - name: messages
    description: Asynchronous sending and reading of messages.
  - name: tags
    description: Tags and their link to tickets.
  - name: queues
    description: Service queues and their agents.
  - name: wrapups
    description: Wrap-up types.
  - name: users
    description: Agents and administrators.
  - name: schedules
    description: Scheduled messages.
  - name: quick-messages
    description: Quick replies.
  - name: campaigns
    description: Bulk sending.
  - name: crm
    description: Boards, stages, cards and metrics.
  - name: channels
    description: Channels (read only).
  - name: reports
    description: Reports and dashboards.
  - name: products
    description: Product catalog, categories and sales performance.
  - name: custom-fields
    description: Custom fields for contacts and cards, plus company-wide global variables.
  - name: profiles
    description: Company permission profiles (read only).
  - name: webchat
    description: >-
      Native webchat from your own system: open a visitor session, send and read
      messages. The token needs the `webchat` scope (GET and POST).
paths:
  /schedules/{id}:
    parameters:
      - $ref: '#/components/parameters/idParam'
    put:
      tags:
        - schedules
      summary: Update scheduled message
      description: >-
        You can only edit schedules that have not been sent yet:


        | Status | Editable | Response |

        | --- | --- | --- |

        | `PENDENTE` | yes | Waiting for the scheduled time. |

        | `ERRO` | yes | Sending failed. Editing reschedules it. |

        | `AGENDADA` | no | `409 ERR_API_SCHEDULE_NOT_EDITABLE`. The message is
        already queued for sending. |

        | `ENVIADA` | no | `409 ERR_API_SCHEDULE_ALREADY_SENT` |

        | `CANCELADA` | no | `409 ERR_API_SCHEDULE_CANCELED`. Create a new
        schedule. |


        If you change the channel of a schedule that uses a template, send
        `template` again. A template

        approved on the old channel may not exist on the new one.


        **Media:** on unofficial WhatsApp channels (`web_whatsapp`,
        `web_whatsapp_premium`), the

        file can be sent along with the request, as `multipart/form-data` in the
        `file` field. On these channels the

        file is the message itself and `body` becomes the caption. With an
        attachment, the text is no longer required.


        On an official channel, an attachment is only accepted when the template
        has a media header. Otherwise

        the response is `400 ERR_API_TEMPLATE_MEDIA_NOT_ALLOWED`, because Meta
        does not accept

        standalone attachments.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                sendAt:
                  type: string
                  format: date-time
                  description: >-
                    Date and time of the send, in ISO 8601. It must be a future
                    date.


                    **Without a time zone, your company's time zone applies.**
                    `2026-09-15T09:00:00` sends at

                    nine in the morning in the time zone set on the company.
                    With an explicit offset

                    (`2026-09-15T09:00:00-03:00`) or in UTC (`Z`), the value is
                    respected as it is.
                  example: '2026-09-15T09:00:00-03:00'
                contactId:
                  type: integer
                  description: Contact this record belongs to.
                  example: 1042
                channelId:
                  type: integer
                  description: >-
                    Channel where the conversation takes place. See the
                    available channels at `GET /channels`.
                  example: 4
                body:
                  type: string
                  description: Message text, on free-text channels.
                  example: 'Lembrete: sua consulta é amanhã às 14h.'
                template:
                  allOf:
                    - $ref: '#/components/schemas/TemplateInput'
                  description: >-
                    Message template, on official WhatsApp channels. It is
                    validated again on every update.
                userId:
                  type: integer
                  description: >-
                    User id in this company, the same one `GET /users` returns.
                    The same person has a different id in each company they work
                    in.
                  example: 3
                queueId:
                  type: integer
                  description: Service queue.
                  example: 7
          multipart/form-data:
            schema:
              type: object
              properties:
                sendAt:
                  type: string
                  format: date-time
                  description: >-
                    Date and time of the send, in ISO 8601. It must be a future
                    date.


                    **Without a time zone, your company's time zone applies.**
                    `2026-09-15T09:00:00` sends at

                    nine in the morning in the time zone set on the company.
                    With an explicit offset

                    (`2026-09-15T09:00:00-03:00`) or in UTC (`Z`), the value is
                    respected as it is.
                  example: '2026-09-15T09:00:00-03:00'
                contactId:
                  type: integer
                  description: Contact this record belongs to.
                  example: 1042
                channelId:
                  type: integer
                  description: >-
                    Channel where the conversation takes place. See the
                    available channels at `GET /channels`.
                  example: 4
                body:
                  type: string
                  description: Caption for the attached file.
                  example: 'Lembrete: sua consulta é amanhã às 14h.'
                userId:
                  type: integer
                  description: >-
                    User id in this company, the same one `GET /users` returns.
                    The same person has a different id in each company they work
                    in.
                  example: 3
                queueId:
                  type: integer
                  description: Service queue.
                  example: 7
                file:
                  type: string
                  format: binary
                  description: >-
                    Attached file. The rules for each channel type are in the
                    endpoint description.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Schedule'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: >-
            The schedule's current status does not allow editing. The possible
            codes are

            `ERR_API_SCHEDULE_ALREADY_SENT`, `ERR_API_SCHEDULE_CANCELED` and
            `ERR_API_SCHEDULE_NOT_EDITABLE`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
components:
  parameters:
    idParam:
      name: id
      in: path
      required: true
      schema:
        type: integer
      example: 1042
  schemas:
    TemplateInput:
      type: object
      description: >-
        The **simple** way to send a template. You provide the name and the
        parameters, and the system finds the template on the channel, checks
        that the parameters match what it requires and builds the message in
        Meta's format.
      required:
        - name
      properties:
        name:
          type: string
          description: >-
            Exact name of the approved template. You can look it up at `GET
            /channels/{id}/templates`.
          example: confirmacao_pedido
        language:
          type: string
          description: >-
            Template language. Only needed when there is more than one template
            with the same name in different languages.
          example: pt_BR
        parameters:
          type: object
          properties:
            body:
              type: array
              description: One item per `{{n}}` variable in the body, in order.
              items:
                type: string
              example:
                - Maria
                - '12345'
            header:
              type: array
              description: >-
                One item per variable in a text header. A media header does not
                use this field.
              items:
                type: string
          example:
            - Marina
            - '88213'
      example:
        name: confirmacao_pedido
        parameters:
          body:
            - Maria
            - '12345'
    Schedule:
      type: object
      properties:
        id:
          type: integer
        body:
          type: string
        sendAt:
          type: string
          format: date-time
          example: '2026-09-15T09:00:00.000Z'
        sentAt:
          type: string
          format: date-time
          nullable: true
        status:
          type: string
          nullable: true
        contact:
          type: object
          nullable: true
          description: >-
            Full contact data, with tags, custom fields and marketing fields.
            You do not need to call `GET /contacts/{id}` to complete the list.
          allOf:
            - $ref: '#/components/schemas/Contact'
        user:
          type: object
          nullable: true
          properties:
            id:
              type: integer
            name:
              type: string
              description: Display name.
        channelId:
          type: integer
          nullable: true
          example: 4
        mediaPath:
          type: string
          nullable: true
        mediaName:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      example:
        id: 318
        body: Oi {{name}}, sua reserva vence amanhã!
        sendAt: '2026-08-20T13:00:00.000Z'
        sentAt: null
        status: pending
        contact:
          id: 842
          name: Maria Silva
          number: '5511987654321'
          numberCountry: BR
          email: maria.silva@exemplo.com.br
          code: CLI-00842
          cpfCnpj: '12345678909'
          origin: site
          profilePicUrl: https://cdn.exemplo.com/avatars/842.jpg
          isGroup: false
          instagramUsername: maria.silva
          lid: null
          sourceUrl: https://loja.exemplo.com.br/promo
          sourceId: '23851234567890123'
          headline: Coleção de inverno
          mediaType: image
          mediaUrl: https://cdn.exemplo.com/anuncios/inverno.jpg
          utmSource: instagram
          utmMedium: cpc
          utmCampaign: inverno-2026
          utmId: '6543210987'
          fbclid: IwAR0xYzAbC123
          gclid: null
          ctwaClid: null
          tags:
            - id: 3
              name: Cliente VIP
              color: '#6941C6'
          customFields:
            - key: plano
              value: Ouro
              customFieldId: 91
              name: Plano
              type: select
          lastChannel:
            id: 11
            name: Instagram Loja
            type: instagram
          createdAt: '2026-07-14T13:22:05.412Z'
          updatedAt: '2026-08-18T09:41:17.883Z'
        user:
          id: 3
          name: Gabriel Goulart
        channelId: 11
        mediaPath: null
        mediaName: null
        createdAt: '2026-08-18T15:10:00.000Z'
        updatedAt: '2026-08-18T15:10:00.000Z'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Fixed error code, so your system can handle each case.
              example: ERR_API_FORBIDDEN_SCOPE
            message:
              type: string
            details: {}
    Contact:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
          description: Display name.
        number:
          type: string
        numberCountry:
          type: string
          nullable: true
          description: >-
            Country of the number, as an ISO 3166-1 alpha-2 code. Inferred from
            the country code when the number is saved through the API.
          example: BR
        email:
          type: string
          nullable: true
          example: marina@exemplo.com.br
        code:
          type: string
          nullable: true
        cpfCnpj:
          type: string
          nullable: true
          example: '12345678909'
        origin:
          type: string
          nullable: true
        profilePicUrl:
          type: string
          nullable: true
          example: https://cdn.exemplo.com.br/avatar/1042.jpg
        isGroup:
          type: boolean
          description: The contact is a group, not a person.
        instagramUsername:
          type: string
          nullable: true
          example: marina.alves
        lid:
          type: string
          nullable: true
          example: '178452961234567'
        sourceUrl:
          type: string
          nullable: true
          example: https://loja.exemplo.com.br/promo
        sourceId:
          type: string
          nullable: true
          example: '23851234567890123'
        headline:
          type: string
          nullable: true
          example: Coleção de inverno
        mediaType:
          type: string
          nullable: true
          example: image
        mediaUrl:
          type: string
          nullable: true
          example: https://cdn.exemplo.com.br/anuncios/inverno.jpg
        utmSource:
          type: string
          nullable: true
          example: instagram
        utmMedium:
          type: string
          nullable: true
          example: cpc
        utmCampaign:
          type: string
          nullable: true
          example: inverno-2026
        utmId:
          type: string
          nullable: true
          example: '6543210987'
        fbclid:
          type: string
          nullable: true
          example: IwAR0xYzAbC123
        gclid:
          type: string
          nullable: true
        ctwaClid:
          type: string
          nullable: true
        tags:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              name:
                type: string
                description: Display name.
              color:
                type: string
                description: Color in hexadecimal, with `#`.
                example: '#6941C6'
        customFields:
          type: array
          description: >-
            Contact custom fields that are filled in. Always included in the
            response, as an empty list when the contact has none.
          items:
            $ref: '#/components/schemas/CustomFieldValue'
        lastChannel:
          type: object
          nullable: true
          properties:
            id:
              type: integer
            name:
              type: string
              description: Display name.
            type:
              type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      example:
        id: 842
        name: Maria Silva
        number: '5511987654321'
        numberCountry: BR
        email: maria.silva@exemplo.com.br
        code: CLI-00842
        cpfCnpj: '12345678909'
        origin: site
        profilePicUrl: https://cdn.exemplo.com/avatars/842.jpg
        isGroup: false
        instagramUsername: maria.silva
        lid: null
        sourceUrl: https://loja.exemplo.com.br/promo
        sourceId: '23851234567890123'
        headline: Coleção de inverno
        mediaType: image
        mediaUrl: https://cdn.exemplo.com/anuncios/inverno.jpg
        utmSource: instagram
        utmMedium: cpc
        utmCampaign: inverno-2026
        utmId: '6543210987'
        fbclid: IwAR0xYzAbC123
        gclid: null
        ctwaClid: null
        tags:
          - id: 3
            name: Cliente VIP
            color: '#6941C6'
        customFields:
          - key: plano
            value: Ouro
            customFieldId: 91
            name: Plano
            type: select
        lastChannel:
          id: 11
          name: Instagram Loja
          type: instagram
        createdAt: '2026-07-14T13:22:05.412Z'
        updatedAt: '2026-08-18T09:41:17.883Z'
    CustomFieldValue:
      type: object
      description: >-
        Value of a custom field, together with the field's definition. This way
        you do not need to call `GET /custom-fields` to find out what field 91
        is.
      properties:
        key:
          type: string
          nullable: true
          description: >-
            Fixed identifier of the field. Use it to point to the field when
            saving values, because the `name` can be renamed in the panel and
            the integration would stop working without warning.
        value:
          type: string
          description: Value filled in for the field, in the format defined by its type.
        customFieldId:
          type: integer
          description: Id of the custom field definition.
          example: 91
        name:
          type: string
          nullable: true
          description: Display name.
        type:
          type: string
          nullable: true
          description: Field type, which defines the format accepted for the value.
      example:
        key: plano
        value: Ouro
        customFieldId: 91
        name: Plano
        type: select
  responses:
    NotFound:
      description: >-
        The resource does not exist or belongs to another company. For security,
        the response is the same in both cases.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: ERR_API_NOT_FOUND
              message: Registro não encontrado.
    UnprocessableEntity:
      description: >-
        The body is well formed, but a required field is missing or a value is
        not accepted. For example, `application` other than `contact`/`card`, an
        empty `orderedIds` or a blank `name`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: ERR_API_VALIDATION
              message: >-
                O parâmetro `application` é obrigatório e aceita "contact" ou
                "card".
  securitySchemes:
    apiToken:
      type: http
      scheme: bearer
      description: API token in the `sk_live_…` format.

````

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