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

# Xquik support ticket API to reply to a request

> Reply to a support ticket with text, screenshots, or videos. Attach private media and read the saved message receipt. An idempotency key makes retries safe.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-support-reply-200">
      ```json theme={null}
      {
        "publicId": "tkt_a1b2c3d4e5f6a1b2c3d4e5f6",
        "attachments": []
      }
      ```
    </Tab>

    <Tab title="201" id="response-support-reply-201">
      ```json theme={null}
      {
        "publicId": "tkt_a1b2c3d4e5f6a1b2c3d4e5f6",
        "attachments": []
      }
      ```
    </Tab>

    <Tab title="400" id="response-support-reply-400">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

    <Tab title="401" id="response-support-reply-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required. Provide a valid API key or bearer token."
      }
      ```
    </Tab>

    <Tab title="404" id="response-support-reply-404">
      ```json theme={null}
      {
        "error": "not_found",
        "message": "Resource not found."
      }
      ```
    </Tab>

    <Tab title="409" id="response-support-reply-409">
      ```json theme={null}
      {
        "error": "idempotency_key_conflict",
        "message": "Reuse this Idempotency-Key only with the original request."
      }
      ```
    </Tab>

    <Tab title="429" id="response-support-reply-429">
      ```json theme={null}
      {
        "error": "rate_limit_exceeded",
        "message": "Too many requests. Try again later.",
        "retryAfter": 60
      }
      ```
    </Tab>
  </Tabs>
</Panel>

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

<Callout icon="circle-check" color="#16a34a">
  **Free.** This endpoint does not consume credits.
</Callout>

Use JSON for text-only replies. Use `multipart/form-data` when attaching media.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/support/tickets/tkt_a1b2c3d4e5f6a1b2c3d4e5f6/messages \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Idempotency-Key: replace-with-one-random-value" \
    -H "Content-Type: application/json" \
    -d '{
      "body": "That worked, thank you!"
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const ticketId = "tkt_a1b2c3d4e5f6a1b2c3d4e5f6";
  const response = await fetch(`https://xquik.com/api/v1/support/tickets/${ticketId}/messages`, {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Idempotency-Key": crypto.randomUUID(),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      body: "That worked, thank you!",
    }),
  });
  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  ticket_id = "tkt_a1b2c3d4e5f6a1b2c3d4e5f6"
  response = requests.post(
      f"https://xquik.com/api/v1/support/tickets/{ticket_id}/messages",
      headers={
          "x-api-key": "xq_YOUR_KEY_HERE",
          "Idempotency-Key": "replace-with-one-random-value",
      },
      json={"body": "That worked, thank you!"},
  )
  data = response.json()
  ```

  ```go Go theme={null}
  package main

  import (
      "bytes"
      "encoding/json"
      "fmt"
      "net/http"
  )

  func main() {
      ticketID := "tkt_a1b2c3d4e5f6a1b2c3d4e5f6"
      body, _ := json.Marshal(map[string]interface{}{
          "body": "That worked, thank you!",
      })

      req, err := http.NewRequest("POST", "https://xquik.com/api/v1/support/tickets/"+ticketID+"/messages", bytes.NewReader(body))
      if err != nil {
          panic(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")
      req.Header.Set("Idempotency-Key", "replace-with-one-random-value")
      req.Header.Set("Content-Type", "application/json")

      resp, err := http.DefaultClient.Do(req)
      if err != nil {
          panic(err)
      }
      defer resp.Body.Close()

      var data map[string]interface{}
      if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
          panic(err)
      }
      fmt.Println(data)
  }
  ```
</CodeGroup>

## Send a support reply once

Read the ticket before composing a response. Confirm its public ID, status,
latest sender, and most recent message. Another operator may
have answered already.

Choose the request format by content. Send JSON for text only.
Use multipart form fields when screenshots or videos are required.

Write a specific message body. Reference the observed problem, completed
check, or requested next step. Avoid pasting secrets, API keys, or private
browser session details.

Review every attachment before upload. Use only the documented image and video
formats. Keep each file and the combined request within the documented size
limits.

Generate one idempotency key after the text and attachments are final. Reuse
it only when the identical request loses its response. Changed text or files
require a new key.

Read each reply status:

* `201` means Xquik created the new message.
* `200` with `Idempotency-Replayed` returns the earlier message.
* `409` means the key already represents different content.
* `404` means the ticket is missing or belongs to another account.
* `429` requires waiting for `Retry-After`.

Store the ticket ID, idempotency key, reply time, and attachment receipts. Do
not store attachment bytes in shared logs.

Fetch the ticket again after creation. Confirm the message appears once and
the sender is correct. Inspect each attachment status before telling the user
that a screenshot or video is available.

## Path parameters

<ParamField path="id" type="string" required>
  The ticket public ID (for example `tkt_a1b2c3d4e5f6a1b2c3d4e5f6`). Returned when you [create a ticket](/api-reference/support/create) or [list tickets](/api-reference/support/list).
</ParamField>

## Headers

<ParamField header="x-api-key" type="string" required>
  Your API key. Session cookie authentication is also supported. Generate a key from the [dashboard](https://xquik.com/dashboard).
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Use `application/json` for text only. Use `multipart/form-data` for media.
</ParamField>

<ParamField header="Idempotency-Key" type="string">
  Generate one random value for this reply. Reuse it only when retrying identical text and attachments. A replay returns the original message with `Idempotency-Replayed: true`.
</ParamField>

## Body

<ParamField body="body" type="string" required>
  Message content. 1-10,000 characters.
</ParamField>

<ParamField body="attachments" type="file[]">
  Up to 4 JPEG, PNG, GIF, WebP, MP4, MOV, or WebM files. The same per-file and 30 MB combined limits apply.
</ParamField>

For a media-only reply, omit `body` and include at least 1 attachment.

```bash cURL With Media theme={null}
curl -X POST https://xquik.com/api/v1/support/tickets/tkt_a1b2c3d4e5f6a1b2c3d4e5f6/messages \
  -H "x-api-key: xq_YOUR_KEY_HERE" \
  -H "Idempotency-Key: replace-with-one-random-value" \
  -F "body=This recording shows the current behavior." \
  -F "attachments=@recording.mp4" | jq
```

## Response

### 201 Created

<ResponseField name="publicId" type="string">
  Public ID of the ticket that received the message.
</ResponseField>

<ResponseField name="attachments" type="object[]">
  Created media receipts.
</ResponseField>

<ResponseField name="attachments[].publicId" type="string">
  Private attachment public ID.
</ResponseField>

<ResponseField name="attachments[].status" type="string">
  Upload status: `ready` or `failed`.
</ResponseField>

```json theme={null}
{
  "publicId": "tkt_a1b2c3d4e5f6a1b2c3d4e5f6",
  "attachments": []
}
```

### 200 Replayed

Returns the original response after a safe retry. The `Idempotency-Replayed` response header is `true`.

### 400 Invalid input

```json theme={null}
{ "error": "invalid_input", "message": "Invalid input. Check the request body." }
```

Missing or invalid `body` field.

### 401 Unauthenticated

```json theme={null}
{
  "error": "unauthenticated",
  "message": "Authentication required. Provide a valid API key or bearer token."
}
```

Missing or invalid API key.

### 404 Not found

```json theme={null}
{ "error": "not_found", "message": "Resource not found." }
```

No ticket exists with this ID, or it belongs to a different account.

### 409 Conflict

The `Idempotency-Key` already belongs to different text or attachments. Generate a new key for the changed reply.

### 429 Rate limited

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Try again later.",
  "retryAfter": 60
}
```

Wait for the `Retry-After` value before adding another reply.

<Note>
  **Related.** [Support Media](/api-reference/support/media) explains private downloads and upload limits.
</Note>


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