# brln.tv API documentation > brln.tv hosts generated artifacts — an HTML report, a chart, a PDF — and gives you back a URL that opens in any browser. One unauthenticated POST is the whole integration, so an AI agent can publish something for a human to look at without credentials, an SDK or a storage bucket. ## Upload a file, get a URL Send a file. Get a link. No account, no key. ```bash curl -X POST https://brln.tv/api/artifacts \ -F 'file=@report.html' ``` ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "url": "https://pages.brln.tv/a1b2c3d4/report.html", "filename": "report.html", "file_size_bytes": 512000, "expires_at": "2026-09-30T10:30:00Z", "delete_token": "keep-this-to-retract-the-upload" } ``` The `url` is live immediately. `delete_token` is shown once and cannot be recovered — keep it if you may need to take the artifact down later. ## Do I need an account? No. Anonymous uploads are the intended path for a one-off artifact. An account raises the limits and gives you a library you can list and delete from. | | Anonymous | Registered | |---|---|---| | Size per file | 2 MB | 95 MB | | Uploads | 5 per month, per IP | Unmetered | | Retention | 30 days | Until you delete it | | Listing your uploads | Not available | GET /api/artifacts/my | | Deleting | One-time delete token | Your bearer token | The anonymous quota is counted per IP address over a rolling 30 days. The registered limit sits under 95 MB because brln.tv is served through a proxy that rejects larger request bodies before this API sees them. ## Uploading ### POST /api/artifacts A `multipart/form-data` request with a single `file` field. To upload as a registered user, add an `Authorization: Bearer ` header. ```bash curl -X POST https://brln.tv/api/artifacts \ -H 'Authorization: Bearer ' \ -F 'file=@quarterly.pdf' ``` The filename is rebuilt from a strict character whitelist before it becomes part of the URL, so `../../etc/passwd.html` is stored as `passwd.html`. Include a real extension: it decides the `Content-Type` the file is served with. ### Accepted file types `.csv .gif .htm .html .jpeg .jpg .json .md .pdf .png .svg .txt .webp` Anything else is refused with `415`. The type is taken from the extension, not from the `Content-Type` you send, so a mislabelled upload still gets served correctly. ## How your artifact is served - Artifacts live on `https://pages.brln.tv` — a different origin from this site and its API. Uploaded HTML is untrusted, so it must not share an origin with anything holding an account session. - Pages are served with scripting sandboxed via `Content-Security-Policy`, framing blocked, and `X-Content-Type-Options: nosniff`. - Artifacts carry `X-Robots-Tag: noindex`. A link is shareable, but search engines are asked to stay out. - Nothing else is reachable on the artifact host — the API and the admin dashboard return 404 there. Anything hosted here can be reported and taken down. Uploading phishing pages, malware, or other people's private data gets the artifact removed and the account banned. ## Deleting something you uploaded ### DELETE /api/artifacts/{id} Authorise as the owner, or with the one-time token from an anonymous upload. ```bash # anonymous upload, using the token from the response curl -X DELETE https://brln.tv/api/artifacts/ \ -H 'X-Delete-Token: ' # your own upload, as the owner curl -X DELETE https://brln.tv/api/artifacts/ \ -H 'Authorization: Bearer ' ``` Deletion is immediate and removes the stored file. The token works once — afterwards the artifact is gone and the endpoint returns `404`. ## Registering and signing in ```bash curl -X POST https://brln.tv/api/auth/register \ -H 'Content-Type: application/json' \ -d '{"username":"agent-smith","email":"agent@example.com","password":"a-long-passphrase"}' curl -X POST https://brln.tv/api/auth/login \ -H 'Content-Type: application/json' \ -d '{"email":"agent@example.com","password":"a-long-passphrase"}' ``` Login returns `access_token`, a bearer token valid for 24 hours. `GET /api/users/me` returns your profile and storage used; `GET /api/artifacts/my` lists your artifacts. ## Using brln.tv from an MCP client brln.tv runs an MCP server at `https://brln.tv/mcp` over Streamable HTTP, so an agent can publish artifacts as a native tool call instead of shelling out to curl. ```bash # Claude Code claude mcp add --transport http brln-tv https://brln.tv/mcp ``` Tools: `upload_artifact`, `list_my_artifacts`, `get_artifact`, `delete_artifact`. Pass text in `content` or base64 in `content_base64`. It works with no credentials, under the same anonymous quota as the REST API. Two things to know: the quota is per IP, and MCP clients often egress from one shared address, so authenticate for anything beyond a trial by configuring an `Authorization: Bearer ` header. And because a tool call is a single JSON body, uploads through MCP are capped lower than the REST limit — use `POST /api/artifacts` for large files. ## Installing the Claude Code plugin One install and "publish this to brln.tv" works with nothing further to configure. ```bash claude plugin marketplace add https://brln.tv/plugin claude plugin install brln-tv@brln-tv # or from GitHub claude plugin marketplace add abrilliantov/brln-tv-skill ``` That registers three things: a skill so plain requests like "put this online" are handled without naming a tool, a `/publish` command for when you want to be explicit, and the MCP server above — so the agent gets real upload tools rather than shelling out to curl. The plugin repository is served from this domain at `https://brln.tv/plugin.git` (read-only), and a tarball for manual installation is at [/plugin-dist/brln-tv-0.1.0.tar.gz](https://brln.tv/plugin-dist/brln-tv-0.1.0.tar.gz). ## Errors, and what to do about them | Status | Meaning | What to do | |---|---|---| | 400 | The file was empty | Check you actually attached content | | 401 | Missing or expired token | Sign in again for a fresh token | | 403 | Not permitted, or account banned | Use the owner's token or the delete token | | 404 | No such artifact, or already deleted | Don't retry; the id is gone | | 413 | File is over your size limit | Register for 95 MB, or split the file | | 415 | File type not accepted | Convert to one of the accepted types | | 429 | Anonymous monthly quota spent | Register — don't retry, the window is 30 days | | 502 | Object storage is unavailable | Retry with backoff; this one is ours | Every error returns JSON with a `detail` string explaining the specific cause. `429` and `413` will not succeed on retry without a change on your side. ## Machine-readable references - [OpenAPI schema (JSON)](https://brln.tv/openapi.json) — includes a `servers` entry, so it works as a standalone client generator input - [OpenAPI schema (YAML)](https://brln.tv/openapi.yaml) - [/llms.txt](https://brln.tv/llms.txt) — index for language models - [/llms-full.txt](https://brln.tv/llms-full.txt) — this entire document in one fetch - [/docs.md](https://brln.tv/docs.md) — this page as Markdown - [Interactive API explorer](https://brln.tv/docs/interactive) and [reference](https://brln.tv/docs/reference) — browser only, rendered client-side - [Service health](https://brln.tv/health) — reports 503 when the database or object storage is unreachable