Create a workflow upload session
Create a workflow session with presigned upload URLs for the files to be submitted for processing. For a workflow with `upload.pdfPages`, create one upload slot (`fileCount: 1`, `contentTypes: ["application/pdf"]`) and PUT the complete PDF to its upload URL. One document becomes one submission regardless of its number of pages. The workflow's page limit is checked when submitting.
/api/v1/workflows/{slug}/sessionsAuthorization
AuthorizationRequiredBearer <token>Steve API key, usually scoped to a company. Legacy keys and keys created by platform administrators may be unscoped; company-scoped endpoints reject unscoped keys with 403 Forbidden. Format: Authorization: Bearer aok_...
In: header
Request Body
application/jsonRequiredfileCountRequiredintegerNumber of files to upload. Must fall within the resolved workflow version's upload window, i.e. between uploadStage.minFiles and uploadStage.maxFiles (inclusive). A value outside that window — or a non-integer — is rejected with a 422 validation-error on field fileCount.
1contentTypesRequiredarray<string>MIME types for each file to upload, in upload order. The array length MUST equal fileCount, and every entry MUST be one of the workflow version's uploadStage.acceptedFormats. A length mismatch returns a 422 validation-error on field contentTypes; an unaccepted entry returns a 422 validation-error on field contentTypes[i].
fileNamesarray<string>Optional original file names, parallel to contentTypes (same order). When present, the array length MUST equal fileCount, or the request is rejected with a 422 validation-error on field fileNames. Only the base name is kept (at most 255 characters); it is shown to reviewers and never used to address storage.
clientSubmissionIdRequiredstringwebhookUrlstringOptional webhook URL notified on session completion. Must be a valid HTTPS URL pointing at a public host. Non-HTTPS URLs, malformed URLs, or hosts that are loopback (localhost, 127.0.0.1), RFC 1918 private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), or .internal / .local suffixes are rejected with a 422.
"uri"metadataobjectOptional arbitrary metadata stored with the session. Constraints, enforced at creation: the serialized JSON must be at most 4096 bytes; nesting is limited to 2 levels; and leaf values must be string, number, or boolean only (no functions, dates, or other types). Violating any of these returns a 422 validation-error on field metadata. Workflow authors can map metadata keys (key or parent.child) to Open Loyalty custom-event fields or transaction labels; mapped values are sent as text.
externalUserobjectOptional end-user attribution. When provided, the submission is labeled in the Steve admin UI with (in order of preference) name, email, or id. If omitted, the submission is attributed to the API key that created it. The fields are also stored on the session. email, when provided, must look like an email address (x@y), otherwise the request is rejected with a 422 validation-error on field externalUser.email. If the workflow's Open Loyalty "Member email" setting is "API user", email identifies the Open Loyalty member; when it is missing, delivery is skipped with reason no_api_user_email.
batchRefstringOptional client-chosen grouping key, unique per company. Steve creates the batch on first use and increments its total once per newly created session. When processed equals total, completion waits until the newest session in the batch is at least five minutes old; a newer session resets that grace check. This reduces completion while an upload burst is still in flight. A pause longer than five minutes can still complete a batch early; sessions later added with the same reference increase totals but do not emit a second batch.completed event.
1Maximum length: 128Pattern: "^[A-Za-z0-9._-]+$"Path Parameters
slugRequiredstringWorkflow slug.
Header Parameters
X-Request-IdstringOptional caller-supplied request identifier. Maximum length is 128 characters.
128Existing pending session returned for the same clientSubmissionId on the same workflow. The Location header also points at the job resource (/api/v1/jobs/{sessionId}). If that session is no longer pending the request returns 409 instead of 200 — see the 409 response.