Zaulto API – for uploaders

With the Zaulto API you create containers programmatically and read at any time which links of your containers are online or offline – including the hoster. It is built for uploaders who want to wire Zaulto into their own tools, scripts or upload workflows.

Your token = your access. Treat it like a password.

An API token is shown exactly once at creation time and cannot be retrieved afterwards. Save it immediately in a safe place (e.g. a password manager) and never commit it to a repository or frontend code.

Always pass the token in the Authorization header – never in the URL, since URLs end up in logs and browser history. If you suspect it has leaked, revoke it in your account right away and create a new one. Every token is limited to your own account and to its type. An upload token (scope “upload”) can create containers on your behalf and read the link status of your own containers – it cannot read, change or delete anyone else's containers, and it never returns the download links themselves. A token for the reupload tool (scope “reupload”) only works on the reupload endpoints below.

Authentication & creating a token

The upload API authenticates with a personal bearer token. Here's how to get one: sign in, open the “API tokens” area in your account, give it a descriptive label (e.g. “My upload script”, up to 100 characters – longer ones are truncated) and optionally a lifetime in days (at most 3650 days; without one the token does not expire). The token is shown once in clear text – copy it immediately.

On every request send the header Authorization: Bearer <YOUR_TOKEN>. If the header is missing or not of the form Bearer <token>, the API responds with 401 and missing_bearer_token. If the token is unknown, revoked or expired – or your account is suspended or not yet approved – you get 401 with invalid_token. Resetting your password via “Forgot password” revokes all your tokens.

Header
Authorization: Bearer zaulto_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Manage tokens in your account

Create a container

A POST to /api/v1/containers with a JSON body (Content-Type: application/json) creates a new link container in your account. Only title and at least one link in links are required; every other field is optional with the defaults listed below. Unknown fields are ignored. Only http and https links are accepted.

If hoster or filename is missing, Zaulto takes the host name or the file name from the URL. Links with the same file name within one link set are grouped as mirrors of the same file. After creation Zaulto starts a link check in the background – until the first check the links have the status unknown.

Rules for customSlug: 3–40 characters, only letters A–Z/a–z, digits, - and _; the first and last character must be a letter or digit. Surrounding whitespace is trimmed, an empty string is invalid – omit the field if you don't want a slug. Reserved (case-insensitive) are api, admin, assets, contact, create, crypt, dashboard, disclaimer, favicon, login, logout, new, privacy, public and static → 400 reserved_slug. Slugs are unique case-insensitively; if one is already taken – also by a deleted container, since slugs are never released – you get 409 slug_taken.

With folderId you file the container into a folder of your account (omit or null = top level). An unknown or foreign folder yields 404 folder_not_found.

The response (201) contains id (8 characters from A–Z without I and O plus the digits 2–9), slug (your customSlug or null), url (public container URL via the ID) and shortUrl (URL via the slug, null without a slug) – so you can hand out the link right away. Access protection, expiry and display are set with the fields in the next section.

MethodPathAuthPurpose
POST/api/v1/containersBearer tokenCreate a new container with one or more links.
Request (curl)
curl -X POST https://zaulto.com/api/v1/containers \
  -H "Authorization: Bearer $ZAULTO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My release",
    "links": [
      { "url": "https://filer.net/get/abc123", "filename": "part1.rar" },
      { "url": "https://ddownload.com/abc123xyz", "filename": "part2.rar" }
    ]
  }'
Response (201)
{
  "id": "AB23CD45",
  "slug": null,
  "url": "https://zaulto.com/#/c/AB23CD45",
  "shortUrl": null
}
Request fields: content (JSON body)
FieldTypeDescription
titlestring (1–200)Required. Container title.
linksarray (1–200)Required. Original link set (tier 0), entries as below.
links[].urlstring (≤2048)Required. Full http or https URL.
links[].hosterstring (≤200)Optional. Default: host name from the URL.
links[].filenamestring (≤255)Optional. Default: file name from the URL.
descriptionstring (≤2000)Optional description (default: empty).
customSlugstring (3–40)Optional custom short slug for the URL, rules see above.
folderIdstring|null (≤64)Folder of your account; null or omitted = top level.
mirrorSetsarray (≤20 × ≤200)Mirror tiers 1, 2, … as complete replacement link sets (entries like links). Visitors get the lowest tier with at least one online link. Empty sets are skipped; the numbering of the following ones is kept.
listedbooleanList in the public directory (default: false). It only appears there while the container is active and not expired, has no password (not even via its folder) and uses no referrer filter.

