Most file hosts assume a human. Somewhere in the signup flow there is an email confirmation link, a CAPTCHA, or a dashboard button that a program cannot click. An autonomous agent that just needs to publish a report gets stuck on step one.
DurableFile removes those steps. The whole account model is three HTTP requests, and none of them needs a person.
Create the account
curl -X POST https://durablefile.com/v1/accounts
The response returns the account and its API key:
{
"account_id": "acct_…",
"api_key": "durable_…",
"status": "unpaid",
"storage_quota_bytes": 0,
"next_step": "POST https://durablefile.com/v1/credit with {\"gb\":1}"
}
Two facts matter here.
First, the key is shown once. There is no email address on the account, so there is no password reset and no recovery flow. Store the key in a secret manager or an environment variable immediately. If the key is lost, the account is lost.
Second, the account starts with zero quota. Account creation is free and unlimited, so any free upload allowance would be farmable by creating more accounts. Payment is the abuse gate, which is exactly what makes the no-email model workable.
Fund it
curl -X POST https://durablefile.com/v1/credit \
-H "Authorization: Bearer $DURABLEFILE_KEY" \
-H "Content-Type: application/json" \
-d '{"gb":1}'
The response carries every way to pay:
checkout_url— a hosted Stripe card page. This path needs a human with a card and a browser.machine_payment_options— stablecoin payment instructions through usevig, each with an exact token amount, a network, and an address. An agent with a wallet can settle one of these without any human involvement.
One dollar grants one GiB. Purchases stack and do not expire. Quota is granted
by a signed payment webhook, never by visiting a return page, so poll
GET /v1/me until the quota appears:
curl https://durablefile.com/v1/me \
-H "Authorization: Bearer $DURABLEFILE_KEY"
Proceed when storage_quota_bytes is greater than zero.
Upload
curl -X POST https://durablefile.com/v1/upload \
-H "Authorization: Bearer $DURABLEFILE_KEY" \
-F "file=@report.pdf"
The response contains the live URL:
{
"hash": "…",
"status": "live",
"public_url": "https://f.durablefile.com/f/…/report.pdf",
"deduplicated": false
}
There is no processing state to poll. Validation happens inside the upload request — file type, extension, format signature, UTF-8 for text formats, JSON syntax for JSON — and the URL in the response already works.
Accepted types are PDF, UTF-8 plain text, Markdown, CSV, and valid JSON, up to 25 MiB. Images are rejected with a pointer to imgd.dev, the sibling host built for images.
The error path is part of the API
If the agent skips the payment step and uploads anyway, it gets HTTP 402 with everything needed to recover:
{
"error": "payment_required",
"fix": "buy storage with POST https://durablefile.com/v1/credit and {\"gb\":1}, complete one payment option, then retry the upload",
"topup_url": "https://durablefile.com/v1/credit",
"checkout_url": "https://checkout.stripe.com/…",
"machine_payment_options": []
}
Every actionable 4xx response has a fix field written as an instruction. An
agent should read it and act on it instead of retrying blindly. The
402 payment flow
has its own article.
What to remember
- Files are public. Anyone with the URL can download them. Never upload secrets or personal data.
- The key is shown once and cannot be recovered.
- Zero quota before payment; $1 buys 1 GiB; purchases stack.
- Quota arrives through the payment webhook. Poll
GET /v1/me, do not assume.
From here, the next useful read is how identical bytes map to identical URLs, which is what makes agent retries free.