> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prodbreak.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Force a branch

> Drive a workflow down its success or failure arm on demand — without inventing a path that can't happen.

Lots of API workflows **branch**: a payment either captures or declines, an identity check either
verifies or fails, a transcription either completes or errors. Each branch produces a *different*
downstream sequence — different webhooks, different fields, a different final state.

ProdBreak lets you pick **which arm runs**, on demand, so you can test the failure path as easily as
the happy one — the path that's a nightmare to trigger against the real vendor.

## You pick the arm; you never invent one

The branches a workflow can take are part of the pack — they're the same forks the real API has. You
choose **which lawful arm** runs; you can't add an arm or reshape the sequence. That's the same
[causes-not-effects](/concepts/causes-not-effects) rule applied to forks: you steer among real
outcomes, you don't puppeteer impossible ones.

A branch is chosen through the **same surface you use for [values you control](/concepts/exogenous)** —
there's no separate "branch" verb to learn. You pin the fork's outcome, and ProdBreak runs the rest
of that arm faithfully.

```ts theme={null}
// take the FAILURE arm of an identity-verification workflow
await sandbox.exogenous.on("identity.verification", "branch", "failed");

// the arm's data is yours to define too — here, why it failed
await sandbox.exogenous.on("identity.verification", "output.reason", "document_expired");

const run = await idv.verifications.create({ userId: "usr_42" });
await sandbox.clock.advance("0s");            // drain the workflow inline (see Deterministic CI)
// → the "verification.failed" webhook fires, status lands on `failed`, output.reason is set
```

Swap `"failed"` for `"verified"` and the **success** arm runs instead — its webhook, its fields, its
final state. Same workflow, both paths, your choice.

## Success arm vs failure arm

The two arms usually fill **different fields**, exactly like production:

|              | Success arm                                        | Failure arm                                                              |
| ------------ | -------------------------------------------------- | ------------------------------------------------------------------------ |
| Final status | `completed` / `verified` / `captured`              | `failed` / `declined`                                                    |
| Webhook      | `…​.completed`                                     | `…​.failed`                                                              |
| Payload      | the success output (a transcript, a balance) binds | the error data (`reason`, `code`) is set; the success output never binds |

You define the out-of-control values on **whichever arm you pick** — the success payload, or the
failure reason — and ProdBreak keeps every channel (the webhook, a later `GET`, the list) agreeing on
it, just like any other [pinned value](/concepts/pins-and-trace).

## Default branch

If you don't pick, the pack's **declared default arm** runs (usually success) — so a suite that only
cares about the happy path needs zero branch setup. Pin a branch only for the tests that exercise the
other arm.

<Note>
  **"Succeed, then fail on the retry."** Making the *same* call branch differently across repeated
  attempts (a flaky third-party that fails once then succeeds) needs an ordered, sequenced choice. That
  primitive is **post-MVP** — for now, a branch choice is fixed per world (pin it, run the test, reset).
  Most failure-path tests only need one arm at a time.
</Note>
