# Introduction

0bull rents real iPhones by the month. Each phone is a physical handset, not an emulator or
a cloud phone, and it is driven for real: logging in, opening the app, and publishing video.
There is no platform API behind this. There is a phone.

Each phone occupies a **slot** (a UUID, labelled `slot12` for humans) and is set up for four
TikTok accounts. Instagram and YouTube accounts are supported too.

Accounts and submissions carry a **`platform`** of `tiktok`, `instagram` or `youtube`. It
defaults to `tiktok` everywhere, so a client written before the parameter existed keeps
working unchanged.

:::caution{title="Account ids are UUIDs"}
Accounts are identified by a UUID such as `019feb70-07f7-71a4-a84e-e33b56837a1d`, in the
REST API, in MCP tools, and in the app's own URLs. They used to be sequential integers.

If you stored account ids, they still resolve: nothing was renumbered, and every account
kept its identity through the change. But anything that **declared** an id as a number
(a generated client, a typed struct, a database column) needs to accept a string. Submission
ids are unaffected and remain integers.
:::

## Getting a phone

Order at [0bull.net/order](https://0bull.net/order). No account is required up front: give a
name, email and card, and an account is created from that email.

- **One dedicated iPhone, one dedicated IP.** The phone is reserved to you, not a slot on a
  shared pool, and keeps the same IP for as long as you hold it.
- **$100 per phone, per month.**
- **Up to 4 accounts per phone**, across TikTok, Instagram and YouTube.
- **Nothing is charged at checkout.** Checkout only saves the card. An admin assigns the
  actual phone afterward, and the card is charged a full month at that moment.
- **Orders are final.** There is nothing to cancel while an order waits to be assigned.

Once you have a phone, manage the farm from [0bull.net](https://0bull.net). These docs cover
the two ways to drive it from your own tools: the MCP server and the REST API.

## The MCP server

`https://0bull.net/mcp` exposes **24 tools** covering accounts, submissions, billing and
uploads, login lifecycle, and direct phone control (commands, raw input, screenshots, OCR,
macros, and a GUI agent). It authenticates with **OAuth**: you add the URL to your client and
authorize in a browser. There is no token to copy.

This is the fuller surface, and the one to start with.

- [MCP overview](/mcp/overview): what it does, and the async model that governs every call
- [Connecting](/mcp/connecting): Claude Code, Claude Desktop, Cursor
- [Tool reference](/mcp/tools): all 24 tools and their parameters

## The REST API

`https://0bull.net/api` exposes **13 endpoints**: accounts and submissions CRUD, the account
login lifecycle, plus the current user. It authenticates with an **API token** sent as a
bearer token.

**1. Create a token.** Go to
[0bull.net/settings/api-tokens](https://0bull.net/settings/api-tokens), give the token a
name you will recognise later (`CI pipeline`, say), and hit **Create**. The token is shown
**once**, right after you create it. Copy it then and store it somewhere safe. If you lose
it, delete it and create another. You can revoke any token from that page at any time.

**2. Send it on every request** in the `Authorization` header:

```bash
curl https://0bull.net/api/v1/accounts \
  -H "Authorization: Bearer <your-token>" \
  -H "Accept: application/json"
```

**3. Post a video.** Submissions upload the file itself, so this is a multipart request:

```bash
curl https://0bull.net/api/v1/submissions \
  -H "Authorization: Bearer <your-token>" \
  -H "Accept: application/json" \
  -F "account_id=019feb70-07f7-71a4-a84e-e33b56837a1d" \
  -F "video=@clip.mp4" \
  -F "caption=hello from 0bull"
```

Account ids are UUIDs, and a UUID identifies its own platform, so `GET`, `PUT` and `DELETE`
on `/v1/accounts/{account}` need nothing but the id. Add `-F "platform=instagram"` (or
`youtube`) to post somewhere other than TikTok; omitting it means `tiktok`. The older
`tik_tok_account_id` field still works as an alias for `account_id`.

On YouTube the text is the Short's **title**, so `caption` is required there and capped at
100 characters rather than 2200.

The account must be logged in on its phone before it can post, and publishing happens on a
real phone after the request returns, so poll `GET /api/v1/submissions/{id}` and read
`status` to find out how it went. The
[submission status table](/mcp/overview#submission-status) lists every value and which are
final.

- [API reference](/api): every endpoint, parameter, and response

## Which one

| | MCP | REST |
|---|---|---|
| Surface | 24 tools | 13 endpoints |
| Auth | OAuth (browser) | API token (bearer) |
| Platforms | TikTok, Instagram, YouTube | TikTok, Instagram, YouTube |
| Login lifecycle | Yes | Yes |
| Phone control | Yes | No |
| Billing and ordering | Yes | No |
| Video source | Public URL or upload | Upload |
| Rate limit | 60/min | 60/min |

MCP covers everything REST does, plus phone control, billing, and uploads. Reach for REST
when you are writing a plain HTTP client and do not need to drive a handset directly.
