# REST API

> Call X-Buddy from n8n, Make, Zapier or code — API keys, idempotency, revisions, jobs and waiting, pagination, batches, media and downloads.

Source: https://x.builera.app/docs/en/rest-api
Last checked: 2026-10-24

Every operation available over MCP is also a REST endpoint. Same registry, same permissions, same rules.

## Base URL and authentication {#base-url-and-authentication}

- **Base URL:** `https://reach-link-craft.lovable.app/api/public/v1`
- **API key:** create one in **Settings → MCP / API connections → Create API key** (you can set an expiry). Send it as:

```http
Authorization: Bearer xb_live_<id>_<secret>
```

The key acts with the **current** role of the person who created it. Keep it secret: it is shown once.

For n8n use an **HTTP Request** node with **Header Auth** (Name `Authorization`, Value `Bearer <YOUR_KEY>`); in Make use **HTTP → Make a request**; in Zapier use **Webhooks by Zapier → Custom Request**.

## Writes need an idempotency key {#writes-need-an-idempotency-key}

Every write (kinds `X`, `W`, `D`) needs an `Idempotency-Key` header (or `idempotency_key` in the body): 8–128 characters from `A–Z a–z 0–9 . _ : -`.

- Same key + same input → the stored answer or the same job. Nothing runs twice.
- Same key + different input → `409 idempotency_conflict`.
- The first call with that key still running → `409 idempotency_processing`, retry after 2 seconds with the same key.

Keys are scoped to the connection.

## Versioned settings {#versioned-settings}

Settings with a revision need the revision you read: send `If-Match: "<revision>"` or `expected_revision` in the body. Responses for versioned objects carry an `ETag`. A stale revision returns `412 revision_conflict` with the current value — merge and retry.

## Jobs and waiting {#jobs-and-waiting}

Live reads (`L`) and X actions (`X`) create jobs. The request waits for the job up to `?wait=` seconds (0–20, default 15).

- Done in time → `200` with the result.
- Still queued, held or running → `202` with `Location: /api/public/v1/jobs/{job_id}` and `Retry-After: 2`. Poll `GET /jobs/{job_id}` (it can wait up to 20 seconds too).
- `POST /jobs/{job_id}/cancel` cancels a queued or held job. A running job is asked to stop and may still end `succeeded`, `cancelled` or `unknown`.

> [!WARNING]
> A job that ends `unknown` may already have happened on X. Never resend it with a new idempotency key.

## Responses and pagination {#responses-and-pagination}

Successful responses use one envelope:

```json
{ "data": {}, "meta": { "request_id": "req_…", "operation": "account_list" }, "next_cursor": null, "has_more": false }
```

Lists return `next_cursor`; pass it back as `cursor` for the next page. Every response has an `X-Request-Id` header.

## Rate limit {#rate-limit}

600 calls per minute per connection. Responses carry `RateLimit-Policy` and `RateLimit` headers; over the limit you get `429 rate_limited` with `Retry-After`. This is the API's limit — each X account's own action limits apply separately.


## Request history {#request-history}

Each call is added to the connection's usage history in X-Buddy right after its answer is sent, so the history never slows a call down. If the server stops at that exact moment, the history can miss that one call; what the call did (a job queued, a setting saved) is kept either way. Refusals of a paused or revoked connection are recorded once a minute.

## Batches {#batches}

`POST /batches` (`x_batch`) runs one X action on up to **1,000** items: explicit account + arguments pairs, or X accounts / groups crossed with a list of arguments. It supports a dry run and spacing per X account. Limits, run hours and do-not-contact still apply. Follow it with `x_batch_get`; a `batch.completed` event fires at the end. Cancelling drops items not yet queued and cancels waiting jobs; running ones finish.

## Media {#media}

1. `POST /media/uploads` (`media_create_upload`) with a `purpose` of `post` (the default), `profile` or `dm` for the operation you'll use; it returns a short-lived `upload_url` and a `media_id`.
2. `PUT` the file bytes to `upload_url` with the content type you declared.
3. Use `media_id` in the post, profile or message operation that matches the `purpose`. Profile images accept JPG, PNG and WEBP only.

Limits: JPG, PNG and WEBP up to 5 MB; GIF up to 15 MB; MP4 and MOV up to 50 MB.

## Downloads {#downloads}

- [OpenAPI 3.1 document](/api/public/v1/openapi.json) — generate a client in any language.
- [TypeScript SDK](/api/public/v1/sdk.ts) — one file, no dependencies.
- [Postman collection](/api/public/v1/postman.json)
- [API explorer](/docs/api) — try calls in the browser.

All are generated from the same registry as the [API reference](/docs/en/reference).

## Example {#example}

```bash
curl "https://reach-link-craft.lovable.app/api/public/v1/accounts" \
  -H "Authorization: Bearer $XBUDDY_API_KEY"
```

## Related {#related}

- [Errors](/docs/en/errors)
- [Webhooks & events](/docs/en/webhooks-and-events)
