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

# Send up to ten messages

> Reports per-entry outcomes rather than failing wholesale: in a
batch of ten, one oversized body should not cost the other nine.
The response is 200 even when every entry succeeded — the status
describes whether the request was processed, not whether every
message landed.




## OpenAPI

````yaml /api-reference/specs/queue.yaml post /v1/queues/{queue_id}/messages/batch
openapi: 3.0.3
info:
  title: Basaltic Queue API
  version: 1.0.0
  description: |
    Durable message queues with at-least-once delivery.

    **A receive is a lease, not a read.** `ReceiveMessage` hides the
    messages it returns for the queue's visibility timeout and hands back
    a *receipt handle*. The message comes back — to you or to another
    consumer — unless you delete it with that handle before the lease
    lapses. Everything else follows from this: a consumer that crashes
    mid-work loses nothing, and a message no consumer can process is
    caught by `receive_count` crossing the redrive threshold.

    **Receipt handles are per-lease, not per-message.** A new one is
    minted on every receive. Presenting a handle from a lease that has
    already lapsed fails with `QUEUE_RECEIPT_HANDLE_EXPIRED` rather than
    deleting a message that has since been handed to someone else — so a
    slow consumer finds out it was slow instead of silently destroying
    another's work.

    **Two kinds of queue, fixed at creation.** A *standard* queue
    delivers at least once with best-effort ordering and races
    consumers freely. A *FIFO* queue — whose name must end in `.fifo` —
    delivers strictly in order within a `message_group_id` and refuses
    to hand out a group's next message while an earlier one is still in
    flight; sends inside a five-minute window that repeat a
    `message_deduplication_id` collapse to one message. Ordering across
    groups is undefined, which is what lets groups run concurrently. The
    kind cannot be changed: a queue holding messages written under one
    set of rules cannot start honouring the other.

    **Long polling.** `wait_time_seconds` (up to 20) blocks the receive
    until a message arrives rather than returning empty immediately. It
    costs one request instead of the many an empty polling loop would
    make, and it returns as soon as a producer sends.

    **Message bodies are encrypted at rest.** Each queue has a data key
    that seals its messages; that key is itself wrapped by a platform key
    or, if you set `kms_key_id`, by your own. The unwrapped data key is
    cached for `kms_data_key_reuse_period_seconds` — so for up to that
    long after you disable your key, sends and receives on the queue keep
    working. Lower it to tighten that window at the cost of more KMS
    round-trips.
  contact:
    name: Basaltic Support
    email: ping@basaltic.sh
  license:
    name: Proprietary
    url: https://basaltic.sh/terms
servers:
  - url: https://queue.{region}.basaltic.sh
    description: Regional API endpoint
    variables:
      region:
        default: sa-saopaulo-1
        description: Region code
security:
  - SignatureAuth: []
tags:
  - name: Queues
    description: Queue lifecycle and attributes
  - name: Messages
    description: Sending, receiving, and acknowledging messages
