# Changelog

Changes to the public API, the scenario grammar, bundles and scoring. Newest first.

## 2026-10-17: why a verification call was not answered

- `last_attempt` of `GET /targets/{id}/verification` has three new fields: `sip_status` and
  `sip_reason` (the carrier's answer when the line never picked up: 480 unavailable, 486
  busy, 603 declined, 404 unknown number...) and `failure_hint`, what to fix before the next
  attempt, in plain words.
- New fields `attempts_max` and `attempts_reset_at` (when the oldest failed attempt stops
  counting). A call the line does not answer still counts as a failed attempt.
- The dashboard and the MCP tools `get_number_status` and `place_verification_call` explain
  the failure and say how many attempts are left.
- See [When the verification call fails](number-verification.md#when-the-verification-call-fails):
  our calls come from a US number (+1), which some carriers and call-screening features block.

## 2026-10-11: support tickets

- Ask the CallQA team from your coding agent: MCP tools `contact_support`,
  `list_support_tickets`, `get_support_ticket` and `reply_support_ticket`. A person answers,
  usually within a few hours; the answer reaches the agent, the app and your email.
- REST API: `GET`/`POST /support/tickets`, `GET /support/tickets/{id}`,
  `POST /support/tickets/{id}/messages`, `POST /support/tickets/{id}/close`. Any key scope
  can open a ticket; guests read. At most 20 new tickets a day per organization.
- `get_setup_status` has a new field `support` (how to reach us, answers not read yet), and
  `links.support`. Secrets pasted in a ticket are replaced by `[redacted secret]`.
- A `429 rate_limited` error can now carry a more precise `detail`.
- See [Getting help](support.md).

## 2026-10-11: compliance review of scenarios

- Every scenario is reviewed against the Acceptable Use Policy before it can call anyone, and
  again when its content changes. Only an allowed scenario runs; a refused one shows its
  reasons (category, the words of the scenario, what to change), a doubtful one is held for
  a human review by CallQA staff. See [Compliance review of scenarios](compliance.md).
- `ScenarioOut` (`POST`, `PUT` and `GET /scenarios/{id}`) has a new field `compliance`; the
  MCP tools `create_scenario`, `update_scenario` and `get_scenario` return it too.
- `POST /scenarios/{id}/runs` on a held or refused scenario answers `403 blocked_policy`.
  New call `block_reason` values: `compliance_blocked`, `compliance_review`. A call can wait
  `queued` a few seconds while the review runs.
- More numbers are never called: emergency and public safety numbers of every country code
  (911, 988, N11, 999, 101, 111, 112, 15, 17, 18, 115, 119, harmonised 116xxx...), and
  international premium rate (+979) and satellite networks (+870, +881, +882, +883).

## 2026-10-09: free trial

- A new organization comes with 10 free test calls to try CallQA, no card needed (plan
  `trial`, the calls are `bonus_remaining` in `GET /usage`). Only the first organization a
  person creates gets it. See [Free trial](billing.md#free-trial).

## 2026-10-09: grace period on a failed renewal

- A subscription whose renewal payment failed (`past_due`, while Stripe retries for up to
  about 2 weeks) keeps its plan: calls and the API work as usual, instead of ending as
  `subscription_inactive`. Only the cancellation after the last retry takes the plan away.
  See [When a renewal payment fails](billing.md#when-a-renewal-payment-fails).
- `GET /billing/subscription` has a new field `payment_retry_until`: the deadline to update
  the card, `null` when no payment is pending.

## 2026-10-08: MCP setup tools, docs search, seat limit as a plan error

- **13 setup tools** on the MCP server, so a coding agent can take an organization from zero
  to scheduled regression tests without the dashboard: `get_setup_status`,
  `create_environment`, `list_numbers`, `add_phone_number`, `get_number_status`,
  `start_number_verification`, `place_verification_call`, `set_schedule`,
  `list_schedules`, `list_webhooks`, `configure_webhook`, `create_alert_channel` and
  `get_ci_setup` (GitHub Actions or GitLab CI files for your scenarios). Same scopes, plan
  limits, verification rules and wallet rules as the REST API.
- Prompt `set-up-callqa`: the setup in order, saying where a person must act (sign the
  attestation of a number, make the line say the verification code, pay, create keys).
  See [MCP server](mcp.md#onboarding-with-an-agent).
- `POST /invitations` with every seat taken answers `403 feature_not_in_plan` (`feature:
  seats`, with `required_plan` and `upgrade_url`), like the other plan limits, instead of
  `400 not_allowed`.
- Importing a scenario whose `environments` names an environment your organization does not
  have is still refused (`422 invalid_scenario`); the error is now on `environments.<slug>`
  and lists your environments and how to create one.
- A call with no result is failed after its own `limits.max_duration_s` plus a margin (40
  minutes at least), and a run left `running` while all its calls are finished is completed.
- Runs are called runs everywhere (dashboard, alerts, CLI summary, API summaries). Webhook
  events keep their names (`suite_run.*`, `suite_run_id`).
- The docs have a search: `/docs/search/?q=`.

## 2026-10-02: MCP server

Additions only.

- **MCP server** on `https://app.callqa.dev/mcp` (Streamable HTTP), authenticated with your
  API keys: 15 tools (scenarios, environments, versions, runs, reports, calls, exports for
  LLMs, the scenario assistant, usage), the scenario grammar and examples as resources, and
  3 prompts. Same scopes, IP restrictions, rate limits and journal as the REST API. See
  [MCP server](mcp.md).

## 2026-09-27: versions, schedules per environment, free tags, billing forecast

Additions, and deprecated aliases kept until 2027-03-31.

### Versions replace releases

A release becomes a **version** of your code in one environment, with git fields. Existing
releases were converted in place: same ids, same runs.

- `/versions` (list, create, read, edit, delete) and `POST /versions/{id}/promote`. A version
  has `label`, `environment`, `deployed_at`, `git_ref`, `git_sha`, `source_url`, `notes`,
  `target_id` and `tags`. Runs of an environment placed after `deployed_at` are attributed to
  it until the next version.
- `POST /scenarios/{id}/runs` takes `version`, `git_ref`, `git_sha`, `source_url`; run
  responses carry `version` and `version_id`; `GET /runs?version_id=`.
- `GET /environments/compare` takes `a_version` / `b_version`.
- Webhook events `version.created` and `version.promoted`.
- **Deprecated** (sunset 2027-03-31): `/releases` and `POST /releases/{id}/promote` (they
  answer with `Deprecation` and `Sunset` headers), the `release` field of the trigger request
  and of run responses, `a_release` / `b_release`, and the events `release.created` /
  `release.promoted` (an endpoint subscribed to them still receives them). The CLI
  `--release` flag and the GitHub Action `release` input became `--code-version` and
  `version`.

### Scenarios per environment

- A scenario is activated per environment with its own schedule, time zone and call window:
  `GET /scenarios/{id}/environments`, `PUT` and `DELETE /scenarios/{id}/environments/{env}`,
  `GET` and `POST /environments/{env}/scenarios` (bulk), `GET /matrix` (scenario x
  environment, and what passes per version).
- Scenario grammar: optional `environments` map, keyed by environment slug, with `enabled`,
  `schedule`, `timezone` and `call_window`. The top-level `schedule`, `timezone` and
  `call_window` stay the plan of the default environment. Same `schema_version: 1`.
- The former per scenario schedule moved to the default environment.

### Tags, billing

- Tags are free keywords on scenarios, runs, versions and numbers: `GET /tags?q=`
  (autocomplete, with `uses`), `POST /tags/bulk`.
- `GET /billing/forecast` (what the schedules will use this month), `GET /billing/referral`,
  and on `/billing/settings`: `allow_paid_overage`, `on_limit` (`block_calls` or
  `pause_schedules`) and `schedules_paused`.

## 2026-09-27: environments, exports for LLMs, webhook scopes

Additions only.

- **Environments**: `/environments` (CRUD, `PUT /environments/{env}/numbers`,
  `GET /environments/stability`, `GET /environments/compare`). See
  [Environments](environments.md).
- `environment` on `POST /scenarios/{id}/runs`, `POST /releases`, and as a filter on
  `GET /runs`, `/calls`, `/releases`; `environment` (slug) in run and release responses.
- `POST /releases/{id}/promote` tags a release in another environment.
- Release versions are unique per environment (they were unique per organization).
- **Exports for LLMs**: `GET /calls/{id}/llm-export`, `/runs/{id}/llm-export`,
  `/scenarios/{id}/llm-export` (Markdown or compact JSON). See
  [Replay and bundles](replay.md#export-a-failure-for-an-llm).
- **Webhook scopes**: `filters` (`scenario_ids`, `tags`, `environments`) on
  `POST`/`PATCH /webhooks`, returned by every webhook endpoint. New events
  `call.regressed`, `call.recovered`, `suite_run.started`, `release.created`,
  `release.promoted`; call and run payloads gain `scenario_id`, `environment`, `release`,
  `tags` (and `variant_id` for calls). `score.dropped` now compares runs of the same
  environment. See [Webhooks](webhooks.md#filter-an-endpoint-by-scenario-tag-or-environment).

## 2026-09-26: API v1 additions

Additions only, except the stricter webhook events noted below.

- **Alerts**: Slack (incoming webhook) and email channels with rules on failure, score and
  latency, `/alert-channels` (CRUD and `test`). See [Alerts](alerts.md).
- **Tags, releases, webhooks**: `GET` and `PATCH` on `/tags/{id}`, `/releases/{id}` and
  `/webhooks/{id}` (pause a webhook with `enabled: false`).
- **Deletes**: `DELETE /runs/{id}` and `DELETE /calls/{id}` (admin); billing lines are kept
  without the calls' content.
- **Webhook secret rotation**: `POST /webhooks/{id}/rotate-secret`, with a grace period during
  which deliveries carry two `v1` signatures. Accept a delivery if any `v1` matches.
- **`wallet.low_balance`** is now sent, with a threshold per organization.
- **API keys**: IP restriction (`allowed_cidrs`), `GET` and `PATCH /api-keys/{id}`, in-place
  rotation with a grace period (`POST /api-keys/{id}/rotate`); `last_used_ip` in responses.
- **Billing**: `GET` and `PATCH /billing/settings` (monthly spend cap, low balance threshold),
  `GET /plans`, `GET /billing/subscription`, `POST /billing/subscription/checkout`,
  `POST /billing/portal`.
- **Audit log**: `GET /audit-log` (admin).
- **Errors**: every error has a machine-readable `code` (`missing_scope`,
  `feature_not_in_plan`, `ip_not_allowed`, `already_exists`...); `code` is never `null`
  any more. See [Errors](errors.md).
- **OpenAPI**: stable, readable `operationId`s (`targets_create`, `runs_trigger`...), and
  `401`, `403`, `404`, `422`, `429` declared on every operation. Client generators produce
  readable method names; regenerate your client once.
- `POST /wallet/checkout`: the schema now states the real range (`2000` to `500000` cents);
  out of range answers `422`.
- `?wait=true` waits asynchronously on the server; same contract (`200`, `412`, `202`).
- Failed authentications from an IP no longer block valid keys used from the same IP.
- Webhooks: an unknown event name is now refused (`400`, `unknown_event`) instead of being
  silently dropped.
- [Deprecation policy](versioning.md#deprecation-policy) with `Deprecation` and `Sunset`
  headers. The developer docs are served on `/docs/`.

## 2026-09-26: API v1 (1.0.0)

First public version.

- REST API `/api/v1`: organization, members and invitations; targets and number verification;
  scenarios (JSON and YAML import/export, validation, generation), variants (manual,
  auto-derived, from a call); suite runs with a CI mode (`?wait=true&threshold=N`, answers
  `200`, `412` or `202`); calls, transcripts and traces; replay bundles and replays; tags and
  releases; webhooks with HMAC-SHA256 signatures and retries; API keys with scopes and the API
  journal; usage, prepaid wallet and top-ups.
- Scenario grammar `schema_version: 1`, with the callqa.dev short form and `x_*` extension
  fields. JSON Schema at `GET /api/v1/scenarios/schema`.
- Replay bundle `bundle_version: 1`.
- Webhook events: `call.completed`, `call.failed`, `call.blocked`, `suite_run.completed`,
  `suite_run.failed`, `score.dropped` (`wallet.low_balance` reserved at the time).
