# Fileinbox API Fileinbox has an API that allows you to programmatically manage your upload pages, view submissions, and download files. **→ [Get an API token](/settings/api_tokens) to start using the API.** ## Table of Contents - [Authentication](#authentication) - [Error Responses](#error-responses) - [Pagination](#pagination) - [Pages](#pages) - [Responses](#responses-submissions) - [Files](#files) - [Public Submissions](#public-submissions) --- ## Authentication To use the API you'll need an access token. Go to your [API Tokens](/settings/api_tokens) page and click **"Generate new token"**. Permission levels: - **Read** — List pages, view responses, download files - **Read + Write** — All read permissions plus create/update/delete pages and responses Include your token in the `Authorization` header: ```bash curl -H "Authorization: Bearer fi_xxxxx" \ https://fileinbox.com/api/v1/ping ``` ```json { "status": "ok", "user_id": 42 } ``` > **Keep your token secret.** Anyone with your token can access your account's data. ## Error Responses | Status | Description | |--------|-------------| | 401 | Missing or invalid token | | 403 | Token doesn't have required permission | | 404 | Resource not found | | 422 | Validation error (includes `details` object with per-field errors) | | 429 | Rate limit exceeded (100 requests/minute) | ```json { "error": { "code": "validation_failed", "message": "Slug has already been taken", "details": { "slug": ["has already been taken"] } } } ``` ## Pagination List endpoints return paginated results. Use `page` and `per_page` query parameters. `per_page` defaults to 25 (max 100). ```json { "data": [...], "meta": { "page": 1, "per_page": 25, "total": 42 } } ``` --- ## Pages ### Get a Page ``` GET /api/v1/pages/:slug ``` **Permission:** Read ```bash curl -H "Authorization: Bearer fi_xxxxx" \ https://fileinbox.com/api/v1/pages/photos ``` ```json { "data": { "id": 1, "slug": "photos", "title": "Upload Photos", "created_at": "2025-01-15T10:30:00Z", "updated_at": "2025-01-15T10:30:00Z", "url": "https://fileinbox.com/photos", "responses_count": 12, "questions": [ { "id": "q1", "type": "text", "title": "Your Name", "required": true } ], "branding": {}, "access_code_enabled": false, "api_submissions_enabled": false } } ``` ### List Pages ``` GET /api/v1/pages ``` **Permission:** Read Returns a paginated array of page objects. Supports `page` and `per_page` query parameters. ```bash curl -H "Authorization: Bearer fi_xxxxx" \ https://fileinbox.com/api/v1/pages ``` ### Create a Page ``` POST /api/v1/pages ``` **Permission:** Read + Write | Field | Type | Required | Description | |----------------------------------|---------|----------|--------------------------------------------| | `page[slug]` | string | yes | URL slug (unique, letters/numbers/hyphens) | | `page[title]` | string | no | Page title shown to uploaders | | `page[access_code]` | string | no | Require this code to access the page | | `page[api_submissions_enabled]` | boolean | no | Allow unauthenticated API submissions | | `page[branding]` | object | no | Branding settings | | `page[new_questions]` | array | no | Form questions (see below) | Each question in `new_questions`: | Field | Type | Description | |---------------|---------|----------------------------------------------------| | `id` | string | Unique identifier for the question | | `type` | string | `text`, `textarea`, `email`, `select`, `files` | | `title` | string | Question label shown to uploaders | | `required` | boolean | Whether an answer is required | | `placeholder` | string | Placeholder text | | `help` | string | Help text | | `settings` | object | Type-specific settings | ```bash curl -X POST \ -H "Authorization: Bearer fi_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "page": { "slug": "photos", "title": "Upload Photos", "new_questions": [ { "id": "q1", "type": "text", "title": "Your Name", "required": true } ] } }' \ https://fileinbox.com/api/v1/pages ``` **Response:** `201 Created` with the page object. ### Update a Page ``` PATCH /api/v1/pages/:slug ``` **Permission:** Read + Write. Only include the fields you want to change. ```bash curl -X PATCH \ -H "Authorization: Bearer fi_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "page": { "title": "Upload Wedding Photos" } }' \ https://fileinbox.com/api/v1/pages/photos ``` **Response:** `200 OK` with the updated page object. ### Delete a Page ``` DELETE /api/v1/pages/:slug ``` **Permission:** Read + Write ```bash curl -X DELETE \ -H "Authorization: Bearer fi_xxxxx" \ https://fileinbox.com/api/v1/pages/photos ``` **Response:** `204 No Content` --- ## Responses (Submissions) Responses are submissions that people make to your upload pages. Each response can contain form answers and uploaded files. ### Get a Response ``` GET /api/v1/pages/:slug/responses/:id ``` **Permission:** Read ```bash curl -H "Authorization: Bearer fi_xxxxx" \ https://fileinbox.com/api/v1/pages/photos/responses/1 ``` ```json { "data": { "id": 1, "created_at": "2025-01-16T14:20:00Z", "answers": [ { "question_title": "Your Name", "question_type": "text", "value": "Jane Smith" } ], "ip": "192.168.1.1", "location": "Dallas, TX", "client": "Chrome on macOS", "files": [ { "id": 10, "filename": "photo.jpg", "content_type": "image/jpeg", "byte_size": 2048000, "download_url": "/api/v1/pages/photos/responses/1/files/10" } ] } } ``` > If a response's files are gated (free plan, older than 30 days), `download_url` is omitted and `"gated": true` is present instead. ### List Responses ``` GET /api/v1/pages/:slug/responses ``` **Permission:** Read Returns a paginated array of response objects. Supports `page`, `per_page`, and `since` (ISO 8601 timestamp) query parameters. ```bash curl -H "Authorization: Bearer fi_xxxxx" \ "https://fileinbox.com/api/v1/pages/photos/responses?since=2025-01-16T00:00:00Z" ``` ### Delete a Response ``` DELETE /api/v1/pages/:slug/responses/:id ``` **Permission:** Read + Write ```bash curl -X DELETE \ -H "Authorization: Bearer fi_xxxxx" \ https://fileinbox.com/api/v1/pages/photos/responses/1 ``` **Response:** `204 No Content` --- ## Files ### Download a File ``` GET /api/v1/pages/:slug/responses/:response_id/files/:id ``` **Permission:** Read Returns a 302 redirect to a signed download URL (expires in 5 minutes). Use `-L` to follow the redirect. ```bash curl -L -H "Authorization: Bearer fi_xxxxx" \ -o photo.jpg \ https://fileinbox.com/api/v1/pages/photos/responses/1/files/10 ``` --- ## Public Submissions These endpoints allow **unauthenticated** submissions to pages that have `api_submissions_enabled` set to `true`. No API token required. Enable via the page's Security settings or the API: ```bash curl -X PATCH \ -H "Authorization: Bearer fi_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "page": { "api_submissions_enabled": true } }' \ https://fileinbox.com/api/v1/pages/photos ``` ### Submit with Files (Multipart) ``` POST /api/v1/pages/:slug/submissions Content-Type: multipart/form-data ``` The simplest way to submit. Send answers and files in a single multipart request — the server handles file storage automatically. ```bash curl -X POST \ -F "answers[q_default_email]=jane@example.com" \ -F "files[q_default_files][]=@report.pdf" \ -F "files[q_default_files][]=@photo.jpg" \ -F "access_code=secret123" \ https://fileinbox.com/api/v1/pages/photos/submissions ``` **Response:** `201 Created` ```json { "data": { "id": 42, "created_at": "2025-01-15T10:30:00Z" } } ``` | Field | Type | Required | Description | |---------------|--------|----------|---------------------------------------------| | `answers` | object | yes | Map of question ID → answer value | | `files` | object | no | Map of file question ID → array of files | | `access_code` | string | no | Required if the page has an access code set | Use question IDs from the page's `questions` array as keys. Rate limit: 10 requests/minute per IP. ### Submit with JSON (Direct Upload) For large files or browser-based uploads, you can use the two-step direct upload flow instead. **Step 1:** Create upload URLs. ``` POST /api/v1/pages/:slug/uploads ``` ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{ "blobs": [{ "filename": "document.pdf", "byte_size": 1048576, "content_type": "application/pdf" }] }' \ https://fileinbox.com/api/v1/pages/photos/uploads ``` ```json { "data": [ { "signed_id": "eyJfcm...", "filename": "document.pdf", "direct_upload": { "url": "https://storage.example.com/...", "headers": { "Content-Type": "application/pdf" } } } ] } ``` Upload the file bytes with a PUT to `direct_upload.url` using the provided headers. Rate limit: 20 requests/minute per IP. **Step 2:** Submit with signed IDs. ``` POST /api/v1/pages/:slug/submissions Content-Type: application/json ``` ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{ "answers": { "q_default_email": "jane@example.com" }, "files": { "q_default_files": [ { "signed_id": "eyJfcm...", "name": "document.pdf" } ] } }' \ https://fileinbox.com/api/v1/pages/photos/submissions ``` **Error Responses:** | Status | Description | |--------|-------------------------------------------| | 403 | API submissions not enabled for this page | | 401 | Invalid access code | | 404 | Page not found | | 422 | Validation error (missing required fields)| | 429 | Rate limit exceeded | --- ## File Sharing Share files by uploading them and getting a download link. Recipients can download without signing up. ### Upload Flow File sharing uses a two-step presigned upload flow: 1. **Request presigned URLs** — tell the API what files you want to upload 2. **Upload directly to storage** — upload each file to the presigned URL 3. **Finalize the share** — create the share with the uploaded file references ### Step 1: Request Presigned Upload URLs ``` POST /api/v1/share_uploads Authorization: Token fi_xxxxx Content-Type: application/json ``` ```json { "blobs": [ { "filename": "report.pdf", "byte_size": 2097152, "checksum": "abc123base64==", "content_type": "application/pdf" } ] } ``` **Response:** ```json { "data": [ { "signed_id": "eyJfcm...", "filename": "report.pdf", "byte_size": 2097152, "content_type": "application/pdf", "direct_upload": { "url": "https://nyc3.digitaloceanspaces.com/...", "headers": { "Content-Type": "application/pdf", "Content-MD5": "abc123base64==" } } } ] } ``` ### Step 2: Upload Files Upload each file directly to the presigned URL using a `PUT` request with the provided headers. ```bash curl -X PUT \ -H "Content-Type: application/pdf" \ -H "Content-MD5: abc123base64==" \ --data-binary @report.pdf \ "https://nyc3.digitaloceanspaces.com/..." ``` ### Step 3: Create Share ``` POST /api/v1/shares Authorization: Token fi_xxxxx Content-Type: application/json ``` ```json { "signed_ids": ["eyJfcm..."], "title": "Q4 Report", "message": "See page 3 for the summary.", "to": ["sarah@example.com"], "password": "optional-password", "expires_in": "7d" } ``` **Response (201 Created):** ```json { "data": { "id": "k8m2x9p3", "url": "https://fileinbox.com/dl/k8m2x9p3", "title": "Q4 Report", "message": "See page 3 for the summary.", "files": [ { "name": "report.pdf", "size": 2097152, "content_type": "application/pdf" } ], "to": ["sarah@example.com"], "password_protected": false, "expires_at": "2026-03-19T16:17:42Z", "download_count": 0, "created_at": "2026-03-12T16:17:42Z" } } ``` ### List Shares ``` GET /api/v1/shares Authorization: Token fi_xxxxx ``` Supports pagination with `page` and `per_page` parameters. ### Get Share Details ``` GET /api/v1/shares/:code Authorization: Token fi_xxxxx ``` Returns share details with `_links` and `_actions` for hypermedia navigation. ### Update Share ``` PATCH /api/v1/shares/:code Authorization: Token fi_xxxxx (write permission required) Content-Type: application/json ``` ```json { "title": "Updated Title", "message": "Updated message" } ``` ### Delete Share ``` DELETE /api/v1/shares/:code Authorization: Token fi_xxxxx (write permission required) ``` Returns `204 No Content`. Soft-deletes the share. ### Error Responses | Status | Code | Description | |--------|------|-------------| | 402 | `share_limit_reached` | Free plan share limit (25) exceeded | | 422 | `file_too_large` | File exceeds plan size limit (100 MB free, 10 GB Pro) | | 422 | `no_files` | No files provided | | 422 | `invalid_signed_id` | Invalid file reference | | 403 | — | Read-only token used for write operation | | 404 | `not_found` | Share not found | | 429 | — | Rate limit exceeded | ### Free vs Pro Limits | | Free | Pro ($29/mo) | |---|---|---| | Lifetime sends | 25 | Unlimited | | Max file size | 100 MB | 10 GB | | File availability | 7 days | Forever (or custom) | | Custom expiry | No | Yes | | Password protection | Yes | Yes | ### Download Page Share download pages are publicly accessible at `https://fileinbox.com/dl/:code`. No authentication required to view or download files. The download page supports content negotiation: - `Accept: text/html` — Beautiful branded download page - `Accept: application/json` — JSON with file metadata and download URLs ### CLI ```bash npm install -g fileinbox fileinbox auth YOUR_API_KEY fileinbox send report.pdf --title "Q4 Report" --to sarah@example.com ```