Protection, expiry & display on creation

All fields in this section are optional and go into the same JSON body as title and links. With them you enable access protection right at creation – a password, a captcha, an expiry date or access limit – and decide what visitors see on the container page. Numbers are integers; values outside the range are rejected with 400 validation, not adjusted.

Points in time (expiresAt, autoDeleteAt) are Unix time in milliseconds; null means “never”, 0 is invalid. Once one of them is reached, the container is deleted automatically. With urlMasking the real hoster URL stays hidden; autoProtection requires masking and is stored as false without it.

Example body with protection
{
  "title": "My release",
  "customSlug": "my-release",
  "links": [{ "url": "https://filer.net/get/abc123" }],
  "mirrorSets": [[{ "url": "https://ddownload.com/abc123xyz" }]],
  "password": "secret",
  "captchaRequired": true,
  "captchaType": "pow",
  "expiresAt": 1798761600000,
  "maxDownloads": 500,
  "urlMasking": true
}
Request fields: protection, expiry & display
FieldTypeDescription
passwordstring (≤200)Password visitors need to open the container. Default: empty = no password.
captchaRequiredbooleanRequire a captcha before opening (default: false).
captchaTypemath|pow|question|turnstileArithmetic task, invisible proof-of-work, your own question or Cloudflare Turnstile (default: math). turnstile only when the operator has set it up – otherwise 400 captcha_type_unavailable.
captchaQuestionstring (≤200)Only with captchaType question: the question shown to visitors.
captchaAnswerstring (≤200)Only with captchaType question: the expected answer (stored hashed only). Without an answer the container shows an arithmetic challenge instead.
adaptiveCaptchabooleanCaptcha only for suspicious IPs: from adaptiveThreshold accesses within 24 hours. Works without captchaRequired too; with captchaRequired the captcha applies to everyone anyway (default: false).
adaptiveThresholdinteger (2–1000)Threshold for adaptiveCaptcha (default: 8).
honeypotEnabledbooleanEnable an invisible decoy link for automated link collectors; hits appear in the access log, the 24 h block is off during the measurement phase (default: false).
expiresAtinteger|nullExpiry time (Unix time in ms). Default: null = never expires.
autoDeleteAtinteger|nullTime (Unix time in ms) at which the container deletes itself. Default: null.
maxDownloadsinteger|null (1–1,000,000)Maximum number of successful unlocks across all visitors; after that access is denied. Default: null = unlimited.
maxAccessesinteger|null (1–1,000,000)The container deletes itself after this many allowed accesses. Default: null = off.
geoModeoff|allow|blockCountry filter: allow only the countries in geoCountries or block them (default: off). With allow, visitors from an unknown country are refused.
geoCountriesstring[] (≤250)Two-letter country codes (ISO 3166-1), e.g. DE, AT.
referrerModeoff|allowWith allow, only visitors coming from a domain in referrerAllow (subdomains included); no referrer means no access (default: off). Protects against linking/embedding by other sites, not against scripts (the origin can be faked).
referrerAllowstring[] (≤100, each ≤253)Allowed domains, e.g. example.com.
rateLimitEnabledbooleanEnable an access limit per visitor IP (default: false).
rateLimitMaxinteger (1–1000)Successful accesses per IP within the window (default: 4).
rateLimitWindowDaysinteger (1–365)Length of the window in days (default: 7).
stealthModebooleanRefused visitors get 404 (as if the container did not exist) instead of 403 (default: true).
showIndividualLinksbooleanShow individual links on the container page (default: true).
enableClickAndLoadbooleanOffer Click'n'Load (default: false).
enableDlcFilebooleanOffer a DLC file (default: false); automatically unavailable with urlMasking.
allowCopyLinksbooleanAllow copying the links (default: true).
showHosterNamesbooleanShow hoster names (default: true).
urlMaskingbooleanURL masking: the real hoster URL stays hidden (default: false).
autoProtectionbooleanInterstitial page with countdown and captcha before the hoster; only with urlMasking (default: false).
autoProtectionSecondsinteger (3–30)Countdown of the interstitial page in seconds (default: 5).
forcedLangde|en|nullForce the container page language; null = the visitor's language (default).

