4klyft API (1.0.0)

Download OpenAPI specification:

4klyft API Support: support@4klyft.com License: Proprietary

Logistics operations API for the 4klyft platform.

Overview

This API provides comprehensive endpoints for managing:

  • Routes & Execution: Create, manage, and execute delivery routes
  • Shipments & Loads: Track shipments from pickup to delivery
  • Fleet Management: Manage carriers, vehicles, and drivers
  • Proof of Delivery: Capture signatures, photos, and delivery confirmations
  • Settings: Configure system-wide and tenant-specific settings
  • Webhooks: Subscribe to real-time event notifications
  • Analytics: Access delivery performance metrics and reports

Authentication

All API endpoints (except /api/docs and /api/v1/iam/auth/*) require JWT Bearer token authentication. Include the token in the Authorization header:

Authorization: Bearer <your-jwt-token>

Rate Limiting

API requests are rate-limited to ensure fair usage. Standard limits are:

  • 1000 requests per minute for read operations
  • 100 requests per minute for write operations

Error Handling

The API uses RFC 7807 Problem Details for error responses.

Storage / Chunked Upload

Resource 'Storage / Chunked Upload' operations.

Begin a chunked upload session

Creates a resumable upload session. Returns the session id; clients then PATCH /storage/uploads/{id} with Upload-Offset headers to deliver chunks, and POST /storage/uploads/{id}/finalize to assemble.

Authorizations:
Bearer
Request Body schema:
required

The new ChunkedUpload resource

filename
required
string
Default: ""
mimeType
required
string
Default: ""
sizeBytes
integer >= 0
Default: 0
driveId
required
string
Default: ""
category
string
Default: "uploads"

Responses

Request samples

Content type
{
  • "filename": "",
  • "mimeType": "",
  • "sizeBytes": 0,
  • "driveId": "",
  • "category": "uploads"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "driveId": "",
  • "filename": "",
  • "mimeType": "",
  • "sizeBytes": 0,
  • "offset": 0,
  • "chunkCount": 0,
  • "status": "",
  • "category": "",
  • "storageUri": "string",
  • "createdAt": "2019-08-24T14:15:22Z",
  • "expiresAt": "2019-08-24T14:15:22Z"
}

Get upload session status

Returns current offset, total size, status, and other session metadata. Used by clients to resume after a disconnect.

Authorizations:
Bearer
path Parameters
id
required
string

Upload session ULID

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "driveId": "",
  • "filename": "",
  • "mimeType": "",
  • "sizeBytes": 0,
  • "offset": 0,
  • "chunkCount": 0,
  • "status": "",
  • "category": "",
  • "storageUri": "string",
  • "createdAt": "2019-08-24T14:15:22Z",
  • "expiresAt": "2019-08-24T14:15:22Z"
}

Abandon an upload session

Mark the session abandoned and clean up any transient chunk blobs.

Authorizations:
Bearer
path Parameters
id
required
string

Upload session ULID

Responses

Response samples

Content type
{
  • "type": "/errors/validation-error",
  • "title": "Validation Error",
  • "status": 400,
  • "detail": "The provided input is invalid",
  • "violations": [
    ],
  • "instance": "string"
}

Append a chunk

Append raw octet-stream bytes at the offset declared in the Upload-Offset header. Must match the server-side offset exactly; mismatch returns HTTP 409 with the expected offset.

Authorizations:
Bearer
path Parameters
id
required
string

Upload session ULID

header Parameters
Upload-Offset
required
integer

Byte offset where this chunk starts

Upload-Checksum
string

Optional sha256: checksum of this chunk

Content-Length
required
integer

Chunk size in bytes

Request Body schema:
required

Raw chunk bytes

string <binary>

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "driveId": "",
  • "filename": "",
  • "mimeType": "",
  • "sizeBytes": 0,
  • "offset": 0,
  • "chunkCount": 0,
  • "status": "",
  • "category": "",
  • "storageUri": "string",
  • "createdAt": "2019-08-24T14:15:22Z",
  • "expiresAt": "2019-08-24T14:15:22Z"
}

Finalize an upload

Concatenate all received chunks into the final stored file and emit FileUploaded. Idempotent on retry as long as the session has not been abandoned.

Authorizations:
Bearer
path Parameters
id
required
string

Upload session ULID

Request Body schema:
required

The new ChunkedUpload resource

id
string
Default: ""
driveId
string
Default: ""
filename
string
Default: ""
mimeType
string
Default: ""
sizeBytes
integer
Default: 0
offset
integer
Default: 0
chunkCount
integer
Default: 0
status
string
Default: ""
category
string
Default: ""
storageUri
string or null
createdAt
string or null <date-time>
expiresAt
string or null <date-time>

Responses

Request samples

Content type
{
  • "id": "",
  • "driveId": "",
  • "filename": "",
  • "mimeType": "",
  • "sizeBytes": 0,
  • "offset": 0,
  • "chunkCount": 0,
  • "status": "",
  • "category": "",
  • "storageUri": "string",
  • "createdAt": "2019-08-24T14:15:22Z",
  • "expiresAt": "2019-08-24T14:15:22Z"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "driveId": "",
  • "filename": "",
  • "mimeType": "",
  • "sizeBytes": 0,
  • "offset": 0,
  • "chunkCount": 0,
  • "status": "",
  • "category": "",
  • "storageUri": "string",
  • "createdAt": "2019-08-24T14:15:22Z",
  • "expiresAt": "2019-08-24T14:15:22Z"
}

Storage

OAuth 2.0 authorization-code flow endpoints for drive providers (API Platform).

POST /api/storage/oauth/init — start the flow (returns auth URL + state) POST /api/storage/oauth/refresh/{driveId} — mint a fresh access token for a drive

The third endpoint, GET /api/storage/oauth/callback, lives on a plain Symfony route (see OAuthCallbackProvider) because API Platform's Get operation requires an identifier in the URI path and OAuth callbacks only carry their code/state/provider as query strings.

List all drives

Retrieve a paginated list of storage drives with optional filters.

Authorizations:
Bearer
query Parameters
scope
string
Example: scope=tenant

Filter by drive scope

status
string
Enum: "active" "suspended" "disconnected"
Example: status=active

Filter by drive status

page
integer >= 1
Default: 1
Example: page=1

Page number for pagination

itemsPerPage
integer [ 1 .. 100 ]
Default: 20
Example: itemsPerPage=20

Number of items per page

Responses

Response samples

Content type
{
  • "totalItems": 0,
  • "search": {
    },
  • "view": {
    },
  • "member": [
    ]
}

Create a drive

Create a new storage drive.

Authorizations:
Bearer
Request Body schema: application/json
required

Drive creation data

label
required
string [ 1 .. 255 ] characters
type
required
string
Enum: "amazon_s3" "google_cloud_storage" "azure_blob" "google_drive" "dropbox" "onedrive" "sftp" "ftp" "s3_compatible"
pathPrefix
string or null
isDefault
boolean
Default: false

Responses

Request samples

Content type
application/json
{
  • "label": "Primary Storage",
  • "type": "amazon_s3",
  • "pathPrefix": "/uploads",
  • "isDefault": false
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "01JNXZ00000000000000000000",
  • "compactId": "string",
  • "scope": "tenant",
  • "label": "Primary Storage",
  • "type": "platform",
  • "status": "active",
  • "purpose": "document",
  • "pathPrefix": "/uploads",
  • "isDefault": false,
  • "quotaBytes": 1073741824,
  • "usedBytes": 0,
  • "createdAt": "2024-01-15T10:00:00+00:00"
}

Get drive credential status (redacted)

Returns whether the drive has stored credentials and a redacted set of public hints. Never returns secret material.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "driveId": "01JNXZ00000000000000000000",
  • "driveType": "amazon_s3",
  • "hasCredentials": false,
  • "configuredAt": "2026-05-28T11:00:00+00:00",
  • "hints": {
    }
}

Set drive credentials

Store encrypted credentials for an S3, S3-compatible, SFTP, or Azure Blob drive. The "type" field discriminates which fields apply.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Request Body schema: application/json
required

Credentials payload; field set selected by "type".

type
required
string
Enum: "amazon_s3" "s3_compatible" "sftp" "azure_blob"
accessKeyId
string or null
secretAccessKey
string or null
bucket
string or null
region
string or null
endpoint
string or null
usePathStyleEndpoint
boolean or null
host
string or null
port
integer or null
username
string or null
password
string or null
privateKey
string or null
accountName
string or null
accountKey
string or null
container
string or null

Responses

Request samples

Content type
application/json
{
  • "type": "amazon_s3",
  • "accessKeyId": "string",
  • "secretAccessKey": "string",
  • "bucket": "string",
  • "region": "string",
  • "endpoint": "string",
  • "usePathStyleEndpoint": true,
  • "host": "string",
  • "port": 0,
  • "username": "string",
  • "password": "string",
  • "privateKey": "string",
  • "accountName": "string",
  • "accountKey": "string",
  • "container": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "driveId": "01JNXZ00000000000000000000",
  • "driveType": "amazon_s3",
  • "hasCredentials": false,
  • "configuredAt": "2026-05-28T11:00:00+00:00",
  • "hints": {
    }
}

Get a drive

Retrieve a single storage drive by its ID.

Authorizations:
Bearer
path Parameters
id
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "01JNXZ00000000000000000000",
  • "compactId": "string",
  • "scope": "tenant",
  • "label": "Primary Storage",
  • "type": "platform",
  • "status": "active",
  • "purpose": "document",
  • "pathPrefix": "/uploads",
  • "isDefault": false,
  • "quotaBytes": 1073741824,
  • "usedBytes": 0,
  • "createdAt": "2024-01-15T10:00:00+00:00"
}

Activate a drive

Activate a suspended drive.

Authorizations:
Bearer
path Parameters
id
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "01JNXZ00000000000000000000",
  • "compactId": "string",
  • "scope": "tenant",
  • "label": "Primary Storage",
  • "type": "platform",
  • "status": "active",
  • "purpose": "document",
  • "pathPrefix": "/uploads",
  • "isDefault": false,
  • "quotaBytes": 1073741824,
  • "usedBytes": 0,
  • "createdAt": "2024-01-15T10:00:00+00:00"
}

Disconnect a drive

Disconnect a drive, making it unavailable.

Authorizations:
Bearer
path Parameters
id
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Request Body schema:
required

The new Drive resource

reason
required
string

Responses

Request samples

Content type
{
  • "reason": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "01JNXZ00000000000000000000",
  • "compactId": "string",
  • "scope": "tenant",
  • "label": "Primary Storage",
  • "type": "platform",
  • "status": "active",
  • "purpose": "document",
  • "pathPrefix": "/uploads",
  • "isDefault": false,
  • "quotaBytes": 1073741824,
  • "usedBytes": 0,
  • "createdAt": "2024-01-15T10:00:00+00:00"
}

Suspend a drive

Suspend an active drive.

Authorizations:
Bearer
path Parameters
id
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Request Body schema:
required

The new Drive resource

reason
required
string

Responses

Request samples

Content type
{
  • "reason": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "01JNXZ00000000000000000000",
  • "compactId": "string",
  • "scope": "tenant",
  • "label": "Primary Storage",
  • "type": "platform",
  • "status": "active",
  • "purpose": "document",
  • "pathPrefix": "/uploads",
  • "isDefault": false,
  • "quotaBytes": 1073741824,
  • "usedBytes": 0,
  • "createdAt": "2024-01-15T10:00:00+00:00"
}

Update drive label

Update the label of a drive.

Authorizations:
Bearer
path Parameters
id
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Request Body schema:
required

The new Drive resource

label
required
string [ 1 .. 255 ] characters

Responses

Request samples

Content type
{
  • "label": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "01JNXZ00000000000000000000",
  • "compactId": "string",
  • "scope": "tenant",
  • "label": "Primary Storage",
  • "type": "platform",
  • "status": "active",
  • "purpose": "document",
  • "pathPrefix": "/uploads",
  • "isDefault": false,
  • "quotaBytes": 1073741824,
  • "usedBytes": 0,
  • "createdAt": "2024-01-15T10:00:00+00:00"
}

Begin an OAuth flow for a drive provider

Returns the authorization URL the browser must navigate to plus the signed state token to be mirrored back on the callback.

Authorizations:
Bearer
Request Body schema: application/json
required

Provider selection + optional redirect override.

provider
required
string
Enum: "google_drive" "dropbox" "onedrive"
redirectUri
string or null
returnUri
string or null

Responses

Request samples

Content type
application/json
{
  • "provider": "google_drive",
  • "redirectUri": "string",
  • "returnUri": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "oauth",
  • "authorizationUrl": "string",
  • "state": "string",
  • "expiresInSeconds": 0,
  • "driveId": "string",
  • "expiresAt": "string"
}

Refresh the OAuth access token for a drive

Refresh the OAuth access token for a drive

Authorizations:
Bearer
path Parameters
driveId
required
string

StorageOAuth identifier

Request Body schema:
required

The new StorageOAuth resource

id
string
Default: "oauth"

Synthetic identifier; not part of any persisted entity.

authorizationUrl
string or null

Authorization URL the browser must navigate to (only present on init)

state
string or null

HMAC-signed state token (only present on init)

expiresInSeconds
integer or null

Lifetime of the state token in seconds (only present on init)

driveId
string or null

ULID of the drive (only present on refresh)

expiresAt
string or null

ISO 8601 timestamp of the new access token expiry (only present on refresh)

Responses

Request samples

Content type
{
  • "id": "oauth",
  • "authorizationUrl": "string",
  • "state": "string",
  • "expiresInSeconds": 0,
  • "driveId": "string",
  • "expiresAt": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "oauth",
  • "authorizationUrl": "string",
  • "state": "string",
  • "expiresInSeconds": 0,
  • "driveId": "string",
  • "expiresAt": "string"
}

File

Resource 'File' operations.

Get a file by name

Fetch file metadata by its storage name.

Authorizations:
Bearer
path Parameters
name
required
string

File identifier

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "name": "string",
  • "path": "string",
  • "isDirectory": false,
  • "mimeType": "string",
  • "sizeInBytes": 0,
  • "lastModified": "string",
  • "thumbnailUrl": "string",
  • "storageUri": "",
  • "originalFilename": "string",
  • "fileType": "string",
  • "derivedVariants": [
    ]
}

Storage / Files

Resource for the Storage signed file-access workflow:

POST /api/storage/drives/{driveId}/files/access-url — mint a short-lived signed URL for a file on a specific drive.

GET /api/storage/files/access/{token} — public stream endpoint. The token IS the auth (signature + expiry). Used by the frontend in /

The Get operation is also what API Platform uses to construct the @id IRI for the mint response — keeping both operations on the same resource avoids cross-resource IRI lookup issues.

List files in a drive

List files and folders within a drive at the given path.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

query Parameters
path
string
Default: "/"
Example: path=/invoices/2024

Directory path to list

page
integer
Default: 1

The collection page number

Responses

Response samples

Content type
{
  • "totalItems": 0,
  • "search": {
    },
  • "view": {
    },
  • "member": [
    ]
}

Delete a file

Delete a file from the specified drive.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

query Parameters
path
required
string
Example: path=invoices/2024/invoice-001.pdf

File path within the drive

Responses

Response samples

Content type
{
  • "type": "/errors/validation-error",
  • "title": "Validation Error",
  • "status": 400,
  • "detail": "The provided input is invalid",
  • "violations": [
    ],
  • "instance": "string"
}

Upload a file

Upload a file to the specified drive.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Request Body schema: multipart/form-data
required

File upload data (multipart/form-data)

file
required
string <binary>

The file to upload

path
string

Target folder to place the file in verbatim (e.g. "invoices/2024")

category
string
Default: "uploads"

Fallback folder when no path is given

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "name": "string",
  • "storageUri": "string",
  • "mimeType": "string",
  • "sizeInBytes": 0,
  • "originalFilename": "string",
  • "fileType": "string"
}

Create a folder

Create a new folder in the specified drive.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

Request Body schema: application/json
required

Folder creation data

path
required
string

Folder path to create

Responses

Request samples

Content type
application/json
{
  • "path": "invoices/2024"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "name": "string",
  • "path": "string",
  • "isDirectory": false,
  • "mimeType": "string",
  • "sizeInBytes": 0,
  • "lastModified": "string",
  • "thumbnailUrl": "string",
  • "storageUri": "",
  • "originalFilename": "string",
  • "fileType": "string",
  • "derivedVariants": [
    ]
}

Delete a folder

Delete a folder and all its contents from the specified drive.

Authorizations:
Bearer
path Parameters
driveId
required
string
Example: 01JNXZ00000000000000000000

Drive ULID

query Parameters
path
required
string
Example: path=invoices/2024

Folder path to delete

Responses

Response samples

Content type
{
  • "type": "/errors/validation-error",
  • "title": "Validation Error",
  • "status": 400,
  • "detail": "The provided input is invalid",
  • "violations": [
    ],
  • "instance": "string"
}

SignedFileUrl

Resource for the Storage signed file-access workflow:

POST /api/storage/drives/{driveId}/files/access-url — mint a short-lived signed URL for a file on a specific drive.

GET /api/storage/files/access/{token} — public stream endpoint. The token IS the auth (signature + expiry). Used by the frontend in /

The Get operation is also what API Platform uses to construct the @id IRI for the mint response — keeping both operations on the same resource avoids cross-resource IRI lookup issues.

Stream a signed file

Public endpoint: streams the file bytes; the signed token IS the auth (signature + expiry).

Authorizations:
Bearer
path Parameters
token
required
string

SignedFileUrl identifier

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "token": "string",
  • "url": "string",
  • "expiresAt": "string",
  • "expiresInSeconds": 0,
  • "filename": "string",
  • "mimeType": "string"
}

Stream a signed file (named URL)

Same as the token stream, with a trailing /{filename} so external consumers see a real file extension. The token is the auth; the filename is ignored.

Authorizations:
Bearer
path Parameters
token
required
string

SignedFileUrl identifier

filename
required
string

SignedFileUrl identifier

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "token": "string",
  • "url": "string",
  • "expiresAt": "string",
  • "expiresInSeconds": 0,
  • "filename": "string",
  • "mimeType": "string"
}

Storage / Upload Intent

Resource 'Storage / Upload Intent' operations.

Resolve (mint or resume) an upload intent

Declares an upload intent for a purpose + config and returns the intent — its id, resolved slots (each with accepted types/size/count constraints), and expiry. Idempotent per (purpose, config, identity): a reload returns the same active intent rather than duplicating staged files. Consumer features reference only the returned intent id.

Authorizations:
Bearer
Request Body schema:
required

The new UploadIntent resource

purpose
string
Default: ""
object
strategy
string or null

return_active (default) | continue_progress | fresh

Responses

Request samples

Content type
{
  • "purpose": "",
  • "config": {
    },
  • "strategy": "string"
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "purpose": "",
  • "status": "",
  • "slots": [
    ],
  • "staged": {
    },
  • "expiresAt": "string",
  • "createdAt": "string"
}

Get an upload intent

Returns the intent status, its slots, and the files staged into each slot so far.

Authorizations:
Bearer
path Parameters
id
required
string

Upload intent ULID

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "purpose": "",
  • "status": "",
  • "slots": [
    ],
  • "staged": {
    },
  • "expiresAt": "string",
  • "createdAt": "string"
}

Finalize an upload intent

Marks the intent complete once every required slot has met its minimum file count. The consumer feature then references the intent id to read the staged files. Pass {"saveToDrive": true} to PROMOTE each staged file into the tenant's document drive (durable, browsable, re-readable) instead of leaving it ephemeral — the response staged then carries the document URIs.

Authorizations:
Bearer
path Parameters
id
required
string

Upload intent ULID

Request Body schema: application/json
optional

Optional finalize options.

saveToDrive
boolean
Default: false

Promote staged files into the tenant document drive.

Responses

Request samples

Content type
application/json
{
  • "saveToDrive": false
}

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "purpose": "",
  • "status": "",
  • "slots": [
    ],
  • "staged": {
    },
  • "expiresAt": "string",
  • "createdAt": "string"
}

Stage a file into a slot

Uploads one file (multipart form field file) into the named slot. The server sniffs the mime type from the bytes and validates it plus the size against the slot constraints — a client-declared content type is never trusted. P2 replaces this proxied path with a presigned direct-to-driver URL.

Authorizations:
Bearer
path Parameters
id
required
string

Upload intent ULID

slot
required
string

Slot name

Request Body schema: multipart/form-data
required

The file to stage

file
string <binary>

Responses

Response samples

Content type
{
  • "@context": "string",
  • "@id": "string",
  • "@type": "string",
  • "id": "",
  • "purpose": "",
  • "status": "",
  • "slots": [
    ],
  • "staged": {
    },
  • "expiresAt": "string",
  • "createdAt": "string"
}