API Documentation
Everything you need to convert files programmatically with the FileSwitch API.
Every example below uses Authorization: Bearer fc_YOUR_API_KEY and follows the selected language everywhere on this page.
Getting Started
A single REST API to convert HTML, images, JSON, and XML files.
The FileSwitch API converts files between supported formats. Upload a file as multipart/form-data, and the API returns a Conversion object with a temporary download URL. Every request goes to a versioned base URL:
https://api.fileswitch.co/api/v1Two kinds of credentials can authenticate requests: API keys for programmatic access to the conversion API and JWT access tokens for account endpoints (login, billing, history, API key management). API keys are available on paid plans and inherit the same rate limits, concurrency, and credit rules as your account.
Quick start
- Create a free account and upgrade to a paid plan.
- Create an API key in the Integrations tab.
- Make your first conversion:
curl -X POST https://api.fileswitch.co/api/v1/converter/html-to-pdf \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@report.html"Authentication
API keys for programmatic access, JWT access tokens for account endpoints.
API keys
The recommended way to authenticate server-side conversions. Keys start with fc_ and are sent as a Bearer token:
Authorization: Bearer fc_ab12cd34ef56...- Creating API keys requires a paid plan (Starter, Pro, or Scale).
- The full key is shown only once at creation; it is stored as a one-way hash.
- Revoking a key immediately invalidates it.
- Keys are scoped to your account and cannot be used to access other accounts' data.
- Requests authenticated with an API key are subject to your plan's rate limits, concurrent job limit, and credit costs — identical to using the web app.
JWT access tokens
Registering or logging in returns an accessToken and a refreshToken. Send the access token as a Bearer token on every authenticated request:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...- Get a token pair via
POST /auth/loginwith your email and password (or register viaPOST /auth/register). - Access tokens expire after 15 minutes.
- When the access token expires (HTTP 401), exchange the refresh token via
POST /auth/refreshfor a new pair. - Refresh tokens are single-use, expire after 7 days, and are revoked on logout.
Which endpoints need what
- Public:
/converter/formats, guest quota, and auth routes. - Either JWT or API key: conversion endpoints (guests may omit auth entirely), and file downloads.
- JWT required: conversion history, stats, and API key management.
Content Types & Conventions
How requests are encoded and how responses are shaped.
JSON bodies use application/json. File uploads use multipart/form-data with a single file field plus optional option fields. File downloads are returned as raw binary with a Content-Type matching the output format.
Success envelope
{
"success": true,
"message": "Conversion completed",
"data": { ... }
}Paginated endpoints add a meta object with page, limit, total, and totalPages.
Error envelope
{
"success": false,
"message": "File size exceeds the 10MB limit",
"error": "FILE_TOO_LARGE",
"details": { ... }
}Every error returns a machine-readable error code. See the Response Codes reference for the full list. When a request is rate-limited, the response includes a Retry-After header (in seconds).
Conversions
Upload a file, get a converted file back with a download URL.
Each conversion has its own endpoint (POST /converter/:slug) so it can accept conversion-specific options alongside the file — for example header and footer text on an HTML-to-PDF job. Upload a single file plus any option fields; every option is optional and defaults when omitted.
curl -X POST https://api.fileswitch.co/api/v1/converter/html-to-pdf \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.html" \
-F "pageSize=A4" \
-F "printBackground=true" \
-F "marginTop=20px" \
-F "marginRight=20px" \
-F "marginBottom=20px" \
-F "marginLeft=20px"Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /converter/:slug | Optional | Convert a file using a dedicated endpoint per conversion (e.g. /converter/html-to-pdf). Accepts conversion-specific options. |
| POST | /converter/convert | Optional | Legacy generic convert endpoint (multipart upload with inputFormat/outputFormat fields). |
| GET | /converter/formats | Public | List all supported conversions and their metadata (includes the endpoint slug). |
| GET | /converter/conversions | JWT | List the authenticated user's conversion history (paginated). |
| GET | /converter/conversions/:id | JWT | Fetch a single conversion by id (owner only). |
| GET | /converter/stats | JWT | Aggregate usage statistics for the authenticated user. |
| GET | /converter/guest/quota | Public | Check the guest conversion quota for the current IP. |
| GET | /converter/download/:key | Optional | Download a converted file by its storage key. |
Guests vs. authenticated requests
/converter/:slugaccepts optional authentication. Unauthenticated (guest) requests are limited by IP: 1 request per 10-second window and 2 conversions per day, each file up to 5 MB. Requests made with an API key or JWT deduct credits from the account balance and follow the plan's rate limits, concurrency, and file size limits.
Conversion endpoints & schemas
One endpoint per conversion. Click through to the endpoint details for the input option schema and a request example. Every endpoint returns the same Conversion response schema.
/converter/html-to-pdfHTML to PDF
html, htm pdf
/converter/html-to-imageHTML to Image
html, htm png
/converter/html-to-markdownHTML to Markdown
html, htm md
/converter/webp-to-pngWebP to PNG
webp png
/converter/png-to-webpPNG to WebP
png webp
/converter/webp-to-jpgWebP to JPG
webp jpg, jpeg
/converter/json-to-csvJSON to CSV
json csv
/converter/json-to-xmlJSON to XML
json xml
/converter/xml-to-jsonXML to JSON
xml json
Input
html, htm
Output
pdf (application/pdf)
Max file
25 MB
Credit cost
2
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| pageSize | string | A4 | A4, A3, A5, Letter, Legal, Tabloid | Output page size. |
| landscape | boolean | false | true | false | Render the page in landscape orientation. |
| printBackground | boolean | true | true | false | Print the CSS background graphics. |
| marginTop | string | 20px | Any CSS length | Top margin as a CSS length (e.g. 20px, 12mm). |
| marginRight | string | 20px | Any CSS length | Right margin as a CSS length. |
| marginBottom | string | 20px | Any CSS length | Bottom margin as a CSS length. |
| marginLeft | string | 20px | Any CSS length | Left margin as a CSS length. |
| headerText | string | — | Any string (≤ 500 chars) | Repeated on every page header (up to 500 chars). |
| footerText | string | — | Any string (≤ 500 chars) | Repeated on every page footer (up to 500 chars). |
curl -X POST https://api.fileswitch.co/api/v1/converter/html-to-pdf \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.html" \
-F "pageSize=A4" \
-F "printBackground=true" \
-F "marginTop=20px" \
-F "marginRight=20px" \
-F "marginBottom=20px" \
-F "marginLeft=20px"Returns the standard Conversion response envelope.
Input
html, htm
Output
png (image/png)
Max file
25 MB
Credit cost
2
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| width | number | 1280 | 320 – 4096 | Viewport width in pixels. |
| height | number | 800 | 240 – 4096 | Viewport height in pixels. |
| fullPage | boolean | true | true | false | Capture the full scrollable page height. |
curl -X POST https://api.fileswitch.co/api/v1/converter/html-to-image \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.html" \
-F "width=1280" \
-F "height=800" \
-F "fullPage=true"Returns the standard Conversion response envelope.
Input
html, htm
Output
md (text/markdown)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| headingStyle | string | atx | atx | setext | Markdown heading syntax (## vs underline). |
| codeBlockStyle | string | fenced | fenced | indented | Code block syntax. |
| bulletListMarker | string | - | - | + | * | Character used for unordered lists. |
curl -X POST https://api.fileswitch.co/api/v1/converter/html-to-markdown \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.html" \
-F "headingStyle=atx" \
-F "codeBlockStyle=fenced" \
-F "bulletListMarker=-"Returns the standard Conversion response envelope.
Input
webp
Output
png (image/png)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| compressionLevel | number | 6 | 0 – 9 | PNG zlib compression level. |
curl -X POST https://api.fileswitch.co/api/v1/converter/webp-to-png \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.webp" \
-F "compressionLevel=6"Returns the standard Conversion response envelope.
Input
png
Output
webp (image/webp)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| quality | number | 90 | 1 – 100 | Lossy compression quality. |
curl -X POST https://api.fileswitch.co/api/v1/converter/png-to-webp \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.png" \
-F "quality=90"Returns the standard Conversion response envelope.
Input
webp
Output
jpg, jpeg (image/jpeg)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| quality | number | 90 | 1 – 100 | JPEG compression quality. |
curl -X POST https://api.fileswitch.co/api/v1/converter/webp-to-jpg \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.webp" \
-F "quality=90"Returns the standard Conversion response envelope.
Input
json
Output
csv (text/csv)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| delimiter | string | , | Any single character | Field separator. |
curl -X POST https://api.fileswitch.co/api/v1/converter/json-to-csv \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.json" \
-F "delimiter=,"Returns the standard Conversion response envelope.
Input
json
Output
xml (application/xml)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| rootElement | string | root | XML element name | Name of the XML root element. |
| prettyPrint | boolean | true | true | false | Indent the output XML. |
curl -X POST https://api.fileswitch.co/api/v1/converter/json-to-xml \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.json" \
-F "rootElement=root" \
-F "prettyPrint=true"Returns the standard Conversion response envelope.
Input
xml
Output
json (application/json)
Max file
25 MB
Credit cost
1
Input options (multipart form fields, all optional)
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
| prettyPrint | boolean | true | true | false | Pretty-print the output JSON. |
curl -X POST https://api.fileswitch.co/api/v1/converter/xml-to-json \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@input.xml" \
-F "prettyPrint=true"Returns the standard Conversion response envelope.
Response Schema
The standard Conversion object returned by every conversion endpoint.
On success, every conversion endpoint returns the same envelope: success, message, and data — a Conversion object. The outputFormat, outputFileName, and outputMime vary per conversion:
{
"success": true,
"message": "Conversion completed",
"data": {
"id": "b10a5f2e-8c1e-4b3a-9c1d-2e3f4a5b6c7d",
"userId": "4b006abd-e7a3-48e5-a29c-d14d28465b57",
"inputFormat": "html",
"outputFormat": "pdf",
"inputFileName": "document.html",
"outputFileName": "document.pdf",
"inputFileSize": 45210,
"outputFileSize": 88431,
"status": "completed",
"error": null,
"creditCost": 2,
"filesCleanedAt": null,
"createdAt": "2026-07-31T13:00:00.000Z",
"completedAt": "2026-07-31T13:00:02.000Z",
"downloadUrl": "/api/v1/converter/download/conversions%2Fb10a5f2e-8c1e-4b3a-9c1d-2e3f4a5b6c7d%2Foutput.pdf"
}
}| Field | Type | Description |
|---|---|---|
| id | string | Unique conversion identifier (UUID). |
| userId | string | null | Owning account id; null for guest conversions. |
| inputFormat | string | Detected input format of the uploaded file. |
| outputFormat | string | Format produced by this conversion. |
| inputFileName | string | Original filename of the uploaded file. |
| outputFileName | string | null | Filename of the converted output. |
| inputFileSize | number | Upload size in bytes. |
| outputFileSize | number | null | Converted output size in bytes. |
| status | string | Lifecycle state: pending, processing, completed, or failed. |
| error | string | null | Error message when the conversion failed. |
| creditCost | number | null | Credits charged for this conversion. |
| filesCleanedAt | string | null | When the stored output was auto-deleted. |
| createdAt | string | ISO 8601 timestamp when the conversion was created. |
| completedAt | string | null | ISO 8601 timestamp when the conversion finished. |
| downloadUrl | string | null | Relative URL to download the output; present while the output is stored. |
Downloading the output
The downloadUrl is relative to the API host. Prepend https://api.fileswitch.co to download the file with the same API key (or the owning account's JWT). Files are retained temporarily and auto-deleted, so download outputs promptly:
curl https://api.fileswitch.co/api/v1/converter/download/conversions%2Fb10a5f2e-8c1e-4b3a-9c1d-2e3f4a5b6c7d%2Foutput.pdf \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
--output document.pdfRate Limits & Credits
How usage is governed per plan and per guest.
Plans
| Plan | Monthly credits | Max file | Rate limit (req/s) | Concurrent jobs | API keys |
|---|---|---|---|---|---|
| Free | 200 | 10 MB | 2 | 1 | 0 |
| Starter | 1000 | 25 MB | 5 | 2 | 2 |
| Pro | 4500 | 100 MB | 15 | 5 | 5 |
| Scale | 15000 | 500 MB | 30 | 15 | 10 |
The effective upload limit is the lower of your plan's max file size and the converter's own limit (currently 25 MB for every supported conversion). Guests are capped at 5 MB.
Rate limiting
- A global rate limit applies to all requests: 100 requests per 15-minute window per IP.
- The conversion endpoint uses a stricter, per-account limiter: your plan's
rateLimitRPSsustained over a rolling window. - Guests get 1 conversion request per 10-second window plus a daily quota.
- Excess traffic returns HTTP 429 with
Retry-After.
Guest quota
Without signing in you can convert up to 2 files per day (per IP), each up to 5 MB. The GET /converter/guest/quota endpoint reports how many conversions remain.
Credit costs
Conversions consume credits from your account. The base cost depends on the conversion type — heavy browser-based jobs cost more:
| Conversion | Base cost |
|---|---|
| html → pdf, html → png | 2 credits |
| html → md, webp → png, png → webp, webp → jpg, json → csv, json → xml, xml → json | 1 credit |
File size adds a multiplier: files ≤ 25 MB cost 1×, files 25–100 MB cost 2×, and files over 100 MB cost 3×. Total cost = base cost × multiplier. Insufficient credits returns HTTP 402. Failed conversions are automatically refunded.
Response Codes
HTTP status codes and machine-readable error identifiers.
HTTP status codes
| Code | Name | Description |
|---|---|---|
| 200 | OK | Request succeeded. The response body contains the data envelope. |
| 201 | Created | A resource was created (account, API key, or conversion record). |
| 400 | Bad Request | Malformed request, invalid body fields, missing file, or validation failure. |
| 401 | Unauthorized | Missing, invalid, or expired credentials. |
| 402 | Payment Required | The account does not have enough credits for the conversion. |
| 403 | Forbidden | Authenticated but not allowed (e.g. API keys require a paid plan, guest quota exceeded). |
| 404 | Not Found | Route, resource, or file does not exist or is not owned by you. |
| 413 | Payload Too Large | The uploaded file exceeds the allowed size for your plan or the converter. |
| 422 | Unprocessable Entity | The requested input-to-output conversion is not supported, or the uploaded file's format does not match this conversion endpoint. |
| 429 | Too Many Requests | Rate limit exceeded. The Retry-After header indicates when to retry. |
| 500 | Internal Server Error | An unexpected server error occurred. Retry later or contact support. |
Error codes
| Code | Status | Description |
|---|---|---|
| VALIDATION_ERROR | 400 | Request body failed schema validation. Check the details field for the offending fields. |
| UNSUPPORTED_FILE_TYPE | 400 | The uploaded file's extension is not a recognized input format. |
| NO_FILE | 400 | The multipart upload contained no file. |
| UNEXPECTED_FILE | 400 | More than one file was uploaded to a single-file field. |
| UPLOAD_ERROR | 400 | The multipart upload failed for an unknown reason. |
| INVALID_FILE_KEY | 400 | The download key is not a valid storage key. |
| UNAUTHORIZED | 401 | No token provided, or the token could not be verified. |
| API_KEYS_REQUIRE_PAID_PLAN | 403 | API keys are a paid feature; the account is on a plan without API access. |
| GUEST_QUOTA_EXCEEDED | 403 | Guest daily conversion quota reached. Sign in to continue. |
| ACCESS_DENIED | 403 | The resource belongs to another account. |
| PAYMENT_REQUIRED | 402 | Insufficient credits for the conversion. Top up or upgrade. |
| FILE_TOO_LARGE | 413 | File exceeds the plan or converter size limit. |
| GUEST_FILE_TOO_LARGE | 413 | File exceeds the guest 5MB limit; sign in to upload larger files. |
| UNSUPPORTED_FORMAT | 422 | The input-to-output conversion is not supported, or the file's format does not match the conversion endpoint. |
| UNKNOWN_CONVERSION | 404 | The conversion endpoint slug does not exist (e.g. POST /converter/nope). |
| API_KEY_LIMIT_REACHED | 403 | The plan's API key allowance is exhausted; revoke a key or upgrade. |
| NOT_FOUND | 404 | Resource does not exist or is not visible to the caller. |
| TOO_MANY_REQUESTS | 429 | Rate limit exceeded. |
| INTERNAL_ERROR | 500 | Unexpected server error. |
OpenAPI Schema
Pull the complete API contract into your toolchain.
The API publishes its full contract as an OpenAPI 3.0.3 document at GET /api/v1/openapi.json. It declares every endpoint — including all nine per-conversion routes — plus authentication, request bodies, and response schemas. Each conversion's input schema is published as a named component (e.g. HtmlToPdfInput), so clients can validate form fields and generate typed SDKs at build time.
curl https://api.fileswitch.co/api/v1/openapi.json > openapi.jsonUsing the schema
- Open the spec in Swagger Editor for an interactive, browsable reference.
- Import the URL into Postman (File → Import → Link) to generate a collection with every endpoint preconfigured.
- Import into Insomnia (Create → Import → URL) the same way.
- Generate typed clients with
openapi-generatororopenapi-typescriptfrom the same URL.
A conversion endpoint is declared with a multipart/form-data request body: a required filefield plus the option properties from the conversion's input schema:
"/converter/html-to-pdf": {
"post": {
"operationId": "convertHtmlToPdf",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"required": ["file"],
"properties": {
"file": { "type": "string", "format": "binary" },
"pageSize": { "type": "string", "enum": ["A4", "A3", "A5", "Letter", "Legal", "Tabloid"], "default": "A4" },
"headerText": { "type": "string", "default": "" },
"footerText": { "type": "string", "default": "" }
}
}
}
}
}
}
}API Keys
Create, list, and revoke API keys programmatically.
Create a key
curl -X POST https://api.fileswitch.co/api/v1/integrations/api-keys \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "ci-server", "expiresInDays": 90}'Response (201) — the full key is shown exactly once:
{
"success": true,
"data": {
"id": "c47afec6-083c-4228-a108-2271ce598dff",
"name": "ci-server",
"keyPrefix": "fc_ab12cd34",
"lastFour": "5678",
"lastUsedAt": null,
"expiresAt": "2026-10-29T13:00:00.000Z",
"revokedAt": null,
"createdAt": "2026-07-31T13:00:00.000Z",
"fullKey": "fc_ab12cd34..."
}
}nameis required (1–100 characters).expiresInDaysis optional (1–365); omit it for a non-expiring key.- Returns HTTP 403 with code
API_KEYS_REQUIRE_PAID_PLANon a free plan. - Returns HTTP 403 with code
API_KEY_LIMIT_REACHEDwhen the plan allowance is exhausted.
Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /integrations/api-keys | JWT | List API keys for the authenticated user. |
| POST | /integrations/api-keys | JWT | Create an API key (paid plans only). |
| POST | /integrations/api-keys/:id/revoke | JWT | Permanently revoke an API key. |
Keys are scoped to the authenticated user; attempting to revoke another user's key returns 404.
SDKs & Code Examples
Convert a file and download the result in the language of your choice.
The examples below show a full convert-and-download flow in the language selected by the switcher at the top of this page.
# 1. Convert with options
curl -X POST https://api.fileswitch.co/api/v1/converter/html-to-pdf \
-H "Authorization: Bearer fc_YOUR_API_KEY" \
-F "file=@report.html" \
-F "pageSize=A4" \
-F "headerText=Quarterly Report" \
-F "footerText=Confidential" > response.json
# 2. Download the converted file using the returned downloadUrl
URL=$(node -e "console.log(JSON.parse(require('fs').readFileSync('response.json')).data.downloadUrl)")
curl https://api.fileswitch.co$URL -H "Authorization: Bearer fc_YOUR_API_KEY" \
--output report.pdfHandling errors & rate limits
import time, requests
headers = {"Authorization": "Bearer fc_YOUR_API_KEY"}
for attempt in range(3):
res = requests.post(
"https://api.fileswitch.co/api/v1/converter/json-to-csv",
headers=headers,
files={"file": open("data.json", "rb")},
data={"delimiter": ";"},
)
if res.status_code == 429:
retry_after = int(res.headers.get("Retry-After", 5))
time.sleep(retry_after)
continue
res.raise_for_status()
break
# 402 -> insufficient credits, 413 -> file too large, 422 -> unsupported input for this endpointBest Practices & Security
Keep your integration fast, safe, and reliable.
- Store API keys securely. Keep them in environment variables or a secret manager, never in client-side code or repositories. The full key is only shown once.
- Download outputs promptly. Converted files are retained temporarily and cleaned up automatically.
- Respect rate limits. Honor HTTP 429 and the
Retry-Afterheader with exponential backoff. - Watch your credit balance. Poll
GET /credits/balanceand handle HTTP 402 gracefully by prompting for a top-up or upgrade. - Rotate keys. Revoke a key and create a new one if it is ever exposed or when a service is decommissioned.
- Set key expiries. Use
expiresInDaysfor temporary or CI credentials so they cannot outlive their purpose. - Pagination. History and transactions default to page size 20 (max 50). Use the
metaresponse to page through results.
Security & compliance
- All traffic is encrypted in transit (HTTPS).
- Uploaded and converted files are auto-deleted after a short retention period.
- API keys are stored as one-way hashes — the plaintext is never recoverable.
- Conversions are scoped to your account and cannot be read by other accounts.
Need help? Contact support or check the plans to pick the right tier for your usage.