Skip to content

DocsIntegrations

curl

Every call of the round trip from a shell: upload a file, create a job from JSON, wait for it and download the outputs.

What you build#

A shell script that uploads a local file, creates a job from a JSON body, waits for the job to end and saves its outputs. It is the shortest way to see every call and every response; the same calls are what the other guides make from their servers. It uses plain HTTP with curl and reads the responses with jq.

The whole project: videxo-curl.zip, or browse it in the examples repository (opens in a new tab).

A shell cannot receive webhooks. To verify them, follow a server guide: Express, Next.js or SvelteKit.

Before you start#

  • An API key from the dashboard's API keys page, in VIDEXO_API_KEY.
  • curl and jq.

Install#

Nothing to install beyond curl and jq. Unpack the project and make the script executable:

bash
chmod +x videxo.sh

Create a job#

The JSON bodies sit in requests/: one MP4 through POST /v1/transcode, and an MP4, a poster and a GIF preview in one job through POST /v1/jobs. The script puts the upload in as the input with jq and sends an Idempotency-Key, so running the same call again returns the same job:

examples/curl/videxo.sh · plain HTTP
# The body from requests/, with the upload as its input. The Idempotency-Key makes a retry safe: the
# same key answers the same job, never a second one.
if [ "$kind" = jobs ]; then
  body=$(jq --arg input "$input" '.inputs.talk = $input' "$here/requests/jobs.json")
  path=/v1/jobs
else
  body=$(jq --arg input "$input" '.input = $input' "$here/requests/transcode.json")
  path=/v1/transcode
fi
job=$(call "$api$path" -H 'Content-Type: application/json' -H "Idempotency-Key: $kind-$(jq -r .id <<< "$upload")" -d "$body")
id=$(jq -r .id <<< "$job")

Every call goes through call, which prints an error response's problem details: its status, code, detail and the field errors.

examples/curl/videxo.sh · plain HTTP
# Every error answer is problem details (application/problem+json): print its code and detail.
call() {
  local body status
  body=$(mktemp)
  # A request that gets no answer stops the script too (set -e does not reach into $(...)).
  status=$(curl -sS -o "$body" -w '%{http_code}' -H "$auth" "$@") || exit 1
  if [ "$status" -ge 400 ]; then
    jq -r '"\(.status) \(.code): \(.detail)", (.errors[]? | "  \(.pointer // .parameter // .header): \(.detail)")' "$body" >&2
    exit 1
  fi
  cat "$body"
}

Then the script reads the job every 2 seconds until it ends:

examples/curl/videxo.sh · plain HTTP
while state=$(jq -r .state <<< "$job"); [ "$state" = queued ] || [ "$state" = running ]; do
  echo "$id: $state"
  sleep 2
  job=$(call "$api/v1/jobs/$id")
done
echo "$id: $state $(jq -r '.error // empty | "\(.code): \(.message)"' <<< "$job")"

Receive the webhook#

Not from a shell: a webhook needs a public https server. Pass "webhook_url" in the body to have the job call yours when it ends, and see Webhooks for how to verify it.

Upload a file#

POST /v1/uploads with the exact size returns a one-time upload_url; one PUT of the bytes, with no API key, completes it. The upload's input_url, videxo://uploads/<id>, is the job's input:

examples/curl/videxo.sh · plain HTTP
name=$(basename "$file" | tr -c 'A-Za-z0-9_.\n-' '-')
size=$(wc -c < "$file" | tr -d ' ')
upload=$(call "$api/v1/uploads" -H 'Content-Type: application/json' \
  -d "{\"filename\":\"$name\",\"size_bytes\":$size,\"content_type\":\"application/octet-stream\"}")
# The upload URL takes one PUT and needs no API key.
curl -sS --fail-with-body -X PUT "$(jq -r .upload_url <<< "$upload")" \
  -H 'Content-Type: application/octet-stream' --data-binary "@$file" > /dev/null
input=$(jq -r .input_url <<< "$upload")

See Files for the size limit and how long an upload lasts.

Download the outputs#

GET /v1/jobs/{id}/outputs/{alias} returns a redirect to a fresh signed link; curl -L follows it:

examples/curl/videxo.sh · plain HTTP
# Each output through GET /v1/jobs/{id}/outputs/{alias}: it redirects to a fresh signed link, which
# needs no API key (curl does not send the Authorization header to another host).
for alias in $(jq -r '.outputs[].alias' <<< "$job"); do
  filename=$(jq -r --arg alias "$alias" '.outputs[] | select(.alias == $alias) | .filename' <<< "$job")
  curl -sS --fail-with-body -L -H "$auth" "$api/v1/jobs/$id/outputs/$alias" -o "$filename"
  echo "saved $filename"
done

A job's outputs[].download_url is also a signed link, valid until download_url_expires_at.

Run it#

bash
export VIDEXO_API_KEY=...       # your key
./videxo.sh talk.mp4            # one MP4
./videxo.sh talk.mp4 jobs       # MP4, poster and GIF preview in one job

Next steps#