---
title: "Create a test case"
method: POST
path: "/api/cases"
tags: ["Test Cases"]
---

# Create a test case

`POST /api/cases`

## Request

- Base URL: `https://aximo.autify.com`
- URL: `https://aximo.autify.com/api/cases`
- Auth: API key in header `x-api-key`
- TypeScript: <https://skmtc.dev/autify/apis/aximo-api/docs/api/cases/post.ts> (a function with typed inputs; its response is checked against the schema)

Creates a saved test case in a workspace. Cases created via the API have
**API access enabled by default**, so they can be triggered immediately with
`POST /api/triggers/cases/{caseId}/run`.

**Default targets.** `apiMobileConfig`, `apiWebConfig`, `apiDesktopConfig`
and `apiMultiDeviceConfig` can be set at creation, in the same shapes, with
the same encrypted tokens and under the same feature gates and validation
as `PATCH /api/cases/{caseId}`, so a mobile case is runnable in one call.
A rejected config creates nothing; the trigger's flat device fields belong
inside `apiMobileConfig`.

## Request body

- object
  - `projectId` string, uuid, required: ID of the workspace to create the case in.
  - `scenario` string, required: Test scenario text (Gherkin, markdown, or plain text).
  - `type` 'web' | 'mobile' | 'desktop' | 'multi_device': Test case type. `multi_device` requires the organization's multi-device feature (403 otherwise).
  - `title` string: Case title. Defaults to the first line of the scenario.
  - `description` string
  - `format` 'gherkin' | 'markdown' | 'plain_text': Scenario format.
  - `startUrl` string, uri, nullable: Starting URL (web/desktop cases); must be http(s).
  - `directoryId` string, uuid: Optional directory to place the case in. Get IDs from `GET /api/directories`.
  - `tags` string[]: Caller-supplied labels, for example the commit and pull request a run was testing. At most 10, each 1-64 characters after trimming; duplicates are collapsed. A request exceeding a bound is refused with 400, never truncated. Tags are returned exactly as stored and are visible to everyone in your organization, so never put secrets in them.
  - `apiMobileConfig` CaseMobileConfig: Exactly one device binding: a Device Farm device (`deviceArn` + `deviceName`) or a registered local phone (`userDeviceId` from `GET /api/devices/user`). For a local phone, `platform` and `localDeviceName` are resolved from the device row server-side and `localDeviceName` is read-only; an app reference on a local phone must carry a `bundleId`.
    - `deviceArn` string: Encrypted device identifier token. Not set for a local phone.
    - `deviceName` string
    - `userDeviceId` string, uuid: Registered local phone to run on instead of Device Farm.
    - `localDeviceName` string: Display-name snapshot of the registered local phone.
    - `platform` 'ANDROID' | 'IOS'
    - `uploadArn` string: Encrypted upload identifier token.
    - `uploadType` 'own_app' | 'existing' | 'sample'
    - `appName` string
    - `bundleId` string
    - `apps` CaseAppInfo[]
      - `uploadArn` string, required: Encrypted upload identifier token.
      - `uploadType` 'own_app' | 'existing' | 'sample', required
      - `appName` string, nullable, required
      - `bundleId` string
  - `apiWebConfig` CaseWebConfig
    - `hostnameOverrideIds` string[]
  - `apiDesktopConfig` object, nullable: Default BYOD desktop target. Requires BYOD.
    - `userDeviceId` string, uuid, required: A registered BYOD desktop device from `GET /api/devices/user`.
  - `apiMultiDeviceConfig` CaseMultiDeviceDevice[], nullable: Multi-device targeting (2-3 entries). Requires the multi-device feature; local entries also require BYOD.
    - union
      - CaseMultiDeviceWebDevice
        - `kind` 'web', required
        - `name` string, required
        - `startUrl` string, nullable
        - `userDeviceId` string, uuid: When set, this entry runs on the user's registered desktop device.
        - `localDeviceName` string: Display-name snapshot of the registered device, resolved when the config was saved.
      - CaseMultiDeviceMobileDevice: On input, exactly one of a Device Farm device (`deviceArn` + `deviceName`) or a registered local phone (`userDeviceId`) is required; they cannot be combined. A `userDeviceId` entry that carries `uploadArn`/`apps` must include a `bundleId` (top-level or on `apps[0]`), and a top-level `bundleId` must match `apps[0].bundleId`. The same `userDeviceId` may appear only once across entries.
        - `kind` 'mobile', required
        - `name` string, required
        - `mobilePlatform` 'android' | 'ios', required
        - `deviceArn` string: Encrypted device identifier token.
        - `deviceName` string
        - `userDeviceId` string, uuid: When set, this entry runs on the user's registered phone.
        - `localDeviceName` string: Display-name snapshot of the registered device, resolved when the config was saved.
        - `uploadArn` string: Encrypted upload identifier token.
        - `uploadType` 'own_app' | 'existing' | 'sample'
        - `appName` string
        - `bundleId` string
        - `apps` CaseAppInfo[]
          - `uploadArn` string, required: Encrypted upload identifier token.
          - `uploadType` 'own_app' | 'existing' | 'sample', required
          - `appName` string, nullable, required
          - `bundleId` string

## Response `201`

Case created.

- object
  - `success` boolean, required
  - `caseId` string, uuid, required
  - `unregisteredPlaceholders` UnregisteredPlaceholders: Advisory, present only when the scenario references `{{VARIABLE}}`, OTP or file placeholders the workspace has not registered. The case is created regardless.
    - `variables` string[], required
    - `otps` string[], required
    - `files` string[], required
  - `embeddedCode` EmbeddedCodeAdvisory: Advisory, present only when the scenario contains embedded code (scripts, shell commands or fenced blocks). The case is created regardless.
    - `kinds` string[], required
    - `emailRelated` boolean, required
    - `suggestEmailTestingContact` boolean, required

## Other responses

- `400`: Invalid request body. Schema failures carry the zod error tree in `details`; an undecryptable token carries `details.path`; fields this endpoint does not define carry `details.unknownFields` and `details.hint`.
- `401`: Missing or invalid API key.
- `403`: The API key's user is not a member of the organization, or the case type or a config needs a feature the organization does not have (multi-device for `multi_device` and `apiMultiDeviceConfig`, BYOD for a local device).
- `404`: Project, directory, device or upload not found.
- `429`: Rate limit exceeded — e.g. the daily session limit was reached for the organization, or too many API requests were sent in a short window (retry after the number of seconds in the `Retry-After` header).
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/autify/apis/aximo-api.md) - [All operations](https://skmtc.dev/autify/apis/aximo-api/llms.txt) - [OpenAPI document](https://skmtc.dev/autify/apis/aximo-api/revisions/590722011284?raw)
