Skip to main content
Convex provides real-time run state, ordered step tracking, asset storage, and execution logs for all live Zap runs. Every stage of a pipeline — from the initial POST /api/zaps/run through provider polling to final asset delivery — is recorded in Convex and updated idempotently. Upstash Redis works alongside Convex to manage polling queues and enforce idempotency across retries.
Mock CLI runs (ZAP_PROVIDER=mock) do not require a Convex deployment. Only web live runs — where a real provider job is submitted and polled — need the full Convex + Upstash stack.

Table Schema

The Convex schema (convex/schema.ts) defines six tables:

zaps

Installed and discoverable recipe metadata. Each record represents a Zap definition that has been published or saved as a draft.
FieldTypeDescription
slugstringURL-safe unique identifier for the Zap
sourcestringRaw Zap.md source content
versionnumberMonotonically increasing version counter
status"draft" | "published"Visibility state
estimateUsdnumberEstimated cost in USD for a single run
tagsstring[]Searchable topic tags
authorIdstring (optional)Wallet address or user ID of the creator
Indexes: by_slug, by_status

runs

Run status, creator input summary, budget tracking, and provider mode for each execution.
FieldTypeDescription
runIdstringUnique run identifier
zapSlugstringSlug of the Zap being executed
zapVersionnumberVersion of the Zap at run time
status"queued" | "running" | "waiting" | "done" | "failed"Current run lifecycle state
inputsanyCreator-supplied input parameters
costUsdnumberAccumulated cost in USD
startedAtnumberUnix timestamp (ms) when the run started
finishedAtnumber (optional)Unix timestamp (ms) when the run completed
stagestring (optional)Human-readable current pipeline stage label
userIdstring (optional)Authenticated user ID
sessionIdstring (optional)Browser or API session identifier
zapUrlstring (optional)Public URL for the run’s output
errorstring (optional)Error message if the run failed
Indexes: by_runId, by_status, by_zap

steps

Ordered pipeline step state for each run. One record per step per run.
FieldTypeDescription
runIdstringParent run identifier
stepIdstringUnique step identifier within the run
kindstringStep type (e.g. image_gen, video_stitch)
status"queued" | "running" | "done" | "failed" | "skipped"Step lifecycle state
progressnumberCompletion progress from 0 to 1
priceQuoteUsdnumberEstimated cost for this step
actualUsdnumber (optional)Actual cost charged by the provider
providerstring (optional)Provider used for this step (e.g. gmi, fal)
modelstring (optional)Model or pipeline variant used
providerRequestIdstring (optional)Provider’s own job/request ID for polling
idemKeystring (optional)Idempotency key for Upstash deduplication
errorstring (optional)Error message if this step failed
Indexes: by_run, by_step, by_status

assets

Generated outputs produced during a run: images, video clips, audio files, and stitched results.
FieldTypeDescription
runIdstringParent run identifier
stepIdstringStep that produced this asset
kind"png" | "mp4" | "wav" | "json"Asset media type
urlstringPublic URL for the asset
storageKeystring (optional)Vercel Blob storage key
parentsstring[]Asset IDs this output was derived from
widthnumber (optional)Width in pixels (images/video)
heightnumber (optional)Height in pixels (images/video)
durationSnumber (optional)Duration in seconds (audio/video)
Indexes: by_run, by_step

feedback

Creator ratings, RLHF votes, and VLM judge scores used as eval signals.
FieldTypeDescription
runIdstringRun this feedback applies to
kind"rlhf_vote" | "judge_score"Feedback category
rater"human" | "vlm"Source of the rating
scoresanyStructured score payload
stepIdstring (optional)Step-level feedback target
commentstring (optional)Free-text annotation
Indexes: by_run, by_step

cronLogs

Poller and drain execution logs. Written after each scheduled or triggered drain cycle.
FieldTypeDescription
jobNamestringIdentifier for the cron or drain job
status"success" | "partial" | "failed"Outcome of the run cycle
startTimenumberUnix timestamp (ms) when the job started
endTimenumberUnix timestamp (ms) when the job finished
durationnumberElapsed time in milliseconds
processedCountnumberNumber of poll jobs processed
errorCountnumberNumber of errors encountered
errorstring (optional)Last error message, if any
Indexes: by_job, by_startTime, by_status

Runtime Flow

Each live run follows this sequence through the stack:
POST /api/zaps/run
  -> validate Zap.md
  -> create run + steps        (Convex)
  -> submit provider job       (GMI / Fal / ...)
  -> enqueue Upstash poll job  (Upstash Redis)
  -> drain endpoint polls provider
  -> update Convex idempotently
  1. The API route validates the Zap.md recipe and resolves creator secrets from Supabase
  2. A runs record and one steps record per pipeline stage are written to Convex
  3. The provider job is submitted; the returned providerRequestId is stored on the step
  4. An Upstash job is enqueued with the step’s idempotency key (idemKey)
  5. The drain endpoint (/api/providers/poll/drain) is called by Upstash on a schedule, polling the provider for status
  6. Results are written back to steps and assets in Convex; the runs record is updated to reflect the final status

Configuration

Required Environment Variables

VariableDescription
NEXT_PUBLIC_CONVEX_URLPublic Convex deployment URL — used by the browser client for real-time subscriptions
CONVEX_URLServer-side Convex URL — used by Next.js API routes for mutations and queries

Upstash Integration

Convex and Upstash Redis work together to provide idempotent polling queues. Configure Upstash in both your Vercel environment and any Convex actions that enqueue jobs:
VariableDescription
UPSTASH_REDIS_REST_URLUpstash Redis REST endpoint URL
UPSTASH_REDIS_REST_TOKENUpstash Redis REST authentication token

Poll Drain Endpoint

The drain endpoint is the bridge between Upstash and Convex. Set these in Vercel:
VariableDescription
ZAP_POLL_DRAIN_URLFull URL of the drain endpoint, e.g. https://zap.wzrd.tech/api/providers/poll/drain
ZAP_POLL_DRAIN_SECRETShared secret added to drain requests so the endpoint can reject unauthorised callers
Set ZAP_POLL_DRAIN_SECRET in both Vercel (where the endpoint runs) and in the Convex environment (or Upstash job config) that enqueues drain calls.

Local Development Setup

After cloning and installing dependencies, regenerate the Convex client types and confirm your deployment target:
# Regenerate Convex TypeScript client from the live schema
npm run convex:codegen

# Inspect the current Convex deployment info
npm run eve:info
convex:codegen must be re-run whenever convex/schema.ts changes to keep the typed client in sync with the deployed schema.