Read your containers' link status

A GET to /api/v1/containers/:id/status returns, for one of your own containers, the status of every link (online, offline or unknown) together with file name and hoster – so you can detect automatically what is offline where. :id is the container ID or your slug (the slug case-insensitively). You need the same bearer token as for creating; only containers of your account can be read – anyone else's, deleted and unknown containers all get the same 404 not_found.

The response deliberately contains no download links – so even a leaked token does not reveal them. Links are sorted by tier. Per mirror tier (tiers) you see the counts and which tier is currently served to visitors: the lowest one with at least one online link, or tier 0 if no link is online anywhere. Zaulto keeps the status current via its built-in, regular link check; lastCheckedAt is the latest check (Unix time in milliseconds) and null as long as no link has been checked yet.

state becomes expired once expiresAt or autoDeleteAt is reached. You only see that briefly: expired containers are deleted automatically (on the next visitor request, otherwise within 5 minutes) – after that the request returns 404. When maxAccesses is reached the container is deleted the same way, without showing expired first. If maxDownloads is used up, on the other hand, the container stays and state remains active; visitors are refused, though.

The public endpoint GET /api/c/:id, from which the container page loads its data, by contrast gives visitors only metadata such as title and protection settings – neither links nor link status. So file names and hosters of password-protected containers stay hidden.

MethodPathAuthPurpose
GET/api/v1/containers/:id/statusBearer tokenStatus (online, offline, unknown) of each link of one of your containers, with file name and hoster.
Request (curl)
curl https://zaulto.com/api/v1/containers/AB23CD45/status \
  -H "Authorization: Bearer $ZAULTO_TOKEN"
Response (200)
{
  "id": "AB23CD45",
  "slug": null,
  "title": "My release",
  "state": "active",
  "activeTier": 0,
  "lastCheckedAt": 1790000000000,
  "tiers": [
    { "tier": 0, "active": true, "total": 2, "online": 1, "offline": 1, "unknown": 0 }
  ],
  "links": [
    { "id": 101, "tier": 0, "filename": "part1.rar", "hoster": "filer.net", "status": "online", "lastCheckedAt": 1790000000000 },
    { "id": 102, "tier": 0, "filename": "part2.rar", "hoster": "ddownload.com", "status": "offline", "lastCheckedAt": 1790000000000 }
  ]
}
Response fields (200)
FieldTypeMeaning
idstringContainer ID (8 characters).
slugstring|nullCustom slug or null.
titlestringContainer title.
statestringactive, expired (expiresAt or autoDeleteAt reached, until the automatic deletion) or disabled (locked by the Zaulto team, not publicly reachable).
activeTiernumberTier visitors currently get: 0 = original, 1+ = mirror.
lastCheckedAtnumber|nullLatest check across all links (Unix time in ms), null = never checked.
tiers[]arrayPer tier: tier, active, total, online, offline, unknown.
links[]arrayPer link: id, tier, filename, hoster, status, lastCheckedAt (null = not checked yet).
status: onlinelink statusFile is reachable at the hoster.
status: offlinelink statusFile is deleted or no longer available.
status: unknownlink statusNot checked yet or could not be determined unambiguously.

Which hosters are detected especially precisely

Reupload tool: replace offline links automatically

The reupload tool runs on your computer and knows your files locally. In the tool you select the containers whose files are on that computer (none at first). When a link in a selected container goes offline, Zaulto creates a job; the tool picks it up, uploads the file again to a hoster and reports the new URL back. Zaulto then replaces the link in the container at the same position and checks it again shortly after. You switch it on and off, pause it and follow the jobs in your account under “Reupload tool”.

