brln.tv

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.

AnonymousRegistered
Size per file2 MB95 MB
Uploads5 per month, per IPUnmetered
Retention30 daysUntil you delete it
Listing your uploadsNot availableGET /api/artifacts/my
DeletingOne-time delete tokenYour 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, 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.

# 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

StatusMeaningWhat to do
400The file was emptyCheck you actually attached content
401Missing or expired tokenSign in again for a fresh token
403Not permitted, or account bannedUse the owner's token or the delete token
404No such artifact, or already deletedDon't retry; the id is gone
413File is over your size limitRegister for 95 MB, or split the file
415File type not acceptedConvert to one of the accepted types
429Anonymous monthly quota spentRegister — don't retry, the window is 30 days
502Object storage is unavailableRetry 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