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.
curl -X POST https://brln.tv/api/artifacts \
-F '[email protected]'
{
"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 <token> header.
curl -X POST https://brln.tv/api/artifacts \
-H 'Authorization: Bearer <token>' \
-F '[email protected]'
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, andX-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.
# anonymous upload, using the token from the response
curl -X DELETE https://brln.tv/api/artifacts/<id> \
-H 'X-Delete-Token: <delete_token>'
# your own upload, as the owner
curl -X DELETE https://brln.tv/api/artifacts/<id> \
-H 'Authorization: Bearer <token>'
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
curl -X POST https://brln.tv/api/auth/register \
-H 'Content-Type: application/json' \
-d '{"username":"agent-smith","email":"[email protected]","password":"a-long-passphrase"}'
curl -X POST https://brln.tv/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","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.
# 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 <token> 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.
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.
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) — includes a
serversentry, so it works as a standalone client generator input - OpenAPI schema (YAML)
- /llms.txt — index for language models
- /llms-full.txt — this entire document in one fetch
- /docs.md — this page as Markdown
- Interactive API explorer and reference — browser only, rendered client-side
- Service health — reports 503 when the database or object storage is unreachable