API Documentation
The FileCourier API enables you to programmatically request documents from external users. When a request is processed, an email or SMS containing a unique secure upload link is sent to the recipient. Once files are uploaded, FileCourier delivers them to your application via webhook.
To get started, create a Project in your dashboard. Each project has a Client ID and Client Secret for API authentication.
Authentication
All API requests require authentication using HTTP Basic Auth. Use your Project's Client ID as the username and Client Secret as the password.
Getting Your Credentials
- Go to Projects in your dashboard
- Create a new project or select an existing one
- Copy your Client ID and Client Secret
Authorization Header
Combine your Client ID and Client Secret with a colon (:), then Base64 encode the string:
Authorization: Basic base64(client_id:client_secret)
Example
curl -X POST https://api.filecourier.io/api/ext/sessions \ -H "Content-Type: application/json" \ -u "fc_7fce16d7095f13f27cd6dbbdced3dc3c:fcs_0bebd9ebed980d243a176ef5eacdb22e86b10bcaed" \ -d '{ "recipient": { "email": "customer@example.com", "name": "John Doe" } }'
The -u flag in cURL automatically handles the Base64 encoding for Basic Auth.
Base URL
All API requests should be made to the following base URL:
https://api.filecourier.io
External API endpoints are prefixed with /api/ext/. For example:
POST /api/ext/sessions- Create a new upload sessionGET /api/ext/sessions/{sessionId}- Get session statusDELETE /api/ext/sessions/{sessionId}- Cancel a session
Create Session
Creates a new upload session and sends a notification (email and/or SMS) to the recipient with a secure upload link. The uploaded documents will be delivered to your application via the specified webhook URL.
Request Headers
| Name | Type | Description |
|---|---|---|
| Content-Type | string | Must be application/json |
| Authorization | string | REQUIRED Basic Auth with Client ID and Client SecretBasic base64(client_id:client_secret) |
Request Body
| Name | Type | Description |
|---|---|---|
| requestor_name | string | REQUIRED Name of the person or company requesting documents (shown to recipient) |
| requestor_email | string | REQUIRED Email address of the requestor (for reply-to) |
| recipient_email | string | REQUIRED Email address of the person who should upload documents |
| recipient_phone | string | OPTIONAL Phone number for SMS notification (format: +15551234567) |
| subject | string | REQUIRED Subject line for the email notification |
| message | string | REQUIRED Custom message shown to the recipient explaining what documents are needed |
| documents | array | OPTIONAL Array of document names/types being requested (e.g., ["ID Verification", "Proof of Address"]) |
| reference_id | string | OPTIONAL Your internal reference ID for this request (e.g., order number, customer ID) |
| callback_url | string | REQUIRED Webhook URL where uploaded files will be delivered |
| callback_api_key | string | OPTIONAL API key to include in Authorization header when calling your callback URL |
| expires_at | string | OPTIONAL ISO 8601 datetime when the upload link expires (default: 7 days) |
| brand_name | string | OPTIONAL Company name to display on the upload portal |
| brand_logo_url | string | OPTIONAL URL to your logo for the upload portal |
Example Request
curl --location --request POST 'https://api.filecourier.io/api/ext/sessions' \ --header 'Content-Type: application/json' \ -u 'your_client_id:your_client_secret' \ --data-raw '{ "recipient": { "email": "customer@example.com", "name": "John Doe" }, "documents": ["Government ID", "Proof of Address"], "message": "Please upload the following documents.", "webhook_url": "https://api.acmecorp.com/webhooks/filecourier", "expires_in_days": 7 }'
// Create Base64 encoded credentials const credentials = btoa('your_client_id:your_client_secret'); const response = await fetch('https://api.filecourier.io/api/ext/sessions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Basic ${credentials}` }, body: JSON.stringify({ recipient: { email: 'customer@example.com', name: 'John Doe' }, documents: ['Government ID', 'Proof of Address'], message: 'Please upload the following documents.', webhook_url: 'https://api.acmecorp.com/webhooks/filecourier' }) }); const data = await response.json();
Response
{
"status": true,
"message": "Request created successfully",
"data": {
"request_id": "req_abc123xyz",
"upload_url": "https://secure.filecourier.io/u/abc123xyz",
"expires_at": "2025-02-15T23:59:59Z",
"notification_sent": {
"email": true,
"sms": true
}
}
}
{
"status": false,
"error": "recipient_email is required"
}
{
"status": false,
"error": "Invalid API key"
}
Get Session Status
Retrieves the current status of an upload session, including whether files have been uploaded and delivered.
Path Parameters
| Name | Type | Description |
|---|---|---|
| sessionId | string | REQUIRED The session ID returned when creating the session |
Example Request
curl --location --request GET 'https://api.filecourier.io/api/ext/sessions/sess_abc123xyz' \ -u 'your_client_id:your_client_secret'
Response
{
"status": true,
"data": {
"request_id": "req_abc123xyz",
"reference_id": "CUST-12345",
"recipient_email": "[email protected]",
"status": "completed",
"created_at": "2025-01-22T10:30:00Z",
"expires_at": "2025-02-15T23:59:59Z",
"uploaded_at": "2025-01-22T14:22:15Z",
"delivered_at": "2025-01-22T14:22:18Z",
"files": [
{
"name": "drivers-license.pdf",
"size": 245832,
"type": "application/pdf"
},
{
"name": "utility-bill.pdf",
"size": 189234,
"type": "application/pdf"
}
]
}
}
Status Values
| Status | Description |
|---|---|
pending |
Request created, notification sent, waiting for recipient to upload |
uploaded |
Files uploaded by recipient, webhook delivery in progress |
completed |
Files successfully delivered to your callback URL |
expired |
Upload link expired before recipient uploaded files |
cancelled |
Request was cancelled via API |
failed |
Webhook delivery failed after all retry attempts |
Cancel Session
Cancels a pending upload session. The upload link will no longer be valid. Cannot cancel sessions that have already been completed.
Example Request
curl --location --request DELETE 'https://api.filecourier.io/api/ext/sessions/sess_abc123xyz' \ -u 'your_client_id:your_client_secret'
Response
{
"status": true,
"message": "Session cancelled successfully"
}
Webhook Events
When files are uploaded, FileCourier sends a POST request to your callback_url with the file details and presigned download URLs.
Webhook Payload
{
"event": "files.delivered",
"timestamp": "2025-01-22T14:22:18Z",
"data": {
"request_id": "req_abc123xyz",
"reference_id": "CUST-12345",
"recipient_email": "[email protected]",
"files": [
{
"name": "drivers-license.pdf",
"size": 245832,
"type": "application/pdf",
"url": "https://files.filecourier.io/abc123/drivers-license.pdf?signature=...",
"expires_at": "2025-01-23T14:22:18Z"
},
{
"name": "utility-bill.pdf",
"size": 189234,
"type": "application/pdf",
"url": "https://files.filecourier.io/abc123/utility-bill.pdf?signature=...",
"expires_at": "2025-01-23T14:22:18Z"
}
]
}
}
Handling Webhooks
// Express.js webhook handler example app.post('/webhooks/filecourier', async (req, res) => { const { event, data } = req.body; if (event === 'files.delivered') { const { request_id, reference_id, files } = data; // Download each file for (const file of files) { const response = await fetch(file.url); const buffer = await response.arrayBuffer(); // Save to your storage await saveFile(reference_id, file.name, buffer); } // Update your database await updateOrder(reference_id, { documentsReceived: true }); } // Always respond with 200 to acknowledge receipt res.status(200).json({ received: true }); });
Retry Policy
If your endpoint returns a non-2xx response, FileCourier will retry the webhook delivery:
- 1st retry: 1 minute after initial attempt
- 2nd retry: 5 minutes after 1st retry
- 3rd retry: 30 minutes after 2nd retry
- 4th retry: 2 hours after 3rd retry
- 5th retry: 24 hours after 4th retry
After all retries are exhausted, the request status will be set to failed. You can check the admin dashboard to manually retry or download the files.
Webhook Security
To verify that webhooks are genuinely from FileCourier, we include a signature in the X-FileCourier-Signature header.
Verifying Signatures
const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(JSON.stringify(payload)) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } // In your webhook handler app.post('/webhooks/filecourier', (req, res) => { const signature = req.headers['x-filecourier-signature']; const isValid = verifyWebhookSignature( req.body, signature, process.env.FILECOURIER_WEBHOOK_SECRET ); if (!isValid) { return res.status(401).json({ error: 'Invalid signature' }); } // Process webhook... });
Your webhook secret is available in your API settings.
Need Help?
If you have questions or run into issues, we're here to help.