Unzip a file
Send a ZIP archive and get back a structured listing of every file and folder inside it, or the extracted contents themselves, without ever unzipping anything on your own servers. It's built for pipelines that receive archives from users, partners or storage buckets and need to know what's inside before deciding what to do with it.
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
Why archives are a liability, not a convenience
A ZIP file is a black box until you open it, and opening untrusted archives on production infrastructure is how zip bombs and path-traversal exploits ('zip slip') end up on the front page of an incident report. Teams that accept user uploads — CMS media libraries, plugin marketplaces, bulk import tools — need a way to inspect and extract archive contents in an isolated environment, so a malformed or malicious file never touches the machine running your application code.
What the endpoint actually does
POST /data/unzip accepts an archive by upload or by URL and an operation flag: list to return file names, sizes, compression ratios and timestamps without extracting anything, or extract to unpack selected paths (or everything) and return the results as individual files behind signed links, or bundled into a fresh archive. The call returns a task_id immediately; the real work happens asynchronously.
A short history of a very old format
The ZIP format dates back to 1989 and PKWARE's PKZIP, designed to squeeze floppy-disk-era files into less space. It became a de facto standard because it's an open specification that any tool could implement, which is exactly why it now shows up everywhere from Office documents (which are ZIPs internally) to Android APKs, Java JARs and game mod packages — our unzip endpoint handles the same DEFLATE-based entries those formats rely on.
What to expect from the response
Listing a 500-entry archive and extracting three specific files from it typically finishes in well under a second of actual processing time once the task starts; delivery timing depends on whether you're polling, waiting on a webhook, or fetching the signed result link, which stays valid for 24 hours. Directory structure, file permissions metadata and original timestamps are preserved in the response so downstream code can rebuild the archive's layout exactly.
Where it fits in a bigger workflow
This is one step, not a whole pipeline: pair it with our conversion and file-processing endpoints to, say, unzip a theme package, validate each file's type, then hand images to a resize task and stylesheets to a minifier — all triggered off the same webhook chain. Because failed tasks are never billed, you can wire this into an upload handler without worrying about paying for corrupt or empty archives your users inevitably send.
What you can do with it
Plugin and theme marketplaces
Inspect the file list of an uploaded plugin ZIP before extraction to reject anything with executable files or suspicious paths outside the expected folder.
Bulk media imports
Extract hundreds of product images from a single vendor-supplied archive and route each one straight into a resize or watermark task.
Backup and migration tooling
Unpack a site or database export archive server-side so a migration script can read individual files without ever writing the raw ZIP to disk.
User-submitted data sets
List the contents of a ZIP submitted through a public form to confirm it contains only the expected CSV or JSON files before further processing.
FAQ
How do I extract a ZIP file using the API?
Send a POST request to /data/unzip with the archive as an upload or a URL and set the operation to extract; you'll get a task_id and the extracted files arrive via webhook or a signed link.
Can I just list the contents without extracting?
Yes, set the operation to list to get file names, sizes and timestamps without unpacking anything, which is useful for validating an archive before committing to full extraction.
Is there a free tier for the unzip API?
The tool above runs free in your browser. The API is paid — each call draws from your prepaid ForHosting KIT balance: top up from $10.00 (it never expires), pay each request's published price, and a call with no balance returns HTTP 402. No subscription, no tokens, and a failed task is never charged.
What happens if the ZIP is corrupted or password-protected?
The task fails cleanly with a descriptive error after a limited number of retries, and a failed task is never charged.
How much does the unzip endpoint cost?
It's $0.002 per request regardless of how many files the archive contains, so listing or extracting a 2-file or 2,000-file archive costs the same.
Does it support nested ZIPs, like an archive inside an archive?
The endpoint extracts the top-level archive; if an entry is itself a ZIP, you can pass it back through the same endpoint as a second call.
How long are extracted files available for download?
Signed result links are valid for 24 hours, and we recommend a webhook for anything you need to process immediately or store permanently.
Is my uploaded archive kept after processing?
No, archives and their extracted contents are deleted after the retention window and are never used for training.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/data/unzip \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"input":"…"}'const res = await fetch("https://api.kit.forhosting.com/data/unzip", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"input": "…"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/data/unzip",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"input": "…"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/data/unzip", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"input":"…"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"input":"…"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/data/unzip", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"input": "…"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "data.unzip",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |