Dev panel

The Dev panel is how you populate, evolve, and wipe the sandbox. Three buttons drive the entire workflow: Generate, Advance lifecycle, and Reset. Each is also a single HTTP endpoint, so agents drive the same actions from the API without opening the portal.

Generate

Creates a batch of synthetic transactions plus a configurable proportion of disputes, evidence-required records, and the matching payment-event timeline.

POST /v1/dev/generate

FieldTypeConstraint
countinteger1 – 20,000 (API keys: 1 – 500)
dispute_ratenumber0 – 1 (e.g. 0.15 = 15%)
currencystringUSD | EUR | GBP | CAD | AUD | JPY
range_daysinteger1 – 365 (spreads created_at over the last N days)
seedintegeroptional; the same seed and parameters give the same shapes
lifecyclestringauto | manual (default auto for people, manual for API keys)

Card-brand distribution: ~60% Visa, ~30% Mastercard, ~7% Amex, ~2% Discover, ~1% JCB. Cardholder names and merchants are drawn from fixed synthetic sets that pass format checks but are never real parties.

Generate at volume

POST /v1/dev/generate answers 202 with the job (gj_…) at once. The rows are created in the background in chunks of 500 transactions, which survive deploys and restarts, so you can keep working in the portal (a progress card in the corner follows the job while you use other pages) or poll the job from a script.

GET /v1/dev/generate/:id

FieldMeaning
statuspending (no chunk has run yet), running, then completed, failed or canceled.
progress{done, total, unit: "transactions", pct}: transactions committed so far of the total; pct is a whole percent, rounded down.
started_atWhen the first chunk started; null while pending.
eta_atEstimated finish while running, from the recent throughput; null until two chunks have committed, and once the job has ended.
error_codeWhy it did not complete: generate_failed, job_lease_expired, canceled or tenant_data_limit (branch on it, not on the error sentence).
result{transactions, disputes} once completed.
  • Limits. A person in the dev panel may generate up to 20,000 transactions per job, and the workspace may have 20,000 in flight across its unfinished jobs. API keys may ask for 500 per job and together hold at most 5,000 of those 20,000. Over the budget, a new generate answers 409 generate_in_progress with Retry-After.
  • Cancel. POST /v1/dev/generate-jobs/:id/cancel stops a pending or running job: its remaining chunks are canceled and it ends canceled, keeping the transactions of the chunks that already committed (rows_done in the response). Clean them up right away. A job that already ended is returned unchanged.
  • Seeds. Each chunk draws its rows from the job's seed and its own position, so the same seed and parameters reproduce the same shapes (merchants, amounts, statuses, reason codes) chunk by chunk, even when a chunk is retried. Ids are always new and timestamps are relative to the run; shapes may change between API versions.
  • Every chunk is a scheduled job: GET /v1/scheduled-jobs?generate_job_id=gj_… lists them (see Flows).

Clean up one job

POST /v1/dev/generate-jobs/:id/cleanup

Deletes exactly what one job created (transactions, their disputes, dispute events, evidence and payment events) and nothing else. A job still running is canceled first. A job of up to 2,000 transactions is cleaned up in the request (200 with the counts). A bigger one is cleaned up in the background in chunks of 500: the call answers 202 with {id, state, scheduled_job_id}, and the generate_job.cleanup audit row with the totals is written when the last chunk commits. Send {"async": false} to always clean up in the request, or {"async": true} to always do it in the background. Calling it again while a background cleanup runs returns that cleanup (202), or 409 cleanup_in_progress with async: false.

Advance lifecycle

Runs the hourly background job on demand. Useful when you don't want to wait for the cron tick. It does three things:

  • Expires rfi_open disputes past their RFI window → rfi_expired.
  • Expires evidence_required disputes past their respond_by → expired.
  • Rules on under_review disputes whose 55-day issuer window has elapsed: ~60% → won, ~40% → lost.

POST /v1/dev/advance-lifecycle

Returns { rfi_expired, expired, ruled } — counts of rows in each transition so the UI can show what moved.

Reset

Wipes the synthetic data inside your tenant — transactions, disputes, evidence records, payment events, reports. Your account, your workspace, and any team members survive.

POST /v1/dev/reset

The reset is scoped to the calling tenant. Other tenants on the same instance are not affected.

It runs in the background: the call answers 202, unfinished generate jobs are canceled, and the data is deleted in batches of 1,000 rows per table, each in its own short transaction. While it runs, a new generate answers 409 reset_in_progress and another reset returns the one in progress. The audit trail is kept; the reset is recorded once, as tenant_data.reset with the totals, when it finishes. Only the owner can reset, never an API key: tests clean up their own jobs instead.