# Media actions

> Media: 7 Xholic actions (3 read, 4 change), each with its MCP tool, REST endpoint and CLI command.

Source: https://docs.xholic.ai/actions/media/

7 actions. Every field marked *Required* must be sent; `account`, `dryRun`, `idempotencyKey`, `confirmCredits` and `quoteId` are the [control fields](/api/responses/#control-fields) every surface adds.

## Upload media

`media.create_upload` · write

Start a media upload (image, GIF or video). Returns a mediaId and an upload URL; PUT the file bytes there, then call media.complete_upload. Video works too.

- **MCP tool:** `upload_media`. Loaded by default in MCP clients.
- **REST:** `POST /v1/media/create-upload`
- **CLI:** `xholic media create-upload`
- **Scope:** `write`
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `write`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `originalFilename` | string ≤ 255 chars | Yes |  |
| `mimeType` | string ≤ 100 chars | Yes |  |
| `byteSize` | integer ≤ 536870912 | Yes |  |
| `kind` | "IMAGE" \\| "VIDEO" | Yes |  |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |
| `dryRun` | boolean | No | Return exactly what would happen without doing it. |
| `idempotencyKey` | string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |

## Finish a media upload

`media.complete_upload` · write

Mark an upload finished after the bytes were PUT to the upload URL. Multipart uploads pass their parts.

- **MCP tool:** `media_complete_upload`. Catalog: reach it with `find_actions` and `run_write_action`, or turn on the full toolset.
- **REST:** `POST /v1/media/complete-upload`
- **CLI:** `xholic media complete-upload`
- **Scope:** `write`
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `write`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mediaId` | string ≤ 200 chars | Yes |  |
| `parts` | array of object (max 10000) | No |  |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |
| `dryRun` | boolean | No | Return exactly what would happen without doing it. |
| `idempotencyKey` | string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |

## Media status

`media.get` · read

One uploaded media item's state. Poll it while a video is still processing.

- **MCP tool:** `media_get`. Catalog: reach it with `find_actions` and `run_read_action`, or turn on the full toolset.
- **REST:** `GET /v1/media/get`
- **CLI:** `xholic media get`
- **Scope:** `read`
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `read`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mediaId` | string (uuid) | Yes |  |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |

## Media preview link

`media.preview` · read

A short-lived URL to view an uploaded media item.

- **MCP tool:** `media_preview`. Catalog: reach it with `find_actions` and `run_read_action`, or turn on the full toolset.
- **REST:** `GET /v1/media/preview`
- **CLI:** `xholic media preview`
- **Scope:** `read`
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `read`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mediaId` | string (uuid) | Yes |  |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |

## Delete uploaded media

`media.delete` · write

Delete an uploaded media item that no post uses. Call it only when the user asked for this in the conversation; never on your own initiative.

- **MCP tool:** `media_delete`. Catalog: reach it with `find_actions` and `run_write_action`, or turn on the full toolset.
- **REST:** `POST /v1/media/delete`
- **CLI:** `xholic media delete`
- **Scope:** `write`. Destructive: it can't be taken back
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `write`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mediaId` | string (uuid) | Yes |  |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |
| `dryRun` | boolean | No | Return exactly what would happen without doing it. |
| `idempotencyKey` | string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |

## Find a GIF or meme

`media.browse_klipy` · read

Search or browse KLIPY GIFs and memes to attach to a post. Import a pick with media.import_klipy to get a mediaId.

- **MCP tool:** `media_browse_klipy`. Catalog: reach it with `find_actions` and `run_read_action`, or turn on the full toolset.
- **REST:** `GET /v1/media/browse-klipy`
- **CLI:** `xholic media browse-klipy`
- **Scope:** `read`
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `read`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | "gifs" \\| "memes" | Yes |  |
| `q` | string ≤ 100 chars | No | Search words. Leave out for trending. |
| `page` | integer 1–50 | No |  |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |

## Import a GIF or meme

`media.import_klipy` · write

Copy a KLIPY GIF or meme into the account's media. Returns a mediaId to attach to a post.

- **MCP tool:** `media_import_klipy`. Catalog: reach it with `find_actions` and `run_write_action`, or turn on the full toolset.
- **REST:** `POST /v1/media/import-klipy`
- **CLI:** `xholic media import-klipy`
- **Scope:** `write`
- **Plan:** Every plan, including the trial
- **Cost:** Free.
- **Rate limit bucket:** `write`

**Input**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | "gifs" \\| "memes" | Yes |  |
| `slug` | string ≤ 200 chars | Yes | The item's slug from media.browse_klipy. |
| `account` | string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection's default account. |
| `dryRun` | boolean | No | Return exactly what would happen without doing it. |
| `idempotencyKey` | string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
