FastSendPartner API
For websites, CRMs and services

Accept large files without building your own storage layer

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.

Bearer API keys Project isolation Client-side E2EE Direct upload to S3

Partner platform pricing

File storage1 GB freethen 4 RUB/GB per month, charged daily
Outbound traffic50 GB/monthfree, then 2.5 RUB/GB
Credit limit−1 000 ₽after the threshold, service pauses until the balance is topped up
File limit100 GBa project may set a lower limit
Transfer limit250 GBthe server hard limit cannot be disabled with a zero value
Retention365 daysfinite retention; you can delete earlier from the portal or API

Print shops and studios

A customer attaches layouts and archives to an order while your backend receives upload status and the transfer link.

Documents and applications

Legal, accounting and service workflows can accept large PDFs, photos and videos within explicit per-project limits.

CRMs and customer portals

A transfer is linked to an `external_id`, while webhooks update the record after upload, email delivery or download events.

Education and media

Students, creators or clients submit video, projects and source files while storage is billed according to actual usage.

How the flow works

1
Partner access

Submit an application; after approval you receive a `project_key` and a secret API key.

2
Create the transfer

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.

3
Reserve and upload

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.

4
Finalize

FastSend creates the share link, sends recipient emails, and records storage plus outbound traffic for daily billing.

End-to-end encryption

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.

Important: antivirus scanning cannot inspect E2EE content. Production therefore rejects such uploads by default; the operator must explicitly approve the abuse policy and enable `ALLOW_UNSCANNABLE_E2EE_UPLOADS=true`. Use a unique IV per file and deliver the key outside FastSend.

Endpoints

MethodEndpointPurpose
POST/partner-api.php?action=partner_meValidate the key and return balance, projects and current statistics.
POST/partner-api.php?action=partner_list_projectsList partner projects, statuses, origins, webhook settings and limits.
POST/partner-api.php?action=partner_update_projectUpdate 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_transferIdempotently create a draft and return `upload_requests[]`; no presigned URL is issued at this stage.
POST/partner-api.php?action=partner_create_upload_urlReserve a single upload by `client_file_id` and return a short-lived PUT URL.
POST/partner-api.php?action=partner_create_multipart_uploadReserve a multipart upload and return `upload_id`, `multipart_upload_id` and part size.
POST/partner-api.php?action=partner_create_multipart_part_urlIssue a URL for exactly one part of an already reserved multipart upload.
POST/partner-api.php?action=partner_complete_multipart_uploadValidate the ETag list, complete multipart upload, verify and confirm the object.
POST/partner-api.php?action=partner_abort_multipart_uploadAbort an unfinished multipart upload and release its reservation.
POST/partner-api.php?action=partner_confirm_uploadAfter a single PUT, verify the object, accept `content_sha256`/`encryption_meta`, and confirm the file.
POST/partner-api.php?action=partner_finalize_transferFinalize the transfer, send email and add the files to daily storage accounting.
POST/partner-api.php?action=partner_list_transfersReturn recent partner transfers with files. Direct-download URLs are included only with `files:download`.
POST/partner-api.php?action=partner_transfer_statusReturn files, recipients, email delivery states and download status.
POST/partner-api.php?action=partner_create_direct_download_linkCreate a signed direct file link without the FastSend download page; requires `files:download`.
GET/partner-api.php?action=partner_direct_downloadPublic signed file-download URL. The API key is never placed in the URL.
POST/partner-api.php?action=partner_delete_fileDelete one partner file, recalculate transfer size and invalidate the ZIP cache.
POST/partner-api.php?action=partner_delete_transferDelete a partner transfer and its files to stop storage accounting.

Request example

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
    }
}'

Create response

`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
}

Initialize a single file

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`.

Webhook

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

Direct file download

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
}'

Project management

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"
}

Usage patterns

CRM or order workflow

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}]
}

Delete after a case is closed

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"
}

Access boundaries

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