Run a pipeline
Use a configured pipeline to process a deal and retrieve its output submissions. The sequence below supplies case figures to a manual-input step, then reads all output values.
Connection and input
Use Bash, curl and jq. Set these variables in the shell. Choose a pipeline with one manual-input form containing numeric fields named TotalAssets and AnnualRevenue, followed by its configured analysis steps. Replace the field names and figures in VALUES for your form.
sh
export API_BASE="https://YOUR_API_HOST"
export TOKEN="YOUR_ACCESS_TOKEN"Run the following sections in order in the same Bash shell, or save them together as run-pipeline.sh and run bash run-pipeline.sh.
sh
set -euo pipefail
: "${API_BASE:?Set the API host root without /v2}"
: "${TOKEN:?Set the access token or API key}"
request() {
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" "$@"
}List the pipelines and select the ID of the pipeline to run:
sh
request "$API_BASE/v2/pipelines/" | jq '.[] | {id, name, steps}'
PIPELINE_ID="YOUR_PIPELINE_ID"1. Start the run
Create a deal to set DEAL_ID, then start the run:
sh
: "${PIPELINE_ID:?Set the configured pipeline ID}"
: "${DEAL_ID:?Set the deal ID}"
request -X POST "$API_BASE/v2/pipelines/runs" \
-d "$(jq -n --arg p "$PIPELINE_ID" --arg d "$DEAL_ID" '{pipelineId:$p,dealId:$d}')" > run.json
RUN_ID=$(jq -er '.runId' run.json)
jq '{runId, dispatchAttempt, links}' run.json
if [ "$(jq -r '.dispatchAttempt.outcome' run.json)" != accepted ]; then
exit 1
fiThe receipt returns the canonical runId and links for status and outputs.
2. Find the required input form
Read requiredFormId from the manual-input blocker, then read the draft submission the run created for that step from its outputs. The data read supplies the item IDs to populate.
Run status returns pipelineId and each step's pipelineStepId. Match these to the pipeline definition and its steps[].id. Use runStepId for an execution. Each steps[].attempt is the current positive-integer attempt, used to fence document uploads against step resets. Select a configured role or label through its definition, and use the IDs for the link. Names are display text.
sh
while :; do
request "$API_BASE/v2/pipelines/runs/$RUN_ID" > status.json
BLOCKER=$(jq -c '[.steps[] | . as $step | .blockers[] |
select(.blockerType == "missing_manual_input") |
{runStepId:$step.runStepId, formId:.blockerDetails.requiredFormId}][0] // empty' status.json)
[ -z "$BLOCKER" ] || break
case "$(jq -r '.status' status.json)" in
failed|cancelled|completed) jq . status.json; exit 1 ;;
esac
sleep 2
done
FORM_ID=$(jq -er '.formId' <<< "$BLOCKER")
RUN_STEP_ID=$(jq -er '.runStepId' <<< "$BLOCKER")
SUBMISSION_ID=$(request "$API_BASE/v2/pipelines/runs/$RUN_ID/outputs" \
| jq -er --arg s "$RUN_STEP_ID" --arg f "$FORM_ID" \
'first(.outputs[] | select(.runStepId == $s and .formId == $f)) | .submissionId')
request "$API_BASE/v2/submissions/$SUBMISSION_ID/data" > input.json3. Supply input values and attach the submission
sh
VALUES='{"TotalAssets":1250000,"AnnualRevenue":840000}'
while IFS=$'\t' read -r FIELD VALUE; do
ITEM_ID=$(jq -er --arg name "$FIELD" \
'[.groups[].items[] | select(.formField.name == $name) | .id] | if length == 1 then .[0] else error("Expected one matching field") end' input.json)
request -X PATCH "$API_BASE/v2/submissions/$SUBMISSION_ID/items/$ITEM_ID" \
-d "$(jq -n --argjson v "$VALUE" '{value:$v}')" > /dev/null
done < <(jq -r 'to_entries[] | [.key, (.value | tojson)] | @tsv' <<< "$VALUES")
request -X PATCH "$API_BASE/v2/submissions/$SUBMISSION_ID" -d '{"status":"final"}' > /dev/null
request -X POST "$API_BASE/v2/pipelines/runs/$RUN_ID/steps/$RUN_STEP_ID/manual-inputs" \
-d "$(jq -n --arg s "$SUBMISSION_ID" '{submissionId:$s}')"The blocker stays open until a final submission exists, so mark it final before attaching. The attach endpoint takes an existing submission ID. Use the exact form required by the step.
A pipeline can have several manual-input steps. Repeat sections 2 and 3 until no manual-input blocker remains. For an extraction step waiting for documents, use the separate run-step upload operation. It supplies that step's document dependency without creating or finalising a manual-input submission.
4. Read the result
sh
while :; do
request "$API_BASE/v2/pipelines/runs/$RUN_ID" > status.json
case "$(jq -r '.status' status.json)" in
completed) break ;;
failed|cancelled) jq . status.json; exit 1 ;;
esac
sleep 2
done
request "$API_BASE/v2/pipelines/runs/$RUN_ID/outputs" > outputs.json
jq '.outputs[] | {runStepId, formId, submissionId, outputRole, links}' outputs.json
while IFS= read -r DATA_PATH; do
request "$API_BASE$DATA_PATH" | jq '{submissionId, groups}'
done < <(jq -r '.outputs[].links.data' outputs.json)Each output identifies its run step, form and submission. Select outputs by those IDs when your application needs a particular result. links.data returns the current editable values for that output submission.
Credit memo
Use an analysis step configured to write the memo into a string-long field named CreditMemo. Set MEMO_FORM_ID to that step's output formId from steps[].outputForms[] in the pipeline list.
GET /v2/pipelines/runs/{runId}/outputs identifies the memo submission:
json
{
"runId": "run-1",
"pipelineId": "pipeline-1",
"dealId": "deal-1",
"runRefId": null,
"outputs": [
{
"runStepId": "run-step-1",
"stepId": "step-1",
"stepRole": "analysis",
"outputRole": null,
"label": null,
"status": "completed",
"submissionId": "memo-submission-1",
"formId": "memo-form-1",
"links": { "data": "/v2/submissions/memo-submission-1/data" }
}
]
}Read the first output matching MEMO_FORM_ID through links.data and save its memo value as UTF-8 text:
sh
MEMO_FORM_ID="YOUR_MEMO_FORM_ID"
MEMO_DATA_PATH=$(jq -er --arg form "$MEMO_FORM_ID" \
'first(.outputs[] | select(.formId == $form)) | .links.data' outputs.json)
request "$API_BASE$MEMO_DATA_PATH" > memo.json
jq -er '.groups[].items[] | select(.formField.name == "CreditMemo") | .value' \
memo.json > credit-memo.txtThe data response contains the memo in groups[].items[]:
json
{
"id": "memo-item-1",
"formField": {
"id": "memo-field-1",
"name": "CreditMemo",
"type": "string-long"
},
"value": "Credit assessment\nThe case meets the configured lending criteria."
}Document input
Start the run before supplying its documents. SeaUpload binds to each extraction step's unique label inside that existing process. The SDK resolves the executable run step, uploads its batch and refreshes the run's outputs.
For server integrations, upload directly to the run step. Several labelled extraction steps can receive their documents within the same run. A complete upload resolves only its selected missing_upload dependency; other blockers may remain.
Read results through the existing run's output links. Submission uploads remain available for integrations that work directly with submissions.
Creation receipt
dispatchAttempt.outcome | Action |
|---|---|
accepted | Poll the run status |
not-sent, BLOCKER_SYNC_FAILED | Retain the run ID for operator recovery |
unknown, DISPATCH_UNCONFIRMED | Read run status and retain the run ID if processing does not progress |
Creation is non-idempotent. An uncertain response must be reconciled using the existing run ID before another creation request. pending, running, blocked and hibernating await progress; completed is successful; failed and cancelled are terminal failures.