FOR YOUR AGENT
Connect your agent.
Let your agent upload the file and bring back a download link. Recipients don’t need an account.
- Get your access token. Sign in to your account and create an agent token. Free accounts can send right away.
- Give your agent the details below. It will guide you through saving the token securely.
- Ask it to send a file. Your agent uploads it and gives you a link to share.
Free: 5 transfers a month, files up to 5 GB. Need more? Plus is $15 for up to 150 GB, Pro is $30 for up to 400 GB, files up to 50 GB. Pay per use, never a subscription.
Give your agent the connection details
Paste this once so your agent knows where Bilaga is and how to use it. This does not sign you in or grant access to your account.
Technical setup and API reference
MCP
If your agent speaks the Model Context Protocol, the MCP server is the shortest path: npx -y bilaga-mcp setup stores your token, and the server gives the agent a send_file tool that returns the link.
Start with a file
Use the Python client with Python 3.10 or later. It uses the standard library and retries failed chunks. Inspect the downloaded script before running it. Set BILAGA_TOKEN in your environment, then replace the filename below.
python3 bilaga.py \ --base https://bilaga.link \ --file report.pdf
The response includes the shareable link and expiry. Your agent delivers that link through its existing conversation or communication channel.
Upload in chunks and resume
Files upload sequentially in 8 MiB chunks. Save the transfer ID printed by the client. After interruption, keep the original file unchanged and resume within 24 hours:
python3 bilaga.py --base https://bilaga.link --file report.pdf --resume TRANSFER_ID
Resume skips confirmed parts only and retries unfinished parts. Changing a previously submitted chunk is rejected. The browser retries chunks while the page stays open; it does not resume after page closure.
Check the handoff
python3 bilaga.py --base https://bilaga.link \ --status TRANSFER_ID
Poll at most once every 15 seconds. A download request means a download started; it doesn’t prove completion or that a human read the file. Bilaga only marks a transfer “sent” when the agent reports delivery.
Prove the handoff
python3 bilaga.py --base https://bilaga.link \ --receipt PUBLIC_ID --verify downloaded-file
Every completed transfer has a receipt signed by Bilaga: content hash, size, sender, and timestamps. Anyone can verify it offline against the published key, with or without the file. It proves what was stored, not that a person read it. Receipts are kept after the file expires or is deleted, and --receipt-hash FILE finds the receipts for any file you hold, whoever sent it. The exact formats and verification steps are on the verification page.
Address a file to another agent
python3 bilaga.py --base https://bilaga.link \ --file report.pdf --to them@example.com
An addressed transfer appears in the recipient’s inbox as soon as they sign in with that email, even if they have no account yet. Their agent lists it with --inbox, downloads it with --download PUBLIC_ID, and can answer with --file answer.pdf --reply-to PUBLIC_ID. When the recipient’s agent downloads or acknowledges the file, your receipt gains their account handle and a received time. Replies reference the original in their receipts, so a conversation of files is a chain of signed receipts.
Put a price on a file (experimental)
python3 bilaga.py --base https://bilaga.link \ --file dataset.parquet --to them@example.com --price 250
A priced transfer must be addressed. The recipient sees the price on the download page and in their inbox, and their agent pays with --pay PUBLIC_ID from its balance. Only then does the file download. Bilaga moves the money, keeps 5%, and signs the settlement into the receipt as paid_at, paid_by_account, and fee_cents. Check what you have with --balance. Card top-ups are available on the account page when payments are enabled.
Hear about it without polling
python3 bilaga.py --base https://bilaga.link \ --webhook https://your-agent.example/bilaga
Bilaga posts each event to your webhook as JSON, signed with the same Ed25519 key as receipts, and retries failures for about half a day. Events: transfer.completed, transfer.downloaded (first download), transfer.received, transfer.reply, transfer.paid, and transfer.deleted. Pipe a delivery to --verify-event to check it, or read the same events from --events if you would rather poll.
A small API, end to end
Send your token as Authorization: Bearer …. Keep it private: all tokens for an account can manage that account’s transfers. Recipient links never contain the token.
| Endpoint | What it does |
|---|---|
| GET /api/config | See upload limits and availability. |
| GET /api/quote?bytes=… | Estimate the future storage price. Storage is not charged yet. |
| POST /api/transfers | Create an upload with a filename and size in bytes. |
| PUT /api/transfers/{id}/parts/{n} | Upload one binary chunk. Retry failed chunks. |
| POST /api/transfers/{id}/complete | Finish the upload and receive the shareable link. |
| GET /api/transfers/{id} | Check uploaded parts, expiry, and download requests. |
| POST /api/transfers/{id}/sent | Record that your agent delivered the link. |
| DELETE /api/transfers/{id} | Revoke the link and delete the stored file. |
| GET /api/receipts/{public_id} | Signed receipt with the content hash. No token needed. |
| POST /api/requests | Create an account-free upload link for multiple files. |
| GET /api/requests | List your file requests. |
| GET /api/requests/{id} | Read files and submission status. |
| GET /api/requests/{id}/receipt | Fetch the private signed submission record after Done. |
| DELETE /api/requests/{id} | Close an upload request. |
| GET /api/inbox | Transfers addressed to your account email. |
| POST /api/inbox/{public_id}/received | Acknowledge a transfer addressed to you; the sender’s receipt records it. |
| GET /api/events | Your signed event feed. Page with ?since=EVENT_ID. |
| PUT /api/webhook | Register one https URL to receive every event, signed with the receipt key. |
| POST /api/inbox/{public_id}/pay | Pay for a priced transfer from your balance. |
| GET /api/balance | Your balance in cents and recent ledger entries. |
Collect files without signup
Create a file request from your account or with POST /api/requests. Share the returned upload link. Anyone holding it can add multiple files without an account and click Done when finished. Each file uses your normal allowance or credit; Done adds no charge.
Use the signed request.submitted event to learn when the uploader has finished. It includes the request ID, your optional reference and the final file list. Individual transfer.completed events mean a file finished uploading, not that the collection is finished. Your application decides what to do next.
The private submission receipt records hashes, submission time and the email supplied by the uploader. That email is not verified and is never added to public file receipts. Links expire, can be closed, and cannot change files after Done. Defaults: 20 files, 5 GB total and 7 days; removed uploads count toward the request limits.
What it costs
Every account gets 5 transfers per rolling 30 days and 5 GB stored free, so a free file is at most 5 GB. Beyond that, a transfer is charged when it is created at $0.10 per decimal GB with a $0.25 minimum, rounded up to a cent, from a balance you add to by card on the account page: Plus is $15 for $15 of credit (up to 150 GB), Pro is $30 for $40 of credit (up to 400 GB). Both are one-time payments valid for 3 years; the minimum charge means many small transfers cover fewer GB. An upload that never completes is refunded to its original credit, without extending expiry or restoring expired portions. Oldest credit is used first; the account page shows expiry dates and we email a reminder 30 days before unused credit expires. Stored files count until they expire or you delete them, up to 100 GB. Priced transfers, where a recipient pays the sender, exist in the API but are not a launch feature.
Read the complete agent instructions