Types and payloads
This page describes the shapes you work with on the low-level client: the payload you pass to
createWorkflow(), the enums that name operations and states, and the status and download responses.
The methods themselves are in the Client reference. If you use the file-first builders
(file(), files(), merge()), they build the payload for you and you can skip most of this page.
Field casing
The SDK does not use one casing everywhere. Which one you see depends on where the data came from:
| Surface | Casing | Example |
|---|---|---|
Responses from low-level methods (getWorkflowStatus, getWorkflowDownloads, createWorkflow, uploadFile, …) | camelCase: properties in TypeScript, getters in PHP | status.workflowId / $status->getWorkflowId() |
The payload you send to createWorkflow, including operation options | snake_case wire keys (PHP's payload classes take camelCase arguments and write them for you) | callback_url, file_id, output_format |
SSE event data from streamEvents() | snake_case, exactly as the server sent it | event.data.operation_id |
| Webhook request bodies | snake_case, until you run them through the generated model | delivery_id, event_type |
Enum values are never re-cased. Only field names change: the value of status is in_progress
on every surface.
In TypeScript, responses are converted by the generated contract models, which also turn timestamps
such as createdAt into Date objects. SSE frames are only JSON.parsed, so their keys stay
snake_case, and GislSseEvent types them that way: each event's data is a snake_case wire interface
(SseOperationProgressWire, SseOperationCompletedWire and the rest), so event.data.operation_id
type-checks and event.data.operationId does not. The camelCase Sse*Data models describe the output
of their FromJSON helpers, not the frames streamEvents() yields. In PHP, GislSseEvent::$data is a
plain associative array with snake_case keys.
For webhook bodies, see Webhooks.
The workflow payload
A workflow is a list of jobs. Each job has one source, or several inputs, and an ordered list of operations. Workflows explains the model; the source factories are listed there too.
| Wire field | Type | Purpose |
|---|---|---|
jobs | list of jobs, at least one | the work |
workflow_edges | list of { from, to } job ids | explicit dependencies; usually inferred from job_output sources |
callback_url | string | enables webhooks |
callback_events | list of CallbackEventType values | which events are posted to callback_url |
notify | NotifyConfig (email channel) | per-job completion notifications. Declared ahead of the server: any channel returns feature_not_available (422) today; an empty object is a no-op |
export | { type: 'connection', connection_id, path } or { type: 'external_import', external_source_id } | write outputs to external storage |
delivery | mode (individual, bundle, both), bundle_format (zip, tar_gz), bundle_filename, include_metadata, selection | how outputs are delivered |
processing | class_hint (auto, short_form_only, long_form_allowed, long_form_preferred) | a hint about the processing class |
delivery.selection.type is terminal, all_outputs or explicit; explicit takes refs, a list of
{ ref, operation? }.
Each job:
| Wire field | Purpose |
|---|---|
id | optional label. Needed when another job, an edge or a delivery selection refers to it. The server generates one when omitted and echoes it back as ref. |
source | single input: an upload, job_output, external_import or connection source |
inputs | multiple inputs: a list of { source, role?, per_input_options? } |
operations | ordered list of { type, options? }; type is an OperationType value, options uses snake_case keys |
deliver | true to deliver this job's output even though another job consumes it; cannot be combined with an explicit delivery selection |
Set source or inputs, not both. The SDK does not check this; the server rejects it.
The multi-input operations are merge, archive, image_watermark, video_watermark,
audio_overlay, audio_to_video and custom_luma. An inputs[].source cannot be an upload: an
uploaded file enters through a job whose only operation is passthrough, which you then reference
with a job_output source. A multi-input job has exactly one operation, of one of those types.
role is base, overlay or transition_mask.
- TypeScript
- PHP
- Python
- Rust
The payload types are plain objects with wire (snake_case) keys: WorkflowCreatePayload,
JobDefinitionPayload, JobInputV2Payload, OperationDef, WorkflowSourcePayload (and
MultiInputSourcePayload, the same union without upload), ExternalDestinationPayload,
DeliveryPayload and WorkflowProcessingPayload. All are exported from @giveitsmaller/sdk.
import {
CallbackEventType,
JobInputV2RoleEnum,
OperationType,
jobOutputSource,
uploadSource,
type WorkflowCreatePayload,
} from '@giveitsmaller/sdk';
const payload: WorkflowCreatePayload = {
jobs: [
{ id: 'base_src', source: uploadSource(base.fileId), operations: [{ type: OperationType.passthrough }] },
{ id: 'logo_src', source: uploadSource(logo.fileId), operations: [{ type: OperationType.passthrough }] },
{
id: 'watermarked',
inputs: [
{ source: jobOutputSource('base_src'), role: JobInputV2RoleEnum.base },
{ source: jobOutputSource('logo_src'), role: JobInputV2RoleEnum.overlay },
],
operations: [{ type: OperationType.image_watermark, options: { anchor: 'bottom_right' } }],
},
],
callback_url: 'https://example.com/hooks/gisl',
callback_events: [CallbackEventType.workflow_completed],
};
const created = await client.createWorkflow(payload);
WorkflowCreatePayload also declares optional top-level source and operations (a flat
single-job form). The server does not accept that form; always send jobs.
createWorkflow() takes a WorkflowCreatePayload object, not an array. The payload classes live in
Gisl\Sdk: WorkflowCreatePayload, JobDefinitionPayload, OperationDef and the Sources
factories. Each class takes camelCase named arguments and writes the snake_case wire keys itself.
export is spelled exportPayload: because export is reserved in PHP. source, each inputs
entry, export, delivery and processing are plain arrays in the wire shape.
use Gisl\Generated\OpenApi\Model\CallbackEventType;
use Gisl\Generated\OpenApi\Model\JobInputV2;
use Gisl\Generated\OpenApi\Model\OperationType;
use Gisl\Sdk\JobDefinitionPayload;
use Gisl\Sdk\OperationDef;
use Gisl\Sdk\Sources;
use Gisl\Sdk\WorkflowCreatePayload;
$passthrough = [new OperationDef(OperationType::PASSTHROUGH)];
$created = $client->createWorkflow(new WorkflowCreatePayload(
jobs: [
new JobDefinitionPayload($passthrough, id: 'base_src', source: Sources::upload($base->getFileId())),
new JobDefinitionPayload($passthrough, id: 'logo_src', source: Sources::upload($logo->getFileId())),
new JobDefinitionPayload(
operations: [new OperationDef(OperationType::IMAGE_WATERMARK, ['anchor' => 'bottom_right'])],
id: 'watermarked',
inputs: [
['source' => Sources::jobOutput('base_src'), 'role' => JobInputV2::ROLE_BASE],
['source' => Sources::jobOutput('logo_src'), 'role' => JobInputV2::ROLE_OVERLAY],
],
),
],
callbackUrl: 'https://example.com/hooks/gisl',
callbackEvents: [CallbackEventType::WORKFLOW_COMPLETED],
));
Not available: the Python SDK is not published and no release is scheduled — see Python.
Not an application SDK: Rust is internal contract types — see Rust.
The options each operation takes are on the Operations pages.
Enums
In TypeScript every enum below is a const object with lowercase members, exported from
@giveitsmaller/sdk (OperationType.compress). In PHP it is a class of string constants in
Gisl\Generated\OpenApi\Model (OperationType::COMPRESS). Both hold the same string values, and
response fields carry the plain string.
| Enum | Values | Where it appears |
|---|---|---|
OperationType | compress, thumbnail, thumbnail_image, thumbnail_video, thumbnail_document, thumbnail_office, image_watermark, text_watermark, render_variants, merge, archive, convert, custom_luma, audio_overlay, audio_watermark, audio_to_video, video_watermark, video_text_watermark, split, transform, passthrough | operations[].type; type on each operation in a status response |
WorkflowStatus | pending, in_progress, completed, failed, partially_failed, paused_insufficient_credits, cancelled, expired | status on status and create responses |
JobStatus | pending, waiting, blocked_insufficient_credits, in_progress, completed, failed | jobs[].status |
OperationStatus | pending, in_progress, completed, failed, retried | jobs[].operations[].status |
CallbackEventType | workflow.completed, workflow.failed, workflow.partially_failed, operation.completed | callback_events on the payload |
SseEventType | operation.progress, operation.completed, operation.failed, job.completed, job.failed, workflow.completed, workflow.failed, workflow.partially_failed | the event tag of a streamed event |
JobInputV2RoleEnum (TS) / JobInputV2::ROLE_* (PHP) | base, overlay, transition_mask | inputs[].role |
A value being in OperationType does not mean it is available to you: several are planned and
return feature_not_available (422). Ask the server with getSchema() or capabilities(); see the
Client reference. The file-first thumbnail() verbs send
thumbnail.
For the dotted enum values the TypeScript member names use underscores
(CallbackEventType.workflow_completed is 'workflow.completed'). Treat an unknown value as
possible: new values can be added, and the PHP SDK passes an unrecognised status string through
rather than failing.
Status and download responses
getWorkflowStatus() and waitForWorkflow() return a WorkflowStatusResponse;
getWorkflowDownloads() returns a WorkflowDownloadResponse. The paths below are TypeScript
properties; in PHP each segment is a getter (jobs[].operations[].result.downloadUrl is
$op->getResult()?->getDownloadUrl() inside loops over getJobs() and getOperations()).
WorkflowStatusResponse
| Path | Notes |
|---|---|
workflowId, status | status is a WorkflowStatus value |
createdAt, updatedAt, completedAt? | Date in TypeScript, \DateTime in PHP |
jobs[].ref | the id you gave the job, or the one the server generated |
jobs[].jobId, jobs[].status, jobs[].dependsOn | dependsOn lists upstream job refs |
jobs[].operations[].id, .type, .status, .progress? | progress is 0 to 100, present once the operation is in_progress or completed |
jobs[].operations[].result?.downloadUrl, .sizeBytes, .mimeType? | the operation's output; downloadUrl is pre-signed |
jobs[].operations[].result?.metrics? | e.g. compressionRatio, durationMs |
jobs[].operations[].errorCode?, .errorMessage? | present when the operation failed |
pausedDetail? | present only when status is paused_insufficient_credits |
WorkflowDownloadResponse
| Path | Notes |
|---|---|
downloads[].ref, downloads[].jobId | one entry per job |
downloads[].files[].operation, .operationId | which operation produced the file |
downloads[].files[].filename, .sizeBytes, .downloadUrl | downloadUrl is pre-signed |
bundle? | one archive of every deliverable; present only once a bundle requested with delivery.mode bundle or both is ready |
retentionExpiresAt? | when the outputs are deleted, if the server reports it |
createWorkflow() returns a WorkflowCreateResponse: workflowId, status, createdAt, jobs,
anonymous, deliveryPlan, processingPlan and warnings, plus webhookSecret, present only when you set
callback_url. The response to the create call is the only place the secret appears; store it
then. It may also carry cap, a read capability for workflows created without an account
(first-party only): keep it, because reads of such a workflow need it ({ capability } in TS)
and it is not returned again. Decide whether a workflow is anonymous from anonymous, never from
whether cap is present.
See also
- Client reference: the methods that take and return these shapes.
- Workflows: jobs, sources and outputs.
- Progress streaming: the event stream.
- Errors: what each error class carries.