Your storage · A code · Your client’s answer
Deliver. Get it signed off.
colis sends your deliverable to a bucket you own under an eight-character code. Your client opens it, previews it, then approves it or asks for changes. You know when it was opened and what they answered, and every step can start an automation.
- ✓ sent
- ✓ opened
- ✓ approved
- colis-site.vercel.app
- Your bucket
- No account for your client
- Preview
- Approve or ask for changes
- Signed webhooks
- n8n
- Resumable large files
- AWS S3
- Cloudflare R2
- MinIO
- Scaleway
- Wasabi
- A CLI in French
- MIT
01Send. Open. Sign off.
A delivery in three steps.
The file goes from your machine to your bucket, and from your bucket to your client. Nobody else stores it, and nobody signs up for anything.
- send
Send it to your bucket.
Drop the file on your delivery page, or send it from a terminal with colis envoyer. It lands in your bucket under a fresh code, with a lifetime, and if you want a password, a note, or burn after the first download.
- open
Your client opens it.
A link, a QR code, or eight characters typed on the page, typos repaired. They see the file before downloading anything: an image, a PDF, a video, audio, text.
- ok
They approve, or ask for changes.
One click to approve, or a comment on what should change. The answer is final and timestamped, and it shows up on your sending page, in colis statut and in a webhook.
02Three ways in
A page for your client, a terminal for you, a webhook for the rest.
One protocol under all three. The delivery page holds the keys to your bucket; the terminal and the automations talk to it.
The delivery page
templates/dropA Next.js template you deploy on your bucket: the sending page, the pickup page with its preview and its two answers, and your tracking.
https://drop.example.com/K7QP2M4X
maquette-v2.pdf · 1.8 MB · PDF
« La version avec le logo corrigé »
[ the PDF, previewed in the page ]
Le fichier correspond à ce qui était attendu ?
[ Valider la livraison ✓ ] [ Demander des corrections → ]From a terminal
@mdemb/colisenvoyer, recevoir, statut, annuler, verifier: the commands are in French, the code alone goes to stdout so it composes, and statut says where a delivery stands.
# colis.config.json points at your delivery page (colis init --provider remote)
$ colis envoyer ./maquette-v2.pdf
maquette-v2.pdf · 1.8 MB · expires in 1 day
K7QP2M4X
# later: where does it stand?
$ colis statut K7QP2M4X
validé
envoyé 2026-09-22 10:00
ouvert 2026-09-22 11:00
validé 2026-09-22 12:00Automations
n8n-nodes-colisA signed webhook at every step, from parcel.sent to parcel.approved, and an n8n node that starts a workflow on any of them.
// app/api/colis/route.ts, on your side
import { verifyWebhook } from '@colis/protocol'
export async function POST(request: Request) {
const body = await request.text() // the raw body, before any JSON.parse
const result = await verifyWebhook(process.env.DROP_WEBHOOK_SECRET!, request.headers, body)
if (!result.valid) return new Response(null, { status: 401 })
const event = JSON.parse(body)
if (event.type === 'parcel.approved') await sendInvoice(event.data.code) // your code
return new Response(null, { status: 204 })
}03Your storage
Nobody in the middle.
colis is a thin layer over object storage you already pay for. The files stay in your bucket, and the page runs on your deployment.
The file goes from you to your bucket, and from your bucket to your client. Nothing else is in the picture.
Your bucket
S3, R2, MinIO, Scaleway, Wasabi, or any S3-compatible storage. Your provider, your region, your bill.
No account for the client
A code or a link is the whole handshake. A password on the parcel when you want one.
Straight to the bucket
Above a few megabytes, the browser sends the file to the bucket itself, in parts, and resumes if the connection drops.
Expires on its own
Every parcel has a lifetime, checked on every read. A lifecycle rule deletes the object, and colis verifier checks you have one.
04The code
A code your client can type.
Eight characters printed on a shipping label. Read out on a call, typed on a phone, scanned off a QR code: it still finds the parcel.
Complete. Separators dropped, case folded, and O, I and L read as 0, 1 and 1, because Crockford base32 has no O, I or L to confuse them with.
Alphabet 0123456789ABCDEFGHJKMNPQRSTVWXYZ · 8 chars · 40 bits
Eight characters of Crockford base32: no I, L, O or U, so a code survives paper, a phone keyboard and a phone call. What the client types stays as typed; only the lookup is repaired.
The code is also the link: /K7QP2M4X on your delivery page is the pickup page, and the page shows a QR code of it for a phone.
A code is a bearer token. When the file is sensitive, give the parcel a short lifetime, a password, or burn it at the first download.
05Automations
Every step can start something.
The delivery page posts a signed event when a parcel is sent, opened, approved, sent back for changes, or burned. n8n, or any route that takes a POST, picks it up.
webhook · type
- parcel.sent
- A parcel was created, from the page or from the CLI.
- parcel.opened
- The client opened it. The first time only.
- parcel.approved
- The client approved it.
- parcel.changes_requested
- The client asked for changes; data.comment says which.
- parcel.deleted
- The code was burned.
Signed, the Standard Webhooks way
HMAC-SHA256 over the id, the timestamp and the body. verifyWebhook from @colis/protocol checks it with the same code that signs, and refuses anything more than five minutes old.
An n8n node
Colis Trigger starts a workflow on the events you pick and checks the signature for you. The Colis node sends, reads and burns parcels.
06Use cases
What freelancers deliver with it.
Deliver
Automate
07Compared
Why not an attachment, or a transfer site?
Sometimes they are enough. Each page says when, and what colis adds.
08Questions
The ones that come up.
01What is colis?
A delivery tool for freelancers. You send a file to storage you own (S3, R2, MinIO…) under an eight-character code; your client opens a pickup page, previews the file, then approves it or asks for changes with a comment. Every step can fire a signed webhook. There is a delivery page to deploy, a CLI with French commands, and an n8n node. How it works
02Does my client need an account?
No. They get a link, or type the code on the pickup page, typos included: lower case, dashes and an O for a 0 are repaired. If the parcel has a password, they type it once. That is all. On the sending side, an account is optional too: it ties your uploads to your address, signed in by e-mail link.
03Where are the files stored?
In your bucket, and nowhere else. The delivery page runs on your deployment, with your credentials; large files even go straight from the browser to the bucket. colis has no hosted service in the middle. Storage providers
04How do I know the client opened or approved it?
The delivery page keeps a receipt for every parcel: sent, opened (the first opening by someone other than you), then approved or changes, with the time and the comment. You see it on your sending page, with colis statut in a terminal, or in the parcel.opened, parcel.approved and parcel.changes_requested webhooks. Webhooks and n8n
05Can the client change their mind?
No: a parcel gets one answer, and it is never overwritten. For a new version, send a new parcel; it gets its own code and its own receipt.
06How big can a file be?
From the delivery page, up to DROP_MAX_UPLOAD_MB, 2 GB by default: above DROP_MAX_SIZE_MB (4 MB by default, because of Vercel’s request limit), the browser sends straight to the bucket, in 8 MiB parts, resumable. That needs a CORS rule on the bucket. From the CLI or the n8n node, the upload goes through the function in one request and has to fit under DROP_MAX_SIZE_MB. Deliver heavy files
07Is a code secure?
A code is a bearer token: whoever has it can open that parcel while it lives. For a sensitive deliverable, add a password (hashed with scrypt, never recoverable), a short lifetime, or burn after the first download. Wrong passwords are limited: ten from one client, or fifty on one code, lock it for fifteen minutes. A confidential delivery
08What happens when a parcel expires?
It is never handed over again: the expiry is checked on every read, and an expired code answers like one that never existed. The object itself is deleted by a lifecycle rule on your bucket, which colis verifier checks you have. The delivery receipt outlives the file.
09Can I install it with npm?
Yes for the command: npm i -g @mdemb/colis, which works with nothing configured thanks to the public colis service. The n8n-nodes-colis node installs from n8n. The @colis/* packages are not published yet: build those from the repository (bun install, then bun run build), and deploy the delivery page on Vercel by importing the whole repository. Install the CLI
10What does it cost?
colis is free software, under the MIT license: on your own deployment, the only bills are your storage provider’s and your host’s. The public service has two plans. Free: no account, files up to 100 MB, 24-hour links, 20 uploads an hour. Pro, €6 a month or €60 a year, with an account: up to 2 GB, 30-day links, 200 uploads an hour. No trial, cancel any time. The Pro plan (in French)
Send it. They sign off. You know.
Your storage, a delivery page under your name, a webhook at every step. Nothing hosted by someone else.