---
name: xaicreator
description: Draft and publish X (Twitter) posts and read trending signals for a xAIcreator user through the xAIcreator Agent HTTP API. Use when the user asks to write, save, publish or check social posts via xAIcreator, or to look at what is trending in their Monitor.
version: 2026-09-18
---

# xAIcreator Agent API

xAIcreator (https://xaicreator.com) is a multi-platform social publishing workspace. This document is the
complete, self-contained reference an AI agent needs to act on behalf of a xAIcreator user.
Everything here is plain HTTPS + JSON; no SDK is required.

Canonical copy of this file: https://xaicreator.com/agent/SKILL.md

## 1. Authentication

- Base URL: `https://xaicreator.com/api/v1/agent`
- Every request must carry the user's Agent Key in one of these headers (pick one):
  - `xai-key: <key>`
  - `Authorization: Bearer <key>`
- Keys look like `xai_agent_<64 hex>`. Read the key from the environment variable `XAIC_API_KEY`.
  If it is missing, ask the user to create one in xAIcreator (Compose → top-right **Agent CLI**) and
  paste it — never invent, log, echo or store the key anywhere else.
- Keys are scoped. `GET /me` returns the granted scopes:
  - `monitor:read` — read trending signals and monitored posts
  - `drafts:read` — list / read the user's drafts
  - `drafts:write` — create text drafts
  - `tweets:publish` — publish to X (only granted when the user explicitly enabled it)
- Keys expire (default 90 days). `401 INVALID_OR_EXPIRED_KEY` means ask the user for a new key.

Quick check:

```bash
curl -s "https://xaicreator.com/api/v1/agent/me" -H "xai-key: $XAIC_API_KEY"
```

## 2. Rules the agent must follow

1. **Never publish without the user's explicit, current authorization** for that specific content.
   Default to creating a draft; publish only when the user clearly says "publish / post / send it".
2. **Every publish call needs an `Idempotency-Key` header** (8–128 chars of letters, digits, `. _ : -`).
   Generate one per user intent (e.g. `launch-post-2026-09-18-01`) and **reuse the same key + same body when retrying**.
3. On `409 PUBLISH_IN_PROGRESS_OR_UNKNOWN` or `503 PUBLISH_OUTCOME_UNKNOWN`: do **not** resend with a
   new key. Call `GET /publish/{requestId}` to learn the outcome, and tell the user to double-check X.
4. A user can own several Social Sets (groups of connected accounts). **Always pass `socialSetId`**
   when creating or publishing. If the user has more than one Set and did not say which, ask — do not pick silently.
5. Text only in this API version: no media, scheduling, polls, communities or non-X platforms.
   For those, tell the user to finish in the xAIcreator Compose UI (the draft you created will be there).
6. Respect X limits: 280 characters per post for standard accounts, up to 25,000 for X Premium. The server
   validates on publish; keep each post within the user's limit, and split long content into a thread.

## 3. Endpoints

All responses are JSON. Errors are `{ "success": false, "error": "<CODE>", "message": "..." }`.

| Method | Path | Scope | Purpose |
| --- | --- | --- | --- |
| GET | `/me` | any | Who the key belongs to + granted scopes |
| GET | `/social-sets` | any | The user's Social Sets (`id`, `name`, `accounts[]`) |
| GET | `/accounts` | any | X accounts reachable through those Sets |
| GET | `/drafts?socialSetId=&limit=&offset=` | drafts:read | List drafts (newest first) |
| GET | `/drafts/{id}` | drafts:read | One draft with its posts |
| POST | `/drafts` | drafts:write | Create a text draft |
| POST | `/publish` | tweets:publish | Publish a draft or direct text to X |
| GET | `/publish/{requestId}` | tweets:publish | Status / result of a publish request |
| GET | `/monitor/viral?scope=system|mine&preset=&hours=&limit=` | monitor:read | Trending signals |
| GET | `/monitor/posts?limit=&offset=&sort=latest` | monitor:read | Posts captured by the user's Monitor |

### 3.1 Create a draft — `POST /drafts`

Body (JSON). Use **either** `text` (single post) **or** `tweets` (thread, max 25 items), never both.

```json
{
  "socialSetId": "SOCIAL_SET_UUID",
  "title": "optional, up to 255 chars",
  "tweets": [
    { "content": "First post of the thread" },
    { "content": "Second post" }
  ]
}
```

```bash
curl -s "https://xaicreator.com/api/v1/agent/drafts" \
  -H "xai-key: $XAIC_API_KEY" -H "Content-Type: application/json" \
  -d '{"socialSetId":"SOCIAL_SET_UUID","text":"Hello from my agent"}'
```

Returns `201 { "success": true, "draft": { "id": "...", "title": "...", "tweets": [...] } }`.
The draft immediately appears in the user's Compose sidebar, where they can add media or schedule it.

### 3.2 Publish — `POST /publish`

Publish an existing draft:

```bash
curl -s "https://xaicreator.com/api/v1/agent/publish" \
  -H "xai-key: $XAIC_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: launch-post-2026-09-18-01" \
  -d '{"socialSetId":"SOCIAL_SET_UUID","draftId":"DRAFT_UUID"}'
```

Or publish text directly (requires both `drafts:write` and `tweets:publish`): replace `draftId`
with `text` or `tweets` exactly as in 3.1.

Success: `{ "success": true, "requestId": "...", "draftId": "...", "socialSetId": "...", ... }`.
A replayed retry returns the original response with header `Idempotency-Replayed: true`.
Changing the body while reusing a key returns `409 IDEMPOTENCY_CONFLICT`.

### 3.3 Trending signals — `GET /monitor/viral`

- `scope=system` (default) — curated discovery presets; pass `preset=<slug>` to pick one
- `scope=mine` — the user's own Monitor strategies
- `hours` (default 72), `limit` (default 30)

Use the returned representative posts and `contentAggregation` as inspiration; attribute sources when
you turn them into new content.

## 4. Recommended workflow

1. `GET /me` → confirm scopes. If `tweets:publish` is absent, you can only draft.
2. `GET /social-sets` → pick the Set (ask the user if ambiguous).
3. Write the content, keep each post within the character limit, then `POST /drafts`.
4. Show the user the draft and ask for approval.
5. Only after explicit approval: `POST /publish` with `draftId` and a fresh `Idempotency-Key`.
6. Report the result; on 409/503 check `GET /publish/{requestId}` before saying anything is unsent.

## 5. Error codes worth handling

| Code | Meaning / what to do |
| --- | --- |
| `API_KEY_REQUIRED`, `INVALID_API_KEY`, `INVALID_OR_EXPIRED_KEY` | Ask the user for a valid key |
| `INSUFFICIENT_SCOPE` | The key lacks the scope; ask the user to create a key with it |
| `SOCIAL_SET_ID_REQUIRED`, `SOCIAL_SET_NOT_FOUND` | Pass a Set id from `/social-sets` |
| `SOCIAL_SET_HAS_NO_X_ACCOUNT`, `SOCIAL_SET_X_TARGET_AMBIGUOUS` | The Set must contain exactly one X account; tell the user |
| `DRAFT_NOT_FOUND`, `INVALID_DRAFT_ID` | Use a draft id from `/drafts` that belongs to the same Set |
| `IDEMPOTENCY_KEY_REQUIRED`, `IDEMPOTENCY_CONFLICT` | Fix the header; do not mutate a retried body |
| `PUBLISH_IN_PROGRESS_OR_UNKNOWN`, `PUBLISH_OUTCOME_UNKNOWN` | Poll `/publish/{requestId}`; never auto-resend |
| `INVALID_TWEET_CONTENT`, `TEXT_ONLY_TWEETS_REQUIRED` | Content empty / too long / contains media fields |
| `UNSUPPORTED_FIELDS` | Remove unknown JSON fields from the body |

## 6. Optional: TypeScript SDK

If the project already vendors `@xaicreator/cli` (ships `XAICreatorClient`), the same endpoints are
available as `client.listSocialSets()`, `client.createDraft()`, `client.publishTweet()`. The HTTP
contract above is authoritative; the SDK is a thin wrapper.
