Print shops and studios
A customer attaches layouts and archives to an order while your backend receives upload status and the transfer link.
Partner API creates file transfers, reserves every object before issuing a short-lived upload URL, verifies the actual uploaded size and sends webhook notifications. Data is isolated by `partner_id` and `project_id`, so a partner can access only its own transfers, files and events.
A customer attaches layouts and archives to an order while your backend receives upload status and the transfer link.
Legal, accounting and service workflows can accept large PDFs, photos and videos within explicit per-project limits.
A transfer is linked to an `external_id`, while webhooks update the record after upload, email delivery or download events.
Students, creators or clients submit video, projects and source files while storage is billed according to actual usage.
Submit an application; after approval you receive a `project_key` and a secret API key.
Your backend calls `partner_create_transfer` with stable `external_id` and `client_file_id` values, receives an `upload_requests[]` manifest and a short-lived `upload_resume_key`. No remote object is created at this stage.
Call the manifest `initialize_endpoint` for each file. Only after server-side reservation does FastSend issue a presigned URL; the uploaded object is verified with HEAD, moved out of staging and confirmed.
FastSend creates the share link, sends recipient emails, and records storage plus outbound traffic for daily billing.
You can enable `e2ee_aes_256_gcm`: the client encrypts the file while FastSend stores the encrypted blob and metadata. The decryption key must remain with your product or user and must not be sent to FastSend.
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /partner-api.php?action=partner_me | Validate the key and return balance, projects and current statistics. |
| POST | /partner-api.php?action=partner_list_projects | List partner projects, statuses, origins, webhook settings and limits. |
| POST | /partner-api.php?action=partner_update_project | Update a project (`transfers:write`). Rotating the webhook secret additionally requires `webhooks:write` and reveals the new secret only in that response. |
| POST | /partner-api.php?action=partner_create_transfer | Idempotently create a draft and return `upload_requests[]`; no presigned URL is issued at this stage. |
| POST | /partner-api.php?action=partner_create_upload_url | Reserve a single upload by `client_file_id` and return a short-lived PUT URL. |
| POST | /partner-api.php?action=partner_create_multipart_upload | Reserve a multipart upload and return `upload_id`, `multipart_upload_id` and part size. |
| POST | /partner-api.php?action=partner_create_multipart_part_url | Issue a URL for exactly one part of an already reserved multipart upload. |
| POST | /partner-api.php?action=partner_complete_multipart_upload | Validate the ETag list, complete multipart upload, verify and confirm the object. |
| POST | /partner-api.php?action=partner_abort_multipart_upload | Abort an unfinished multipart upload and release its reservation. |
| POST | /partner-api.php?action=partner_confirm_upload | After a single PUT, verify the object, accept `content_sha256`/`encryption_meta`, and confirm the file. |
| POST | /partner-api.php?action=partner_finalize_transfer | Finalize the transfer, send email and add the files to daily storage accounting. |
| POST | /partner-api.php?action=partner_list_transfers | Return recent partner transfers with files. Direct-download URLs are included only with `files:download`. |
| POST | /partner-api.php?action=partner_transfer_status | Return files, recipients, email delivery states and download status. |
| POST | /partner-api.php?action=partner_create_direct_download_link | Create a signed direct file link without the FastSend download page; requires `files:download`. |
| GET | /partner-api.php?action=partner_direct_download | Public signed file-download URL. The API key is never placed in the URL. |
| POST | /partner-api.php?action=partner_delete_file | Delete one partner file, recalculate transfer size and invalidate the ZIP cache. |
| POST | /partner-api.php?action=partner_delete_transfer | Delete a partner transfer and its files to stop storage accounting. |
curl -X POST https://fast-send.ru/partner-api.php?action=partner_create_transfer \
-H "Authorization: Bearer fs_partner_live_xxx" \
-H "Content-Type: application/json" \
--data '{
"project_key": "prj_your_project_key",
"external_id": "order-100500",
"share_mode": "both",
"sender_email": "noreply@example.com",
"recipients": [
"client@example.com"
],
"subject": "Application documents",
"encryption_mode": "none",
"files": [
{
"client_file_id": "order-100500-contract-v1",
"filename": "contract.pdf",
"size": 7340032,
"content_type": "application/pdf"
}
],
"metadata": {
"order_id": 100500
}
}'
`uploads` is intentionally empty: call `initialize_endpoint` first. Keep `upload_resume_key` until finalization and never write it to logs.
{
"ok": true,
"idempotent": false,
"transfer": {
"id": 987,
"external_id": "order-100500",
"status": "draft",
"expires_at": "2027-07-16T12:00:00+03:00"
},
"uploads": [],
"upload_initialization_required": true,
"upload_requests": [
{
"client_file_id": "order-100500-contract-v1",
"upload_type": "single",
"initialize_endpoint": "partner-api.php?action=partner_create_upload_url",
"filename": "contract.pdf",
"relative_path": "contract.pdf",
"content_type": "application/pdf",
"size": 7340032,
"confirm_endpoint": "partner-api.php?action=partner_confirm_upload"
}
],
"upload_resume_key": "<43-char-scoped-secret>",
"upload_resume_key_revealed_once": false,
"upload_resume_key_recoverable_on_idempotent_replay": true,
"upload_resume_expires_at": "2026-07-17 12:00:00",
"management_access_code": "<management-secret>",
"management_access_code_revealed_once": false,
"management_access_code_recoverable_on_idempotent_replay": true
}
curl -X POST https://fast-send.ru/partner-api.php?action=partner_create_upload_url \
-H "Authorization: Bearer fs_partner_live_xxx" \
-H "Content-Type: application/json" \
--data '{
"project_key": "prj_your_project_key",
"send_id": 987,
"upload_resume_key": "<43-char-scoped-secret>",
"client_file_id": "order-100500-contract-v1",
"filename": "contract.pdf",
"relative_path": "contract.pdf",
"content_type": "application/pdf",
"size": 7340032
}'
Then PUT the bytes to `upload_url` with the same `Content-Type` and call `partner_confirm_upload` with `project_key`, `send_id`, `upload_resume_key` and `upload_id`. For multipart, request each part URL, retain its ETag and pass the ordered `parts` array to `partner_complete_multipart_upload`.
FastSend sends `transfer.finalized`, `transfer.downloaded`, `transfer.file_deleted` and `transfer.deleted`. `X-FastSend-Signature: sha256=…` is an HMAC-SHA256 over the exact byte sequence `X-FastSend-Timestamp + "." + raw_body`. The receiver rejects timestamps older than five minutes, compares the signature in constant time and deduplicates `X-FastSend-Delivery`.
{
"event": "transfer.finalized",
"partner_id": 12,
"project_id": 34,
"transfer": {
"id": 987,
"external_id": "order-100500",
"share_url": "https://fast-send.ru/?t=abc123",
"status": "sent",
"declared_size": 7340032,
"file_count": 1,
"encryption_mode": "e2ee_aes_256_gcm"
},
"data": {
"email_delivery": {
"sent": 1,
"failed": 0
}
},
"occurred_at": "2026-10-13T22:44:32+03:00"
}
Test vector
secret: whsec_test_0123456789abcdef
timestamp: 1720000000
payload: {"event":"transfer.finalized","transfer":{"id":987}}
signature: sha256=993d8c2f1f8322474acdd42154dbafd815d5e2a0cb3ccef2b26f64bbfcbe6830
When a partner needs to deliver a file inside its own interface without the FastSend download page, the backend requests a signed link. The link contains no API key, expires automatically and still counts actual outbound traffic.
curl -X POST https://fast-send.ru/partner-api.php?action=partner_create_direct_download_link \
-H "Authorization: Bearer FS-PARTNER-..." \
-H "Content-Type: application/json" \
--data '{
"project_key": "prj_your_project_key",
"external_id": "order-100500",
"file_id": 123,
"ttl_seconds": 604800
}'
POST /partner-api.php?action=partner_update_project
Authorization: Bearer FS-PARTNER-...
Content-Type: application/json
{
"project_key": "prj_your_project_key",
"name": "CRM production",
"domain": "crm.example.com",
"allowed_origins": "https://crm.example.com",
"webhook_url": "https://crm.example.com/webhooks/fastsend",
"rotate_webhook_secret": true,
"e2e_enabled": true,
"status": "active"
}
POST /partner-api.php?action=partner_create_transfer
Authorization: Bearer FS-PARTNER-...
Content-Type: application/json
{
"project_key": "prj_your_project_key",
"external_id": "order-100500",
"share_mode": "email",
"recipients": ["client@example.com"],
"subject": "Order documents",
"files": [{"client_file_id": "order-100500-invoice-v1", "filename": "invoice.pdf", "size": 245760}]
}
POST /partner-api.php?action=partner_delete_transfer
Authorization: Bearer FS-PARTNER-...
Content-Type: application/json
{
"project_key": "prj_your_project_key",
"external_id": "order-100500"
}
A Partner key is scoped to the partner and its projects. Responses expose sender/recipient email, file lists, upload state, email delivery and download status only within your project.
Scopes fail closed: an empty scope list grants no access. JSON requests are limited to 1 MB; one transfer supports up to 1,000 files and 100 recipients; metadata supports up to 64 top-level fields and 32 KB. `webhook_secret` is absent from all read responses.
`external_id` is the create idempotency key. A retry is accepted only with the identical canonical request and restores the scoped upload capability; a changed payload receives HTTP 409. `client_file_id` provides stable file identity and makes upload initialization retries safe.
The current contract version is `2026-07-16`: the server returns it in `X-FastSend-API-Version`; a client can send the same header and receive 406 instead of silently using an unsupported version. Full contract: OpenAPI 3.1; compatibility history: changelog/deprecation policy.
Keep the machine API key on the backend only; the browser should receive only the minimum necessary short-lived upload URL/scoped upload key.
Before requesting access, the partner accepts the Partner terms and data-processing policy. Access may be denied or suspended for prohibited workflows, illegal content or attempts to bypass billing.
Request Partner access