# The Ship Your Pod API

Connect your own tools — or your own Claude — to your Ship Your Pod account. Read your episodes and clips,
send us a new episode, ask for a change, and manage your plan, all without opening a browser.

You do not need to be a developer to use the Claude setup in the next section. If you can paste a block of
text into a settings file, you can do it.

- **Base URL:** `https://api.shipyourpod.com`
- **Your key goes in a header:** `Authorization: Bearer syp_live_...`
- **Everything is JSON.** Responses are objects; errors have a `message` written to be read by a person.
- **Your key only ever sees your account.** There is no account id in any request. Asking for something that
  belongs to another customer comes back as "not found", because the lookup only ever looks inside your account.

Get your key in the app: **Settings → Connect your AI → Get my API key** (every plan). It is shown once, so copy it
then and keep it somewhere safe. If it goes missing, remove it there and make a new one; anything using the old key
stops working at once. You can have up to 3 keys, e.g. one for Claude on your laptop and one for an automation.

---

## Point your Claude at it (MCP)

This is the quickest way to use the API, and it needs no code. `mcp_shipyourpod.py` is a small file that speaks
[MCP](https://modelcontextprotocol.io): download it from
[shipyourpod.com/ai/mcp_shipyourpod.py](https://shipyourpod.com/ai/mcp_shipyourpod.py). It needs Python 3.9 or
newer and nothing else — no `pip install`. It works with any AI app that can run a local MCP server, such as
Claude Desktop and Claude Code.

Add this to your Claude config (Claude Desktop: **Settings → Developer → Edit Config**; Claude Code:
`.mcp.json` in your project), then restart Claude:

```json
{
  "mcpServers": {
    "shipyourpod": {
      "command": "python",
      "args": ["C:/path/to/mcp_shipyourpod.py"],
      "env": {
        "SHIPYOURPOD_API_KEY": "syp_live_your_key_here"
      }
    }
  }
}
```

Change `C:/path/to/mcp_shipyourpod.py` to wherever you saved the file, and paste your own key in place of
`syp_live_your_key_here`. On a Mac or Linux the path looks like `/Users/you/mcp_shipyourpod.py`.

Then just ask, in your own words:

> *"What did my last episode produce?"*
> *"The hook on the second Short is too long — ask them to redo it."*
> *"Here's this week's episode: <link>. Send it over."*
> *"How many episodes have I got left this month?"*

Once it is connected, Claude can use these:

| Tool | What it does |
|---|---|
| `get_my_plan` | Plan, episodes used against your cap, and your price |
| `get_plans` | Read-only: the plans, their prices, and where you change plan (the app) |
| `get_my_usage` | The same cap, plus how much of each rate limit is left |
| `list_episodes` | Every delivered episode, newest first |
| `get_episode` | One episode: every clip, its hook, length, score and URLs |
| `get_settings` | How your clips are being cut, and every value each setting accepts |
| `submit_episode` | Send a new episode by link |
| `revise_clip` | Ask for one Short to be re-cut |
| `change_settings` | Change how future episodes are cut |
| `redo_thumbnail` | Redo one thumbnail |
| `ask_support` | Ask us a question (we reply by email) |
| `check_request` | What happened to a request you made |
| `show_cancel_options` | Read-only: what cancelling does, and the alternatives |
| `keep_subscription` | Record that you are staying, and why |
| `cancel_subscription` | Cancel, yourself, needs `confirm` |
| `undo_cancellation` | Changed your mind — put the plan back |

Two things worth knowing. Claude will not cancel your plan as a side effect of some other request:
`cancel_subscription` refuses unless it is told `confirm: true`, and it is written so that only a clear,
direct "cancel my subscription" from you should trigger it. And your key lives in the config file, not in the
conversation, so it is never something Claude can be talked into repeating back.

---

## Endpoints

Every example below works as-is once you put your key in. `$KEY` is your key.

### Reading

**Check the key works**

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/ping
```

**Your plan and usage** — which plan, episodes used against your cap, and your price now and where it settles.

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/me
```

**Usage and rate limits** — the same cap plus the live limit counters. Worth reading before you queue a batch.

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/usage
```

**Your episodes**

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/episodes
```

**One episode, with every clip** — each clip's `id`, on-screen `hook`, start and end, duration, score, why it
was picked, and a `watch_url` and `download_url`. The clip `id` is what you pass to revise and post.

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/episodes/EPISODE_ID
```

**Your settings, and the values each one accepts**

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/settings
```

**What happened to a request**

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/requests/REQUEST_ID
```

`status` is `new` (queued), `working`, `done` or `error`.

### Sending us work

Everything here joins the same queue as the buttons on your delivery page, and the same people and programs
do the work. Nothing here is a different service.

**Send a new episode** — a link we can fetch: YouTube, Drive, Dropbox, WeTransfer or a direct file. This
counts against your monthly episode allowance.

```bash
curl -X POST https://api.shipyourpod.com/v1/episodes \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://www.youtube.com/watch?v=XXXXXXXXXXX", "title": "Episode 41"}'
```

**Upload a file instead** — if the recording only exists on your own machine. Ask for a slot, upload to it,
then tell us you are done. Up to 10 GB and 4 hours, the same as the Upload tab in your account.

```bash
curl -X POST https://api.shipyourpod.com/v1/episodes \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"file_size": 2400000000, "title": "Episode 41"}'
```

That comes back with an `upload_id` and an `upload_url`. Send the file to `upload_url` with any
[tus](https://tus.io) client — resumable, so a dropped connection picks up where it left off — and then:

```bash
curl -X POST https://api.shipyourpod.com/v1/episodes/UPLOAD_ID/complete \
  -H "Authorization: Bearer $KEY"
```

**Nothing is queued until you call `/complete`**, so an upload you abandon halfway costs you nothing and does
not use an episode.

**Ask for a Short to be re-cut** — `mode` is `shorter`, `longer`, `earlier` (start further back), `hook` (new
on-screen words) or `recut` (anything else; describe it in `note`).

```bash
curl -X POST https://api.shipyourpod.com/v1/clips/CLIP_ID/revise \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"mode": "shorter", "note": "cut the bit before the question"}'
```

**Posting** — we do not post for you: every clip has a `download_url` (full quality, no watermark) and you post it
wherever you like. The old `/v1/clips/CLIP_ID/post` answers `410` with the clip's `download_url`.

**The plans** — read-only. Your plan, the plans on offer, and where to change plan. Plan changes and payments are
always approved by you in the app (Billing tab, which shows the exact price first) or at checkout; no key and no AI
can change your plan or pay for anything.

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/plans
```

**Redo a thumbnail**

```bash
curl -X POST https://api.shipyourpod.com/v1/episodes/EPISODE_ID/thumbnails/2/redo \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"text": "SHE SAID WHAT", "time": "5:12"}'
```

**Change how future episodes are cut** — applies from your next episode; clips already delivered are not
re-cut (ask for a revision for those). `GET /v1/settings` lists every accepted value.

```bash
curl -X PATCH https://api.shipyourpod.com/v1/settings \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"clip_length": "long", "caption_style": "hormozi"}'
```

**Ask us a question** — we answer by email.

```bash
curl -X POST https://api.shipyourpod.com/v1/help \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"question": "How do I connect my TikTok?"}'
```

### Cancelling, in the app, yourself

You never have to email us to cancel. You can do it here, or on the Billing tab of your account, and it takes
effect immediately. Replying "cancel" to an email still works too, if you would rather a person did it.

**See what cancelling does, and the alternatives** — read-only; it changes nothing.

```bash
curl -H "Authorization: Bearer $KEY" https://api.shipyourpod.com/v1/cancel
```

Pass a reason and you get alternatives that actually match it — for example, if the price is the problem it
will tell you that pausing keeps your place on the price ladder, and what a smaller plan would give you:

```bash
curl -X POST https://api.shipyourpod.com/v1/cancel/offer \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"reason": "too_expensive"}'
```

Reasons: `too_expensive`, `not_enough_use`, `quality`, `doing_it_myself`, `podcast_stopped`, `too_confusing`,
`missing_feature`, `other`. Anything else is refused rather than quietly filed as nothing, so a typo does not
lose what you told us. `GET /v1/cancel` lists them with their plain-English labels.

**Staying instead** — if one of the alternatives works for you, this records it and what you told us.
`choice` is `pause`, `smaller_plan`, `automatic_pickup`, `change_settings`, `revisions`, `connect_help`,
`download_instead` or `ask_us`.

```bash
curl -X POST https://api.shipyourpod.com/v1/cancel/stay \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"choice": "pause", "reason": "not_enough_use", "detail": "back in February"}'
```

**Cancel** — needs `confirm`. The reason is optional and we never hold the cancellation up for it.

```bash
curl -X POST https://api.shipyourpod.com/v1/cancel \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"confirm": true, "reason": "quality", "detail": "hooks were too long for my audience"}'
```

You keep the plan until the end of the month you have already paid for, you are not charged again, and your
pages and downloads stay up. Nothing is deleted because you cancelled.

**Changed your mind**

```bash
curl -X POST https://api.shipyourpod.com/v1/cancel/undo \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{}'
```

This works while the month you paid for is still running, and it puts your loyalty price back where it was.
Once that month has ended, coming back is a new signup and the price ladder starts again at month 1 — so if
you think you might return, pausing keeps your place and undoing is free.

### Switching plans, and the check before checkout (no API key)

These four are what the website and the account app call. They do not take a `syp_live_` key: the plan check
is public, and the plan switch uses your sign-in to shipyourpod.com/app. An API key sent to them is treated as
no sign-in at all.

```
POST /v1/plan-check                {"email": "you@example.com"}
```

Does this email already have a Ship Your Pod plan? The plan buttons on shipyourpod.com ask this before opening
checkout, so nobody pays for two plans. The answer is only `{"live_plan": true, "message": ..., "sign_in_url": ...}`
or `{"live_plan": false}`; the plan and its date are included only when you are signed in as that same email.
Limited to 10 a minute per visitor and 10 an hour per address. If this cannot answer, the website sends you to
checkout anyway.

```
GET  /v1/account/plan              (signed in)  the switch you can make, or why not
POST /v1/account/plan/preview      (signed in)  {"tier": "pro"} - Stripe's exact amounts, changes nothing
POST /v1/account/plan/switch       (signed in)  {"tier": "pro", "proration_date": ..., "expected_cents": ...}
```

Moving up to Pro starts straight away and charges the difference for the rest of the month; the switch is
refused unless `expected_cents` is the amount the preview showed. Moving down to Starter starts at your next
renewal, with nothing charged or refunded for it. Your place on the loyalty price comes with you. Older plans
switch by replying "upgrade" or "downgrade" to any of our emails.

---

## Limits

Two different ceilings, and they do different jobs.

**Your episode allowance** is the one that matters. Each plan includes a number of episodes a month
(`GET /v1/me` reports yours under `usage`, as `episodes_used_this_month`, `episodes_cap`, `episode_credits`
and `episodes_left`). When it is used up, sending another
episode comes back as refused, with the numbers, and nothing is queued or charged. It resets at the start of
your month. Moving up a plan raises it straight away. Extra episode credits, if you have bought any, are
counted on top.

**Rate limits** stop a script or an agent in a loop from flooding the queue. Per key:

| Limit | Ceiling |
|---|---|
| All requests | 60 a minute |
| Requests that change something or queue work | 10 a minute |
| Requests that change something or queue work | 20 an hour |

Going over gets HTTP `429`, a message saying which limit it was, and `retry_after_seconds`. Nothing is queued
when a call is refused. Refused calls count toward the window, so hammering does not clear it — wait the
number of seconds you are given and carry on. If your setup genuinely needs a higher ceiling, reply to any of
our emails and we will raise it on your key.

## When something goes wrong

| Code | What it means |
|---|---|
| `401` | The key is missing, wrong or revoked |
| `404` | No such thing on your account (this is also what you get for anything that is not yours) |
| `400` | Something in the request was wrong — `message` says what, and lists valid values where there are some |
| `402` | Your plan does not include this, or your episode allowance is used up |
| `409` | Can be done, but not right now |
| `410` | That action no longer exists (posting); the body says what to do instead |
| `423` | This account is flagged so the API will not change its billing; reply to an email and a person does it |
| `429` | A rate limit. `retry_after_seconds` tells you how long |
| `502`/`503` | Our side. Nothing was changed; try again shortly |

Every error body has a `message` meant to be read as a sentence. If a call fails, nothing was queued unless
the message says otherwise.

---

Prices, what each plan includes and the loyalty ladder are on the plans page at
[shipyourpod.com](https://shipyourpod.com) and on the Billing tab of your account, which are always the
current numbers. Month to month, cancel any time.
