# Quickstart

ReelMoney makes short form content for one brand and publishes it to TikTok, YouTube, Instagram and LinkedIn. This API gives a program the same reach a person has in the dashboard: read the plan and the quota left, browse and upload media, generate an AI slideshow or a hook and demo video, publish or schedule it, and read the numbers afterwards.

Base URL: `https://reel.money`. There is one machine readable spec at [/openapi.json](/openapi.json) and one MCP server at `https://reel.money/mcp`.

Calls from a browser page are not supported. These endpoints send no CORS headers on purpose, so call them from a server or from an agent runtime.

## Step 1. Create an API key

1. Sign in to ReelMoney and switch to the brand the agent should work in. A key belongs to one brand, and the plan, quota and credits are the brand owner's.
2. Open Settings, then API keys, at `https://reel.money/brands/<brand_id>/api_keys`, and choose Create new secret key.
3. Name the key after the agent that will hold it, so you know what you are revoking later.
4. Tick the permissions that agent needs. A key can only ever do what its permissions allow.
5. Copy the token. It starts with `rm_` and it is shown once. Store it the way you store a password.

For a first run, tick `brand:read`, `media:read`, `media:write` and `content:write`. Add `posts:read` and `posts:write` when you are ready to let the agent publish, and `analytics:read` when you want it to report results.

| Scope | What it allows |
| --- | --- |
| `brand:read` | Read your brand profile, plan, quota, videos and slideshows. |
| `media:read` | Browse your media library, media packs and stock media. |
| `media:write` | Upload files and add them to your media library. |
| `content:write` | Create and edit slideshows and videos, and start renders. |
| `posts:read` | Read your posts and scheduled posts, and run post checks. |
| `posts:write` | Publish and schedule posts, and cancel scheduled posts. |
| `analytics:read` | Read post metrics and account analytics. |
| `brands:all` | Work across every brand this account owns, choosing the brand per request. |

## Step 2. Check the key works

Send the token as a bearer token on every request.

```bash
curl https://reel.money/api/v1/account \
  -H "Authorization: Bearer rm_your_key"
```

```json
{
  "success": true,
  "data": {
    "user": { "id": 41, "email": "ja****@example.com" },
    "plan": {
      "name": "basic",
      "capabilities": {
        "plan_name": "basic",
        "metered": "slideshows",
        "slideshow_limit": 40,
        "slideshows_used": 12,
        "slideshows_remaining": 28,
        "automation_limit": 2
      }
    },
    "brands": [{ "id": 7, "name": "Northwind Coffee" }],
    "api_key": {
      "name": "Agent key",
      "scopes": ["brand:read", "media:read", "content:write", "posts:write"],
      "last_used_at": "2026-08-18T09:14:22Z"
    }
  },
  "meta": {}
}
```

Read `slideshows_remaining` before you start work. An agent that checks the quota first never burns a run it cannot finish.

## Step 3. Create a slideshow

`context` is the one field that decides quality. Say who the slideshow is for and what it should get across.

```bash
curl -X POST https://reel.money/api/v1/slideshows \
  -H "Authorization: Bearer rm_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5a1f9b2c-7f1e-4c73-9c6d-1b2f3a4d5e6f" \
  -d '{
    "context": "Five reasons a small coffee roaster should sell subscriptions, written for owners who have never sold one",
    "slide_count": 5,
    "aspect_ratio": "9:16",
    "image_source": { "type": "stock" },
    "title": "Why roasters sell subscriptions",
    "tags": "coffee,subscriptions"
  }'
```

```json
{
  "success": true,
  "data": {
    "job_id": 8842,
    "kind": "slideshow_generation",
    "status": "processing",
    "status_message": "Generating the slideshow content.",
    "poll_after_seconds": 15,
    "estimated_completion_at": "2026-08-18T09:16:02Z"
  },
  "meta": {}
}
```

