Piggy Send

Developers

Piggy Send API

Five endpoints cover upload, create, lookup, download and delete. All endpoints are POST with JSON bodies (except upload). Without a token, guest quota applies (1 GB, 7 days); send an API Token to use your account quota.

Download links are issued by the server after checking expiry and download count. All inputs are validated server-side, and quotas are enforced only on the server.

API Token

Add the X-Api-Key header to call the API with your account quota. Keep it secret — never commit it to a public repo.

POST/api/apps/6a9a6a33f8552c104c920ebc/integration-endpoints/Core/UploadFile

Step 1: upload the file directly

Upload large files straight to the storage endpoint instead of proxying them through /functions (a proxied body hits the request-size limit and the function memory/timeout, showing up as 413 or 502). POST multipart/form-data with a file field, no auth required, and you get a file_url — pass it as file_uri to createTransfer in step 2. Files can be uploaded in parallel and there is no total cap.

curl -X POST https://piggysend.com/api/apps/6a9a6a33f8552c104c920ebc/integration-endpoints/Core/UploadFile \
  -F "file=@./movie.mp4"
{
  "file_url": "https://…/movie.mp4"
}
POST/functions/createTransfer

Step 2: create the transfer

Bundle the file_url values from step 1 (as file_uri) into one transfer with an expiry and download limit. The server validates each file size, the expiry and your transfer quota (guest 1 GB / signed-in 10 GB / Pro 1 TB, no total cap), then returns an unguessable short link.

curl -X POST https://piggysend.com/functions/createTransfer \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ps_xxx" \
  -d '{
    "title": "Weekend photos",
    "message": "Check the last one!",
    "files": [{ "name": "movie.mp4", "size": 734003200, "type": "video/mp4", "file_uri": "https://…" }],
    "expires_in_days": 7,
    "max_downloads": 10
  }'
{
  "slug": "k3Jd9sLq2mXa7B",
  "url": "https://piggysend.com/t/k3Jd9sLq2mXa7B",
  "expires_at": "2026-09-11T06:50:00.000Z"
}
POST/functions/getTransfer

Get transfer info

Fetch the public info of a transfer by slug: file names, sizes, downloads left, expiry and state.

curl -X POST https://piggysend.com/functions/getTransfer \
  -H "Content-Type: application/json" \
  -d '{ "slug": "k3Jd9sLq2mXa7B" }'
{
  "slug": "k3Jd9sLq2mXa7B",
  "title": "Weekend photos",
  "files": [{ "name": "movie.mp4", "size": 734003200, "type": "video/mp4" }],
  "total_size": 734003200,
  "max_downloads": 10,
  "download_count": 2,
  "expires_at": "2026-09-11T06:50:00.000Z",
  "state": "active"
}
POST/functions/downloadTransfer

Get download links

Returns download links after checking expiry and download count, and counts one download. Pass file_index for a single file, omit it for all files.

curl -X POST https://piggysend.com/functions/downloadTransfer \
  -H "Content-Type: application/json" \
  -d '{ "slug": "k3Jd9sLq2mXa7B", "file_index": 0 }'
{
  "files": [{ "name": "movie.mp4", "size": 734003200, "url": "https://…" }],
  "expires_in": 300,
  "download_count": 3
}
POST/functions/chunked upload

Large files: chunked upload

Split files over 10 MiB into 10 MiB (10485760-byte) parts and upload each part with step 1 (in parallel, retrying single parts on failure). Then upload a manifest JSON the same way, pass its URL as file_uri, and add chunked, chunk_size and chunk_count to the file entry in createTransfer.

# manifest.json
{
  "version": 1, "name": "movie.mp4", "size": 734003200, "type": "video/mp4",
  "chunk_size": 10485760,
  "chunks": [{ "i": 0, "size": 10485760, "url": "https://…part0" }, …]
}

# createTransfer 中的文件项 / file entry
{ "name": "movie.mp4", "size": 734003200, "type": "video/mp4",
  "file_uri": "https://…manifest.json",
  "chunked": true, "chunk_size": 10485760, "chunk_count": 70 }
{ "slug": "k3Jd9sLq2mXa7B", … }
POST/functions/mergeDownload

Merged download (streaming, resumable)

Streams the original file while pulling its parts in order on the server; works for plain files too. Supports Range requests for resuming; only a request starting at byte 0 counts as a download. A single request lasts about 5 minutes at most, so resume very large files with Range, or fetch the parts yourself via the manifest_url from downloadTransfer.

curl -X POST https://piggysend.com/functions/mergeDownload \
  -H "Content-Type: application/json" \
  -d '{ "slug": "k3Jd9sLq2mXa7B", "file_index": 0 }' \
  -o movie.mp4

# 续传 / resume
curl -X POST https://piggysend.com/functions/mergeDownload \
  -H "Content-Type: application/json" \
  -H "Range: bytes=$(stat -c%s movie.mp4)-" \
  -d '{ "slug": "k3Jd9sLq2mXa7B", "file_index": 0 }' >> movie.mp4
HTTP/1.1 206 Partial Content
Content-Range: bytes 52428800-734003199/734003200
Accept-Ranges: bytes
<binary>
POST/functions/deleteTransfer

Delete a transfer

Requires an API Token. Only the owner can delete a transfer; it stops working immediately and frees up quota.

curl -X POST https://piggysend.com/functions/deleteTransfer \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ps_xxx" \
  -d '{ "slug": "k3Jd9sLq2mXa7B" }'
{ "ok": true }