These endpoints need a token of its own with the type Reupload tool (scope reupload). The tool gets it itself: login takes your account's username and password and returns a new token (same check and attempt limit as the browser sign-in; a new login from the same computer – field device – revokes that computer's old token). Alternatively you create it in your account under “API tokens”. logout revokes the calling token, “Sign the tool out everywhere” in your account revokes all reupload tokens. It only works here; the upload API rejects it with 401 invalid_token – and an upload token is rejected here the same way. These responses, too, never contain the old download URL, only file name, hoster and size.

Flow: heartbeat reports the version and the hosters the tool holds an account for. pending returns jobs of selected containers for exactly those hosters only and is empty while the tool is switched off or paused in your account. With claim the tool takes a job for 2 hours; progress reports progress and extends the claim. result closes it. Anyone else's and unknown jobs all get the same 404 not_found; if a job is already closed or no longer fits (link deleted, back online or discarded in your account), you get 410 job_closed.

The new URL in result must be http or https, point to public addresses and be on the old hoster or one of these hosters: filer.net, ddownload.com, rapidgator.net, nitroflare.com, uploady.io – otherwise 400 url_rejected with a reason (scheme, host_not_allowed or ssrf). Error texts from upload_failed are cut to one line of 200 characters with local paths removed.

Request limits per token: heartbeat 10 per minute, pending and containers 30 per minute each, selection 120 per minute, claim/progress/result together 300 in 5 minutes; beyond that 429 too_many_requests. Every response carries Cache-Control: no-store.

MethodPathAuthPurpose
POST/api/v1/reupload/login–{ username, password, device? } ⇒ { token, username }; switches the tool on for the account (a pause stays); 401 invalid_credentials, 403 account_pending/account_suspended, 429 rate_limited.
POST/api/v1/reupload/logoutReupload tokenRevokes the calling token.
POST/api/v1/reupload/heartbeatReupload tokenSign of life with version and hosters; returns the switch state and poll interval.
GET/api/v1/reupload/updateReupload tokenCurrent tool version for the self-update: { version, size, sha256, signature }; 404 no_release. The tool checks the signature itself.
GET/api/v1/reupload/update/downloadReupload tokenProgram file of that version (6 per hour per token).
GET/api/v1/reupload/containersReupload tokenYour active containers for the selection: { containers: [{ containerId, title, folder, links, offline, selected }] }.
PUT/api/v1/reupload/containers/:containerIdReupload tokenSelect or deselect a container: { selected: true|false }. Only selected containers get jobs; deselecting ends their open jobs.
GET/api/v1/reupload/pending?limit=50Reupload tokenOpen jobs of selected containers for the reported hosters (limit 1–100, default 50).
POST/api/v1/reupload/jobs/:jobId/claimReupload tokenTake a job (409 already_claimed if it is taken).
POST/api/v1/reupload/jobs/:jobId/progressReupload tokenReport progress { percent: 0–100 }, extends the claim.
POST/api/v1/reupload/jobs/:jobId/resultReupload tokenReport the result; with uploaded the link is replaced.
Heartbeat (curl)
curl -X POST https://zaulto.com/api/v1/reupload/heartbeat \
  -H "Authorization: Bearer $ZAULTO_REUPLOAD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "version": "1.0.0", "hosters": ["filer.net", "ddownload.com"] }'
Response (200)
{
  "enabled": true,
  "paused": false,
  "pollIntervalSec": 60,
  "latestVersion": "1.0.0",
  "username": "uploader"
}
Open jobs (200)
{
  "jobs": [
    {
      "jobId": 7,
      "linkId": 102,
      "containerId": "AB23CD45",
      "containerTitle": "My release",
      "filename": "part2.rar",
      "hoster": "ddownload.com",
      "hosterSize": 1048576000,
      "hosterMd5": null,
      "tier": 0,
      "position": 2,
      "offlineSince": 1790000000000
    }
  ]
}
Report a result (curl)
curl -X POST https://zaulto.com/api/v1/reupload/jobs/7/result \
  -H "Authorization: Bearer $ZAULTO_REUPLOAD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "outcome": "uploaded", "url": "https://ddownload.com/new123xyz" }'
Fields
FieldTypeMeaning
heartbeat: versionstring (≤32)Required. Tool version, e.g. 1.0.0.
heartbeat: hostersstring[] (≤20)Hosters with a stored account, e.g. filer.net.
pending: jobs[]arrayjobId, linkId, containerId, containerTitle, filename, hoster, hosterSize, hosterMd5, tier, position, offlineSince.
filenamestringFile name of the link; if missing, the file name at the hoster, otherwise empty.
hosterSize / hosterMd5number|null / string|nullSize in bytes and MD5 according to the hoster, where known – for matching the local file.
positionnumberPosition of the link within its tier (from 1).
offlineSincenumber|nullSince when the link has been offline (Unix time in ms).
result: outcomestringuploaded (with url, optional size and md5), file_missing, ambiguous, no_account or upload_failed (optional error).
claim/progress: claimTtlSecnumberSeconds the claim is valid (7200).

Reupload tool in your account

Limits & error codes

A container's original link set holds up to 200 links, plus up to 20 mirror tiers with up to 200 links each. Titles are capped at 200, descriptions at 2000 characters, the JSON body at 1 MB (larger → 413). There is no fixed upper limit on the number of your containers.

Status reads are limited to 300 requests per token in a sliding 5-minute window; beyond that you get 429 too_many_requests. Rejected requests count too – if you keep polling at the same rate, you stay blocked. So wait until older requests drop out of the window. Requests with a missing or invalid token (401) do not count. Creating containers has no request limit of its own.

Errors come as JSON {"error": "<code>"}; with validation there is also details with formErrors (errors of the body as a whole) and fieldErrors (a list of messages per field). Exceptions: invalid JSON (400), a too large body (413) and internal errors (500) respond with {"message": "…"}. Evaluate the HTTP status code, not only the body.

HTTP status codes
HTTPerrorMeaning
201–Container was created (POST).
200–Status returned (GET).
400validationBody breaks the field rules (e.g. missing title, invalid URL, value out of range); an invalid customSlug shows up as invalid_slug in details.fieldErrors.customSlug.
400reserved_slugcustomSlug is a reserved word.
400(message)Body is not valid JSON.
401missing_bearer_tokenAuthorization header missing or not of the form Bearer <token>.
401invalid_tokenToken unknown, revoked or expired, wrong scope, or account suspended or not approved.
404folder_not_foundfolderId is not a folder of your account (POST).
404not_foundContainer unknown, deleted or not in your account (GET).
409slug_takencustomSlug is already taken (also by a deleted container).
413(message)JSON body larger than 1 MB.
429too_many_requestsMore than 300 status reads within 5 minutes with one token (GET).
500(message)Internal error – try again later.

Security – keeping your access tight

Store the token server-side or in a secret store only, never in browser code or public repositories. Create a separate token with its own label per app/script – that way you can revoke a single one precisely without affecting the others.

Set a lifetime where it makes sense so a forgotten token expires automatically. Send requests over HTTPS only. And if a token ever does leak: revoke it in your account immediately – a revoked token is worthless instantly.

More on security & privacy

That's everything to wire Zaulto cleanly into your uploads: create containers via token and monitor the online/offline status automatically.

Zaulto roadmap

From the first concept to the finished platform – how Zaulto evolves step by step.

Spring 2026 – Polish & security

  • AutoProtect, stealth mode and geo-IP rules
  • DLC/Click'n'Load support added
  • Analytics, user management and API tokens

June 2026 – Soft launch

  • Public launch of the platform (beta)
  • Bilingual interface and knowledge base live
  • Feedback gathered from first users

Summer 2026 – Stabilisation & expansion

  • Feedback incorporated, performance optimised
  • Hosters ddownload, rapidgator, nitroflare and uploady connected
  • Documentation and FAQ expanded

End of September 2026 – Version 1.0

  • Official version 1.0 of the platform
  • Complete API and stable interfaces
  • Full feature set for all users