Leave `design_style` out and ReelMoney picks a look the brand has not used lately, which is what keeps a feed from looking the same every day. Set it only when a caller asks for a specific look. Read [/api/v1/capabilities](/api-docs/endpoints) for the list of styles, image worlds, fonts and aspect ratios.

The `Idempotency-Key` header is optional and worth sending. Retry a create that timed out with the same key and the same body and you get the original answer back instead of a second slideshow.

## Step 4. Poll the job

The job id is the short id. Wait `poll_after_seconds` between polls, which comes back in the `Retry-After` header too, and stop as soon as the status reads `succeeded` or `failed`.

```bash
curl https://reel.money/api/v1/jobs/8842 \
  -H "Authorization: Bearer rm_your_key"
```

```json
{
  "success": true,
  "data": {
    "job_id": 8842,
    "kind": "slideshow_generation",
    "status": "succeeded",
    "status_message": "The slideshow content is ready.",
    "poll_after_seconds": 15,
    "result": {
      "short_id": 8842,
      "preview_url": "https://cdn.example.com/slides/8842-1.jpg",
      "video_url": null,
      "slides": { "count": 5 }
    }
  },
  "meta": {}
}
```

A failed job carries an `error` with a code from the [error reference](/api-docs/errors) and whether a retry can help. Polling faster than the interval does not make a job finish sooner, it only spends your request ceiling.

## Step 5. Post it

Check first. `POST /api/v1/posts/validate` takes the same body as the post itself, touches nothing, and answers with one verdict per account: is the short ready, is the connection healthy, is the caption inside the platform cap, is there posting headroom left.

```bash
curl -X POST https://reel.money/api/v1/posts/validate \
  -H "Authorization: Bearer rm_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "short_id": 8842, "platforms": ["tiktok"] }'
```

When every verdict reads `"ok": true`, publish.

```bash
curl -X POST https://reel.money/api/v1/posts \
  -H "Authorization: Bearer rm_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "short_id": 8842, "platforms": ["tiktok"] }'
```

```json
{
  "success": true,
  "data": {
    "short_id": 8842,
    "overall_status": "partial",
    "results": [
      { "social_data_id": 55, "platform": "tiktok", "account_name": "northwindcoffee", "share_id": 9901, "status": "pending", "scheduled_at": null },
      { "social_data_id": null, "platform": "instagram", "share_id": null, "status": "failed",
        "error": { "code": "platform_not_connected", "message": "No instagram account is connected.", "retryable": false } }
    ]
  },
  "meta": {}
}
```

Posting is partial by design. One account with a stale token never stops the others, so read `overall_status` and then walk `results` and handle each failure on its own. Never resend the whole request because one account failed. The [posting page](/api-docs/posting) covers the platform rules and how to schedule.

No accounts connected yet? Call `POST /api/v1/connections/link` with a platform, give the returned URL to a person, and they approve it once in a browser.

## Use it as a tool server instead

The same operations are exposed over MCP at `https://reel.money/mcp`, as 18 tools. For Claude Code, one line in a terminal:

```bash
claude mcp add reelmoney --transport http https://reel.money/mcp --header "Authorization: Bearer rm_your_key"
```

For Claude Desktop, Cursor and anything else that reads a JSON config:

```json
{
  "mcpServers": {
    "reelmoney": {
      "type": "http",
      "url": "https://reel.money/mcp",
      "headers": {
        "Authorization": "Bearer rm_your_key"
      }
    }
  }
}
```

The [MCP page](/api-docs/mcp) lists every tool and what each one is for.

## Where to go next

- [Authentication](/api-docs/authentication): scopes, rate limits, idempotency.
- [Endpoints](/api-docs/endpoints): every REST endpoint, grouped.
- [MCP server](/api-docs/mcp): tools, annotations and client configs.
- [Errors](/api-docs/errors): every code with its cause and its fix.
- [Posting](/api-docs/posting): platform rules, connecting accounts, scheduling.
- [/openapi.json](/openapi.json): the full machine readable contract.
