DurableFile

Public artifact hosting for AI agents and automation

Give every agent deliverable a durable URL.

Upload a report, export, log, archive, or build output — any file up to 25 MiB. Get one public download URL back. $1 per 1 GiB, one-time. No email. No password. No CAPTCHA. No dashboard.

bash
# 1 — create an account. No email, no CAPTCHA, no human step.
curl -X POST https://durablefile.com/v1/accounts
→ {"api_key":"durable_…","status":"unpaid","next_step":"POST …/v1/credit"}

# 2 — buy storage. $1 = 1 GiB, one-time, stacks.
curl -X POST https://durablefile.com/v1/credit \
  -H "Authorization: Bearer $DURABLEFILE_KEY" \
  -H "Content-Type: application/json" -d '{"gb":1}'
→ {"checkout_url":"https://checkout.stripe.com/…","machine_payment_options":[…]}

# 3 — upload. The URL in the response is live.
curl -X POST https://durablefile.com/v1/upload \
  -H "Authorization: Bearer $DURABLEFILE_KEY" \
  -F "file=@report.pdf"
→ {"public_url":"https://f.durablefile.com/f/<sha256>/report.pdf","status":"live"}

How it works

  1. Create an account

    One POST request returns the API key. The key is shown once — store it in a secret manager.

  2. Buy storage

    One dollar grants one GiB. Purchases stack and do not expire. A new account has zero quota until it pays.

  3. Upload a file

    Multipart field file or raw bytes. Synchronous checks, then the response carries the live URL.

  4. Share the URL

    Content-addressed, download-only delivery. The same bytes always map to the same URL.

What agents host here

Reports

CI test reports, rendered invoices, generated documents a client downloads once and keeps.

Data exports

CSV and JSON dumps from a pipeline or cron job, ready for a spreadsheet or another agent to fetch.

Build logs

Plain-text command output, linkable from a ticket instead of pasted into it.

Archives

Zips of artifacts, wheels, datasets, or binaries that a downstream step pulls by URL.

Media

Screenshots, renders, and video clips delivered as downloads, not inline pages.

Anything else

There is no allowlist. If the bytes are under 25 MiB, the upload works.

Any file type works, up to 25 MiB per file. Every download is forced attachment with nosniff, so nothing served here renders or executes in a browser. Files are public: do not upload secrets or personal data.

Why DurableFile

Payment before upload
There is no free upload tier. Account creation is free and unlimited, so any free allowance would be farmable. The first dollar is the abuse gate.
Same bytes, same URL
Files are addressed by their SHA-256 hash. Retried uploads are idempotent, never billed twice, and identical bytes are stored once.
Errors an agent can act on
Every actionable 4xx response carries an exact fix field that states the next call to make.
A retention clock you control
Every file serves for 14 days by default, up to 180 on request. Republish or re-upload before expiry to renew — the URL stays identical.
Delete frees quota
A delete frees the caller's quota immediately. The stored object disappears only when no account claims it.
Download-only delivery
Every public response forces Content-Disposition: attachment with nosniff. Nothing served here executes in a browser.

Lifecycle

No expiry sentThe file serves for 14 days from upload.
expires_after_hours / expires_atYour own window, from minutes up to 180 days. One value only, never null.
Expiry passesThe URL returns 404 and the file stops using quota. A background purge removes the bytes soon after.
Manual unpublishHides the link now; the bytes stay until their expiry time.
POST /v1/files/:hash/publishRepublishes the identical URL and starts a fresh expiry window.
DELETE /v1/files/:hashFrees the caller's quota immediately. The shared object survives while another account still claims it.

Pricing

$1 = 1 GiB of storage. One-time, and it stacks.

No subscription, no metered bandwidth, no balance that drains. Buy a gigabyte when you need one. There is no free upload tier. Pay by card through Stripe, or machine-to-machine with stablecoins through usevig — the checkout response carries both options, and an agent can settle the usevig one without a human. Storage purchases never expire; files do — 14 days by default, 180 at most, renewable.

API

POST /v1/accountsCreate an account. Returns the API key once.
POST /v1/creditBuy storage. Body {"gb": N}. Returns Stripe and usevig options.
GET /v1/meQuota, bytes used, bytes remaining.
POST /v1/uploadMultipart field file, or raw bytes with X-Filename.
GET /v1/filesList your file claims, paginated.
GET /v1/files/:hashMetadata and publish state for one file.
POST /v1/files/:hash/publishRepublish, or start a new expiry window.
POST /v1/files/:hash/unpublishHide the link now. Bytes stay until their expiry.
DELETE /v1/files/:hashRemove your claim and free its quota.
GET /f/:hash/:filenamePublic download. Forced attachment.
GET /healthLiveness. Public.

FAQ

What files can I upload?
Anything up to 25 MiB. There is no allowlist: PDFs, CSV exports, JSON results, logs, Markdown, archives, images, videos, and unknown binaries all work. Delivery always forces a download attachment with nosniff and a sandbox policy, so a served file never renders or executes in a browser.
Are files public?
Yes. Anyone with the URL can download the file. Do not upload secrets or sensitive personal data. There are no private files.
How long does a URL last?
Fourteen days by default. Send expires_after_hours or expires_at for up to 180 days. Republish or re-upload before expiry to renew at the same URL. Expired files stop serving and free their quota automatically.
Where do inline images go?
DurableFile delivers downloads, not inline rendering. If you want an image that embeds in a page or README, use the sibling host imgd.dev.
What happens when I upload identical bytes?
The same bytes produce the same hash and the same URL. A repeat upload from your account starts the requested expiry window again — the 14-day default when you send none — and is not billed twice. Another account uploading the same bytes gets its own claim against its own quota while the object is stored once.
How do expiry, unpublish, and delete differ?
An expiry ends the file: the URL returns 404, quota use stops, and a purge removes the bytes soon after. An unpublish hides the link temporarily and keeps the bytes until their expiry time. A delete removes your claim and frees your quota immediately; the object itself goes only when no account claims it.
What does 1 GiB cost?
One dollar, once. Purchases stack: five payments of $1 give 5 GiB. There is no subscription and no bandwidth charge, and storage purchases never expire.
Can an agent pay by itself?
Yes. The checkout response includes machine-payable stablecoin options through usevig — an exact amount, token, and address an agent can pay without a browser or card. The Stripe checkout URL covers the human-with-a-card path.