Skip to Content
API ReferenceLoad Cargo

Load Cargo

Submit a request for batch processing.

POST /cargo/load

Authentication

This endpoint requires the X-API-Key header with a valid project API key.

-H "X-API-Key: convoy_sk_your_key_here"

See Authentication for details on obtaining API keys.

Request Body

{ "params": { "model": "claude-3-haiku", "max_tokens": 1024, "messages": [ {"role": "user", "content": "Your prompt here"} ], "system": "Optional system prompt", "temperature": 0.7, "top_p": 0.9, "top_k": 50, "stop_sequences": ["STOP"] }, "callback_url": "https://your-server.com/callback", "metadata": { "order_id": "ord_8842", "de_callback_id": "AQICAHh..." } }

Parameters

FieldTypeRequiredDescription
params.modelstringYesProvider-agnostic model ID (e.g., claude-3-haiku)
params.max_tokensintegerYes (chat)Max tokens to generate. Required for chat requests (messages); ignored for embedding requests (input_text). Must be a positive integer
params.messagesarrayYesConversation messages
params.systemstringNoSystem prompt
params.temperaturefloatNoSampling temperature (0.0-1.0)
params.top_pfloatNoTop-p sampling (0.0-1.0)
params.top_kintegerNoTop-k sampling
params.stop_sequencesarrayNoStop sequences
callback_urlstringNoHTTPS URL to receive results via webhook. Omit for “mailbox-only” submissions — no webhook is sent and you fetch the result with GET /cargo/{cargo_id}/result. Mutually exclusive with callback
callbackobjectNoStructured callback target for direct AWS delivery, discriminated on type: aws_durable_callback ({"type": "aws_durable_callback", "connection_id": "awsconn_…", "callback_id": "<your durable callback ID>"} — resumes your durable Lambda execution), aws_sfn_task_token ({"type": "aws_sfn_task_token", "connection_id": "awsconn_…", "task_token": "<$$.Task.Token>"} — resumes your Step Functions .waitForTaskToken wait), aws_lambda_invoke ({"type": "aws_lambda_invoke", "connection_id": "awsconn_…", "function_arn": "arn:aws:lambda:…:function:on-cargo-done:$LATEST"} — invokes your Lambda function asynchronously with the result envelope; the ARN must be qualified with :$LATEST, a version, or an alias), aws_eventbridge ({"type": "aws_eventbridge", "connection_id": "awsconn_…", "event_bus_arn": "arn:aws:events:…:event-bus/my-bus"} — publishes a source=convoy.cargo event onto your bus), aws_sqs ({"type": "aws_sqs", "connection_id": "awsconn_…", "queue_arn": "arn:aws:sqs:…:cargo-results"} — sends the envelope to your queue; FIFO queues require message_group_id), aws_kinesis ({"type": "aws_kinesis", "connection_id": "awsconn_…", "stream_arn": "arn:aws:kinesis:…:stream/cargo-results"} — puts the envelope on your stream; optional partition_key, defaults to the cargo_id), aws_sfn_start ({"type": "aws_sfn_start", "connection_id": "awsconn_…", "state_machine_arn": "arn:aws:states:…:stateMachine:handle-result"} — starts a NEW execution named convoy-{cargo_id} with the envelope as input), or aws_s3 ({"type": "aws_s3", "connection_id": "awsconn_…", "bucket_arn": "arn:aws:s3:::acme-cargo-results", "key_prefix": "convoy/"} — writes the FULL result, no size cap, as {key_prefix}{cargo_id}.json in your bucket; write-only and prefix-scoped). No webhook endpoint needed. Mutually exclusive with callback_url
result_ttl_secondsintegerNoHow long the stored result stays retrievable via /result — 3,600 (1 hour) to 2,592,000 (30 days). Default: 30 days
metadataobjectNoUp to 50 string-to-string pairs, echoed back verbatim in the callback payload and the /result body. Opaque to Convoy — never interpreted, logged, or indexed

Breaking change: max_tokens is now required for chat requests and no longer defaults to 1024. Requests that omit it are rejected with a 422 validation error ("max_tokens is required for chat requests"). Set it to a realistic ceiling for your workload — it caps the model’s output and is used to estimate the credit hold placed while the batch is in flight, so a tighter value means a smaller hold against your available balance.

See Supported Models for the full list of available model IDs.

Getting your results

Every result is stored server-side (30 days by default) regardless of how you submit. You have two delivery options — use either or both:

The webhook body and the /result body have the same shape, so your parsing code is delivery-agnostic. Even with a callback_url, /result remains available as a fallback (e.g. after callback_failed).

Metadata

