Quickstart
Discover a workflow, send valid inputs, and wait for the result with copy-paste-safe curl commands.
Developers making their first Edgaze API run.
This guide uses curl, jq, and a shell such as Bash or Zsh. It deliberately reads workflow IDs, input requirements, and run URLs from API responses so you do not have to assemble them by hand.
Before you start#
You need:
- an API key with
run:executeandrun:readscopes; - enough wallet balance or a valid bundle for a paid workflow; and
- any provider setup shown by the selected workflow's
credentialModeandrequiredProvidersfields.
Create a key in Developer → API keys. The plaintext is shown only once. Put it in an environment variable and keep the quotes:
export EDGAZE_API_KEY='paste_your_api_key_here' export EDGAZE_API_BASE='https://api.edgaze.ai/v1'
The public API uses api.edgaze.ai, not the marketing-site URL. These examples use --fail-with-body, so curl returns a failure exit code for HTTP errors while still showing Edgaze's JSON error message.
1. Discover a workflow#
List current marketplace workflows for which your account has API access:
WORKFLOWS_JSON="$(
curl --fail-with-body --silent --show-error \
"$EDGAZE_API_BASE/workflows?runnableOnly=true&limit=10" \
-H "Authorization: Bearer $EDGAZE_API_KEY"
)"
printf '%s\n' "$WORKFLOWS_JSON" | jq '.workflows[] | {
id,
name,
displayedRunPriceUsd,
credentialMode,
requiredProviders
}'GET /workflows returns catalog metadata, not the input schema. Copy one id from the output:
export EDGAZE_WORKFLOW_ID='paste_workflow_id_here'
If the list is empty, remove runnableOnly=true to inspect the catalog. A result with apiRunnableNow: false cannot be started by the current account. runnableOnly checks listing access; provider-key and Plus requirements are still reported separately.
2. Inspect its inputs#
Fetch the selected workflow before constructing a run request:
WORKFLOW_JSON="$(
curl --fail-with-body --silent --show-error \
"$EDGAZE_API_BASE/workflows/$EDGAZE_WORKFLOW_ID" \
-H "Authorization: Bearer $EDGAZE_API_KEY"
)"
printf '%s\n' "$WORKFLOW_JSON" | jq '{
name,
displayedRunPriceUsd,
credentialMode,
requiredProviders,
inputSchema
}'Build an inputs object using the exact nodeId or name from each inputSchema entry. Supply every field where required is true, use a value of the documented type, and use one of options for dropdown fields. For example:
export EDGAZE_INPUTS_JSON='{"input_node_id":"replace with a real value"}'Use {} when inputSchema is empty. This validation catches malformed local JSON before it reaches the API:
printf '%s\n' "$EDGAZE_INPUTS_JSON" | jq --exit-status 'type == "object"' >/dev/null
3. Start one run#
Create one idempotency key and reuse it if the POST must be retried. A new key intentionally creates a new, potentially billable run.
export EDGAZE_IDEMPOTENCY_KEY="quickstart-$(date +%s)-$$"
REQUEST_BODY="$(
jq --null-input --compact-output \
--arg workflow "$EDGAZE_WORKFLOW_ID" \
--arg idempotencyKey "$EDGAZE_IDEMPOTENCY_KEY" \
--argjson inputs "$EDGAZE_INPUTS_JSON" \
'{workflow: $workflow, inputs: $inputs, idempotencyKey: $idempotencyKey}'
)"
RUN_JSON="$(
curl --fail-with-body --silent --show-error \
-X POST "$EDGAZE_API_BASE/runs" \
-H "Authorization: Bearer $EDGAZE_API_KEY" \
-H 'Content-Type: application/json' \
--data "$REQUEST_BODY"
)"
printf '%s\n' "$RUN_JSON" | jq .
export EDGAZE_RUN_ID="$(printf '%s\n' "$RUN_JSON" | jq --raw-output --exit-status '.run.id')"
export EDGAZE_STATUS_URL="$(printf '%s\n' "$RUN_JSON" | jq --raw-output --exit-status '.run.statusUrl')"
export EDGAZE_STREAM_URL="$(printf '%s\n' "$RUN_JSON" | jq --raw-output --exit-status '.run.streamUrl')"A 202 Accepted response means the run was created, not that it succeeded. Keep the returned URLs: they already contain the correct API host and run ID.
4. Poll until terminal#
The following loop waits for completed, failed, or cancelled, and stops after about five minutes. pending, running, and suspended are non-terminal states.
EDGAZE_TERMINAL_STATUS=''
for ((attempt = 1; attempt <= 150; attempt++)); do
RUN_STATE="$(
curl --fail-with-body --silent --show-error \
"$EDGAZE_STATUS_URL" \
-H "Authorization: Bearer $EDGAZE_API_KEY"
)" || break
STATUS="$(printf '%s\n' "$RUN_STATE" | jq --raw-output --exit-status '.status')" || break
printf 'status=%s\n' "$STATUS"
case "$STATUS" in
completed)
EDGAZE_TERMINAL_STATUS="$STATUS"
printf '%s\n' "$RUN_STATE" | jq '{status, displayedChargeUsd, outputs}'
break
;;
failed|cancelled)
EDGAZE_TERMINAL_STATUS="$STATUS"
printf '%s\n' "$RUN_STATE" | jq '{status, reason, displayedChargeUsd}'
break
;;
esac
sleep 2
done
if [ -z "$EDGAZE_TERMINAL_STATUS" ]; then
printf 'Run did not reach a terminal state in this polling window. Continue with: %s\n' "$EDGAZE_STATUS_URL"
fiDo not treat 202 as success, and do not treat suspended as failure. Branch on the final status; for a failed run, reason is a sanitized explanation suitable for logs or user-facing error handling.
Optional: stream progress#
SSE is useful for live progress. Polling remains the simplest durable integration.
curl --fail-with-body --no-buffer --silent --show-error \ "$EDGAZE_STREAM_URL" \ -H "Authorization: Bearer $EDGAZE_API_KEY"
The stream starts with a snapshot, sends run.status and node lifecycle events, emits heartbeat comments while idle, and closes after the terminal snapshot. curl does not reconnect automatically. After a disconnect, reconnect with the last numeric SSE id you processed:
export EDGAZE_LAST_EVENT_ID='paste_last_processed_event_id_here' curl --fail-with-body --no-buffer --silent --show-error \ "$EDGAZE_STREAM_URL" \ -H "Authorization: Bearer $EDGAZE_API_KEY" \ -H "Last-Event-ID: $EDGAZE_LAST_EVENT_ID"
Process events idempotently because a client can disconnect after receiving an event but before saving its cursor.
Common first-run errors#
| HTTP or status | Meaning | Next action |
|---|---|---|
401 unauthorized | Missing, invalid, expired, or revoked key | Check EDGAZE_API_KEY or create a new key |
403 insufficient_scope | The key lacks the endpoint's scope | Add run:execute for POST and run:read for run reads/streams |
403 forbidden | The workflow is unavailable to this account through the API | Choose a result returned with apiRunnableNow: true |
402 spend_cap_reached | The key's spend cap rejected the POST | Raise the cap or wait for its window to reset; no run was created |
429 rate_limited | Too many create-run requests | Wait for the Retry-After response header, then retry with the same idempotency key |
status: failed after 202 | Preparation, wallet, provider, or execution failed asynchronously | Inspect reason; retry only when appropriate and use a new idempotency key for a genuinely new run |
See Create Run for the complete request contract, Streaming for SSE event behavior, and Errors for synchronous versus asynchronous failures.
Was this useful?
Your response helps us improve the documentation.