REST API
Upload bestanden, maak collecties en beheer shares via HTTP. Alle antwoorden zijn JSON; voor anonieme uploads is geen API-sleutel vereist.
Introductie
De storage.to API vormt de basis voor onze CLI, desktopapp, web-uploader en elke third-party client die je wilt bouwen.
Het uploadproces bestaat uit drie stappen:
- Init - laat ons weten dat je een bestand wilt uploaden. We retourneren één of meer presigned URL's die naar Cloudflare R2 wijzen.
- Upload naar R2 -
PUTje bytes direct naar de presigned URL(s). Bytes gaan niet via onze servers. - Bevestigen - laat ons weten dat de upload klaar is. We maken een
File-record en geven je een deelbare URL.
Basis-URL
https://storage.to/apiAlle endpoints hieronder zijn relatief aan deze basis. Voorbeeld: POST /upload/init betekent POST https://storage.to/api/upload/init.
Authenticatie
Anonieme uploads werken zonder authenticatie, maar met strikte limieten. Aanroepen zonder sleutel zijn beperkt tot 50 bestanden per doorlopende 24 uur per apparaat of IP, plus de bandbreedtequota hieronder, en bestanden verlopen na 3 dagen.
Authenticeren met een gratis account ontgrendelt:
- Geen dagelijkse bestandslimiet
- Geen uploadbandbreedtequotum
- Uploads gekoppeld aan je account (zichtbaar op /dashboard)
- Premiumfuncties (permanente bestanden, meer opslag)
- Mutaties op basis van eigendom (verwijderen, wachtwoord instellen, vervaldatum wijzigen) zonder dat je de visitor-token match nodig hebt
Limieten in één oogopslag
| Limiet | Zonder token (anoniem) | Token van gratis account | Token van betaald account |
|---|---|---|---|
| Bestanden per dag | 50 / 24 uur | Onbeperkt | Onbeperkt |
| Uploadbandbreedte | 100 GB / 24 uur (500 GB per IP) | Onbeperkt | Onbeperkt |
| Maximale bestandsgrootte | 25 GB | 25 GB | 100 GB |
| Vervaldatum bestand | Standaard 3 dagen, tot 7 via expiry_days | Standaard 3 dagen, tot 7 via expiry_days | Nooit (bestanden zijn permanent) |
| Opslagruimte | Geen (bestanden verlopen) | Geen (bestanden verlopen) | 100 GB - 1 TB permanent, per abonnement |
Er zijn geen maandelijkse quota - alle limieten zijn voortschrijdende 24-uursvensters of limieten per minuut. Het gratis abonnement heeft geen vaste opslagruimte: elk bestand verloopt vanzelf, dus er stapelt zich niets op tegen een quotum.
Om te authenticeren, genereer je een persoonlijk API-token vanuit je account en stuur je dit als bearer token bij elke aanvraag:
Authorization: Bearer <token>Je moet ingelogd zijn. Het volledige token wordt alleen één keer getoond bij het aanmaken, dus kopieer het naar een veilige plek. Je kunt een token op elk moment intrekken vanaf dezelfde pagina.
Bezoekerstoken
Anonieme clients hebben een manier nodig om eigenaarschap van hun eigen uploads te bewijzen zonder account. We gebruiken een visitor token - een willekeurige tekenreeks die de client één keer genereert en daarna hergebruikt. Stuur deze mee met elke request:
X-Visitor-Token: <random-string>Op het web wordt de token automatisch opgeslagen in de visitor_token-cookie. De CLI slaat deze op op ~/.config/storageto/token (zie CLI-documentatie).
Voor mutatie-endpoints (verwijderen, wachtwoord instellen, vervaldatum wijzigen) wordt eigendom bevestigd als of de bezoeker-token overeenkomt met of het verzoek afkomstig is van hetzelfde IP dat het bestand heeft aangemaakt. Beide kunnen verloren gaan (cookies gewist, netwerkwijzigingen). De owner-token is het voorkeursbewijs voor de toekomst.
Eigenaars-token
Elk endpoint dat een resource aanmaakt (/upload/init multipart, /upload/confirm, /file/reserve, /collection) retourneert een owner_token in zijn antwoord. De token is een ondertekend bewijs van eigendom dat gekoppeld is aan die specifieke resource, onafhankelijk van je IP of bezoeker-token.
Bewaar de token samen met de resource-ID en stuur deze bij elke mutatie als:
Authorization: Owner <token>Of, als je al Authorization: Bearer gebruikt voor een geauthenticeerde sessie, stuur het dan als:
X-Owner-Token: <token>De server accepteert het owner-token als geldig bewijs van eigenaarschap naast de legacy visitor token + IP-fallback. Clients die het token hebben blijven werken na het wisselen van netwerk of het wissen van cookies, en clients die het token niet hebben werken nog steeds precies zoals voorheen.
Tokens bestaan zolang de resource bestaat, zijn veilig om op te slaan en verlopen niet onafhankelijk. Een verloren token betekent dat je de controle over die resource (bestand/collectie/upload) verliest — behandel ze als lokale wachtwoorden.
Fouten
Fouten volgen een consistent patroon:
{
"success": false,
"error": "Human-readable message"
}Veelvoorkomende HTTP-statuscodes:
| Code | Betekenis |
|---|---|
200 | OK. |
201 | Aangemaakt. |
400 | Slecht verzoek (bijv. limiet voor collectiegrootte overschreden). |
401 | Wachtwoord vereist of onjuist. |
403 | Niet geautoriseerd (niet de eigenaar van de resource). |
404 | Resource niet gevonden of verlopen. |
422 | Validatie mislukt, of beperking door abonnement/quota. |
429 | Snelheidslimiet bereikt of uploadquota overschreden. |
500 | Serverfout. Controleer status. |
Snelheidslimieten
Alle snelheidslimieten zijn per IP. Een 429-antwoord bevat de standaard Retry-After-, X-RateLimit-Limit- en X-RateLimit-Remaining-headers.
| Bereik | Limiet |
|---|---|
| Upload initialiseren / bevestigen / afbreken | 60 / minuut |
| Multipart voltooiing | 500 / minuut |
| Multipart part-URL's | 120 / minuut |
| Batch initialiseren / bevestigen | 500 / minuut |
| Status-polls (bestand & collectie) | 120 / minuut |
| Instellingen (wachtwoord, vervaldatum, max-downloads) | 30 / minuut |
| Wachtwoordverificatie | 10 / minuut |
| Collectie aanmaken | 30 / minuut |
| Beheren (klaarzetten, verwijderen) | 60 / minuut |
| Thumbnail uploaden | 120 / minuut |
| ShareX uploaden | 20 / dag |
| App-analytics / fouten | 120 en 60 / minuut |
Uploadquota: anonieme clients hebben twee limieten tegelijk actief — 100 GB / 24 u per visitor token en 500 GB / 24 u per IP (de IP-limiet vangt verkeer zonder token en gedeelde netwerken). Zodra één van beide wordt overschreden krijg je een 429 met details. Dit is alleen een upload-quota — downloads zijn onbeperkt en niet beperkt (geleverd via R2 signed URLs).
Upload
De uploadflow in drie stappen voor elk bestand, inclusief bestanden groter dan 5 GB (automatisch multipart). Als je alleen een snelle upload in screenshot-stijl nodig hebt, kijk dan in plaats daarvan naar ShareX.
/upload/init60/minStart een upload. Voor bestanden >50 MB is het antwoord een multipart-upload (type: "multipart"-veld); anders een enkele presigned PUT.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
filename | string · required | Originele bestandsnaam. Maximaal 255 tekens. |
content_type | string · required | MIME-type. |
size | integer · required | Bestandsgrootte in bytes. Minimaal 1. |
/upload/partsOwner only120/minVraag extra URL's op voor een multipart-upload die nog bezig is. Wordt gebruikt wanneer /init minder URL's teruggeeft dan je hebt (of wanneer ze zijn verlopen).
Request body
| Veld | Type | Beschrijving |
|---|---|---|
upload_id | string · required | De upload_id uit /init. |
part_numbers | array<int> · required | Partijnummers waarvoor je URL's wilt ophalen. |
/upload/complete-multipartOwner only500/minRond een multipart-upload op R2 af zodra alle delen zijn geüpload.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
upload_id | string · required | De upload_id uit /init. |
parts | array · required | Elke entry: { partNumber, etag } uit de R2-respons. |
/upload/abortOwner only60/minAnnuleer een multipart-upload en ruim eventuele gedeeltelijke data op op R2.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
upload_id | string · required | De upload die moet worden afgebroken. |
/upload/confirm60/minBevestig dat de upload is voltooid. Dit is wanneer we het File-record aanmaken en de deelbare URL teruggeven.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
filename | string · required | Originele bestandsnaam. |
size | integer · required | Bestandsgrootte in bytes. |
content_type | string · required | MIME-type. |
r2_key | string · required | De r2_key uit /init. |
collection_id | string · optional | Koppel aan een collectie. |
crc32 | integer · optional | CRC32-checksum voor integriteitscontrole. |
file_id | string(9) · optional | Voldoe een eerder gereserveerd file-ID. |
/file/reserve60/minReserveer een file-ID en deelbare URL voor de bytes klaar zijn. Handig wanneer je eerst een link wilt doorgeven en de upload daarna wilt afronden. Eigendom is gekoppeld aan je visitor-token + IP. Rond de upload later af met /upload/init + /upload/confirm en geef file_id door om te bevestigen.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
filename | string · optional | Placeholder-bestandsnaam. Standaard: "Pending". |
content_type | string · optional | Placeholder MIME-type. |
/upload/init-batch500/minBatch-equivalent van /upload/init, geoptimaliseerd voor de web-uploader. Start tot 250 bestanden in één round-trip.
Wordt intern gebruikt door de web-uploader. De meeste clients moeten de voorkeur geven aan single-file /upload/init.
/upload/confirm-batch500/minBatch-equivalent van /upload/confirm. Bevestigt veel bestanden in één round-trip.
Collecties
Een collectie groepeert meerdere bestanden onder één deelbare URL (/c/{id}). Tot 10.000 bestanden en 25 GB totaal.
/collection30/minMaak een nieuwe collectie. Koppel bestanden achteraf door collection_id door te geven op /upload/confirm.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
expected_file_count | integer · optional | Tip voor automatisch markeren van de collectie als klaar zodra alle verwachte bestanden zijn bevestigd. |
/collection/{id}/status120/minControleer de status van een collectie. Markeert de collectie ook automatisch als klaar als alle verwachte bestanden zijn bevestigd.
/collection/{id}/readyOwner only60/minMarkeer de collectie als klaar om te downloaden. Meestal niet nodig — collecties worden automatisch klaar zodra expected_file_count is bereikt.
/collection/{id}Owner only60/minVerwijder een collectie en al haar bestanden.
/collection/{id}/passwordOwner only30/minStel een wachtwoord in voor de collectie. Vereist 4–100 tekens.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
password | string · required | 4–100 tekens. |
/collection/{id}/passwordOwner only30/minVerwijder het wachtwoord uit een collectie.
/collection/{id}/verify-password10/minControleer een wachtwoord. Geeft 200 terug bij succes, 401 bij een onjuist wachtwoord.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
password | string · required |
/collection/{id}/expiryOwner only30/minWijzig de vervaldatum van een collectie.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
days | integer · optional | 1–7 dagen vanaf nu. Laat weg of gebruik null voor permanent (alleen premium). |
/collection/{id}/max-downloadsOwner only30/minStel een downloadlimiet in (burn-after-N-downloads). De collectie wordt automatisch verwijderd zodra de limiet is bereikt.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
max_downloads | integer · optional | 1–1000. Moet hoger zijn dan het huidige aantal downloads. null om de limiet te verwijderen. |
Bestanden
Alle instellingen op bestandsniveau (wachtwoord, vervaldatum, max-downloads) spiegelen de collectie-endpoints. Alleen voor de eigenaar.
/file/{id}/status120/minControleer of een bestand nog wacht op de upload.
/file/{id}Owner only60/minVerwijder een bestand direct.
/file/{id}/thumbnailOwner only120/minUpload een thumbnail-afbeelding voor een video- of afbeeldingsbestand (wordt gebruikt op de downloadpagina). Max 2 MB.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
thumbnail | image · required | Multipart-upload. Max 2 MB. |
/file/{id}/passwordOwner only30/minStel een wachtwoord in voor een bestand. Vereist 4–100 tekens.
/file/{id}/passwordOwner only30/minVerwijder het wachtwoord van een bestand.
/file/{id}/verify-password10/minControleer het wachtwoord van een bestand.
/file/{id}/expiryOwner only30/minWijzig de vervaldatum van een bestand.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
days | integer · optional | 1–7 dagen vanaf nu. Laat weg of gebruik null voor permanent (alleen premium). |
/file/{id}/max-downloadsOwner only30/minBeperk het totale aantal downloads van een bestand. Wordt automatisch verwijderd zodra de limiet is bereikt.
ShareX uploaden
One-shot upload-endpoint — stuur een multipart-bestand en je krijgt een deelbare URL terug. Geen gedoe met init/confirm. Ideaal voor screenshot-tools. Volledige setup-gids op /docs/sharex.
Desktop-authenticatie
Voor geauthenticeerde clients (bijv. de desktopapp) met een Sanctum-token.
/userBearer tokenGeef de geauthenticeerde gebruiker terug.
/auth/logoutBearer tokenIntrek het huidige toegangstoken.
Overig
/healthLiveness-check. Geeft 200 met { "status": "ok" } terug wanneer de API-worker draait.
/activityLive activiteitenstream voor de homepageglobe. Gecachet op de Cloudflare-edge.
/bandwidth/status60/minHuidig upload-quota-gebruik voor de aanroeper — gebruikt door de CLI en desktop-app om de resterende capaciteit te tonen. Het response-formaat verschilt voor geauthenticeerde gebruikers. Ondanks de naam van de URL houdt dit alleen upload bytes bij; downloads worden niet meegerekend.
/app-analytics120/minVerstuur een gebruiksgebeurtenis vanuit de CLI of desktopapp.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
app | string · required | desktop, cli of web. |
version | string · optional | Clientversie. |
event | string · required | Gebeurtenisnaam, bijvoorbeeld upload_complete. |
context | object · optional | Extra metadata. |
/app-errors60/minDien een foutmelding in via de CLI of desktop-app. Server-side gededupliceerd — maximaal 10 van dezelfde fout per uur.
Request body
| Veld | Type | Beschrijving |
|---|---|---|
app | string · required | desktop, cli of web. |
type | string · required | Foutklasse/type. |
message | string · required | Foutmelding. |
stack | string · optional | Stack trace. |
version, os, os_version, arch, context | various · optional | Diagnostische metadata. |