Attach your own correlation data to a request with the optional top-level metadata object. Convoy stores it verbatim and echoes it back in the callback payload — it is never interpreted, logged, or indexed. Typical uses: correlating a callback with a record in your system (order_id, trace_id), or carrying a resume token for a workflow engine (e.g. an AWS Lambda durable function callback ID).

Limits (requests that exceed them are rejected with a 422):

ConstraintLimit
Entries50
Key length128 characters
Value length2,048 characters
Total serialized size4,096 bytes (JSON-encoded)
TypesString keys and string values only

Metadata values may carry secrets or capability tokens, so Convoy treats them as sensitive: validation errors reference the offending key only, and values never appear in Convoy’s logs.

Message Format

{ "role": "user", "content": "Message text" }

Or with content blocks:

{ "role": "user", "content": [ {"type": "text", "text": "Message text"} ] }

Multimodal Content Blocks

Messages can reference uploaded files (images, PDFs, documents, and video) alongside text using image, document, and video content blocks. Upload the file either from your project’s Files tab in the dashboard or programmatically via the Files API (POST /files → presigned direct-to-storage upload → POST /files/{id}/complete), then reference its file_id in the request. Two Files API branches to handle: if POST /files returns an existing identical file (deduplicated: true, upload: null), skip the upload and completion steps and use its id directly; and POST /files/{id}/complete may return 202 (status: "validating") while the malware scan is pending — keep polling while the status is pending and use the file once it reaches ready. A failed status is terminal (e.g. malware detected, checksum mismatch, scan timeout): stop polling and surface the error instead of referencing the file:

{ "role": "user", "content": [ {"type": "text", "text": "Summarize this document"}, {"type": "document", "source": {"file_id": "file_0123456789abcdef0123456789abcdef"}} ] }

Only models with the matching capability accept these blocks — look for the Vision, Documents, and Video badges on the models page . Referenced files must be uploaded to the same project and finished processing (status ready); otherwise the request is rejected.

Plan availability (Convoy Cloud): file uploads are available on the Starter and Pro plans. On the Free plan, creating files returns 403 files_not_allowed_for_plan and the dashboard shows an upgrade prompt instead of the upload widget — upgrade from Dashboard → Billing to enable uploads. Self-hosted Enterprise deployments are not plan-gated; Files limits come from your license entitlements.

Response

{ "cargo_id": "cargo_9f4c1b2a3d4e5f60718293a4b5c6d7e8", "status": "success", "message": "Cargo loaded successfully" }
FieldDescription
cargo_idUnique identifier for tracking
statussuccess or error
messageResult description

Examples

curl

curl -X POST https://api.cnvy.ai/cargo/load \ -H "Content-Type: application/json" \ -H "X-API-Key: convoy_sk_your_key_here" \ -d '{ "params": { "model": "claude-3-haiku", "max_tokens": 100, "messages": [{"role": "user", "content": "Hello"}] }, "callback_url": "https://example.com/callback" }'

Python

import httpx response = httpx.post( "https://api.cnvy.ai/cargo/load", headers={ "X-API-Key": "convoy_sk_your_key_here" }, json={ "params": { "model": "claude-3-haiku", "max_tokens": 100, "messages": [{"role": "user", "content": "Hello"}] }, "callback_url": "https://example.com/callback" } ) data = response.json() cargo_id = data["cargo_id"] print(f"Submitted: {cargo_id}")

JavaScript

const response = await fetch("https://api.cnvy.ai/cargo/load", { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": "convoy_sk_your_key_here" }, body: JSON.stringify({ params: { model: "claude-3-haiku", max_tokens: 100, messages: [{ role: "user", content: "Hello" }] }, callback_url: "https://example.com/callback" }) }); const { cargo_id } = await response.json(); console.log(`Submitted: ${cargo_id}`);

Errors

StatusDescription
400Invalid request body or invalid model ID
401Missing or invalid API key
403Project is inactive
422Validation error (e.g. max_tokens missing on a chat request)
429Rate limit or quota exceeded (rate_limit_exceeded / quota_exceeded)
500Internal server error

Error Response Examples

Missing API Key:

{"detail": "API key required. Include X-API-Key header."}

Invalid API Key:

{"detail": "Invalid API key."}

Inactive Project:

{"detail": "Project is inactive."}

Missing max_tokens (chat request):

{ "detail": [ { "type": "value_error", "loc": ["body", "params"], "msg": "Value error, max_tokens is required for chat requests" } ] }

Invalid Model ID:

{ "detail": { "error": "invalid_model", "message": "Unknown model: claude-4-turbo", "supported_models": ["claude-3-haiku", "claude-3-sonnet", "claude-3-opus", "..."] } }
Last updated on