paths:
  /v1/queues/{queue_id}/messages/batch:
    parameters:
      - $ref: '#/components/parameters/QueueId'
    post:
      tags:
        - Messages
      summary: Send up to ten messages
      description: |
        Reports per-entry outcomes rather than failing wholesale: in a
        batch of ten, one oversized body should not cost the other nine.
        The response is 200 even when every entry succeeded — the status
        describes whether the request was processed, not whether every
        message landed.
      operationId: sendMessageBatch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendMessageBatchRequest'
      responses:
        '200':
          description: Per-entry results.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    QueueId:
      name: queue_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
        example: a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d
  schemas:
    SendMessageBatchRequest:
      type: object
      required:
        - entries
      properties:
        entries:
          type: array
          minItems: 1
          maxItems: 10
          items:
            allOf:
              - type: object
                required:
                  - id
                properties:
                  id:
                    type: string
                    description: >-
                      Your own identifier for this entry, echoed back in the
                      result. Must be unique within the request.
                    example: e1
              - $ref: '#/components/schemas/SendMessageRequest'
    BatchResponse:
      type: object
      required:
        - results
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/BatchResult'
    SendMessageRequest:
      type: object
      required:
        - body
      properties:
        body:
          type: string
          description: >-
            The payload. Counted against the queue's max_message_bytes together
            with the attributes.
          example: '{"order_id":"A-1001"}'
        attributes:
          $ref: '#/components/schemas/MessageAttributes'
        delay_seconds:
          type: integer
          minimum: 0
          maximum: 900
          description: |
            Overrides the queue's default for this message. Rejected on
            FIFO queues, where it would let a later message become visible
            before an earlier one in the same group.
          example: 0
        message_group_id:
          type: string
          maxLength: 128
          description: |
            Required on FIFO queues, rejected on standard ones. Messages
            sharing a group are delivered in order, and a group's next
            message is withheld while an earlier one is in flight.
          example: customer-42
        message_deduplication_id:
          type: string
          maxLength: 128
          description: |
            FIFO only. A repeat within five minutes is suppressed and the
            original message's id is returned. Omit on a queue with
            `content_based_deduplication` to derive it from the body.
          example: order-A-1001
    BatchResult:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          description: The entry id from the request.
          example: e1
        message_id:
          type: string
          format: uuid
          example: 019400aa-bbbb-7ccc-8ddd-eeeeffff0000
        duplicate:
          type: boolean
          example: false
        error:
          type: string
          description: Machine-readable code when this entry failed.
          example: QUEUE_MESSAGE_TOO_LARGE
        message:
          type: string
          description: Human-readable reason accompanying error.
          example: message is 300000 bytes; this queue accepts 262144
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - request_id
          properties:
            code:
              type: string
              description: Error code identifying the type of error
              example: INVALID_INPUT
            message:
              type: string
              description: Human-readable error message
              example: Invalid request parameters
            request_id:
              type: string
              format: uuid
              description: Request ID for debugging
              example: 550e8400-e29b-41d4-a716-446655440000
    MessageAttributes:
      type: object
      description: |
        Typed attributes carried alongside the body. At most 20; values at
        most 1024 characters. `Binary` values are standard base64. The
        queue never coerces a value — it only checks the value is
        representable as the declared type.
      additionalProperties:
        type: object
        required:
          - type
          - value
        properties:
          type:
            type: string
            enum:
              - String
              - Number
              - Binary
            example: String
          value:
            type: string
            example: critical
      example:
        severity:
          type: String
          value: critical
        attempt:
          type: Number
          value: '2'
  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INVALID_INPUT
              message: Invalid request parameters
              request_id: 550e8400-e29b-41d4-a716-446655440000
    Unauthorized:
      description: Authentication required or token invalid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHORIZED
              message: Authentication required
              request_id: 550e8400-e29b-41d4-a716-446655440000
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: ACCESS_DENIED
              message: You don't have permission to perform this action
              request_id: 550e8400-e29b-41d4-a716-446655440000
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: NOT_FOUND
              message: Resource not found
              request_id: 550e8400-e29b-41d4-a716-446655440000
  securitySchemes:
    SignatureAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >
        Request signing with an access key issued to a service account. An

        HMAC-SHA256 over a canonical form of the request, close to AWS SigV4.

        The `basaltic` CLI signs for you.


        Send `Authorization`, `X-Date` (UTC, `YYYYMMDDTHHMMSSZ`) and `X-Nonce`

        (random per request); add `X-Content-Sha256` to bind a body, and

        `X-Amz-Security-Token` when using temporary credentials.


        ```

        Authorization: BASALTIC-HMAC-SHA256
        Credential=<access_key_id>/<date>/<region>/basaltic/basaltic_request,
        SignedHeaders=host;x-date;x-nonce, Signature=<hex>

        ```


        `<region>` is the region code you are calling, or `global` for the
        global

        services. A signature is valid for 5 minutes from `X-Date`, and mutating

        requests are replay-guarded on the nonce.


        **Full signing procedure, including a working implementation:**

        https://docs.basaltic.sh/authentication


        ## Rate limits

        There is no global request budget. A limit applies only where an

        operation documents a `429`, and that operation says what it counts.

        Those responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`,

        `X-RateLimit-Reset` and, on a `429`, `Retry-After` — read them rather

        than hard-coding a number. Retrying before `Retry-After` is refused and

        extends the window. Everything else is bounded by quota, not by request

        rate.

````