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

# Create and update risk scenarios

> Create risk scenarios in a specific register, set custom fields, and update them via the Manage Vanta API — including the common 400 errors that trip up most integrations.

export function vibePromptBuildText(prompt, pageTitle) {
  const url = typeof window !== "undefined" && window.location ? window.location.href : "";
  const ref = url ? "\n\nReference: " + (pageTitle || "Vanta docs") + " — " + url : "";
  return prompt + ref;
}

export function vibePromptOpen(e) {
  e.preventDefault();
  e.stopPropagation();
  const link = e.currentTarget;
  const target = link.getAttribute("data-target");
  const prompt = link.getAttribute("data-prompt") || "";
  const pageTitle = link.getAttribute("data-page-title") || "";
  const URL_LIMIT = 8000;
  const text = vibePromptBuildText(prompt, pageTitle);
  let enc = encodeURIComponent(text);
  if (enc.length > URL_LIMIT) enc = encodeURIComponent(text.slice(0, 2400));
  let dest = "";
  if (target === "cursor") dest = "cursor://anysphere.cursor-deeplink/prompt?text=" + enc; else if (target === "claude") dest = "https://claude.ai/new?q=" + enc; else if (target === "chatgpt") dest = "https://chatgpt.com/?q=" + enc;
  if (!dest) return;
  if (target === "cursor") {
    window.location.href = dest;
  } else {
    window.open(dest, "_blank", "noopener,noreferrer");
  }
}

export function vibePromptCopy(e) {
  e.preventDefault();
  e.stopPropagation();
  const btn = e.currentTarget;
  const prompt = btn.getAttribute("data-prompt") || "";
  const pageTitle = btn.getAttribute("data-page-title") || "";
  const original = btn.getAttribute("data-label") || btn.innerText;
  btn.setAttribute("data-label", original);
  const text = vibePromptBuildText(prompt, pageTitle);
  navigator.clipboard.writeText(text).then(function () {
    btn.innerText = "Copied";
    setTimeout(function () {
      btn.innerText = original;
    }, 1500);
  }, function () {
    btn.innerText = "Copy failed";
    setTimeout(function () {
      btn.innerText = original;
    }, 1500);
  });
}

export function vibePromptToggle(e) {
  e.preventDefault();
  const summary = e.currentTarget;
  const panel = summary.parentElement;
  if (!panel) return;
  const body = panel.querySelector(".vibe-prompt__body");
  const chevron = summary.querySelector(".vibe-prompt__chevron");
  const isOpen = panel.getAttribute("data-open") === "true";
  const next = isOpen ? "false" : "true";
  panel.setAttribute("data-open", next);
  summary.setAttribute("aria-expanded", next);
  if (body) body.style.display = isOpen ? "none" : "block";
  if (chevron) chevron.style.transform = isOpen ? "rotate(0deg)" : "rotate(180deg)";
}

export const BuildPrompt = ({prompt, pageTitle, defaultOpen}) => <div className="vibe-prompt__panel" data-open={defaultOpen ? "true" : "false"} style={{
  marginTop: "0.85rem",
  borderRadius: "12px",
  border: "1px solid var(--vanta-border, rgba(120, 120, 130, 0.18))",
  background: "color-mix(in srgb, #5E05C4 4%, transparent)",
  overflow: "hidden"
}}>
    <button type="button" onClick={vibePromptToggle} aria-expanded={defaultOpen ? "true" : "false"} style={{
  display: "flex",
  alignItems: "center",
  gap: "0.75rem",
  width: "100%",
  padding: "0.9rem 1.1rem",
  background: "transparent",
  border: "none",
  textAlign: "left",
  cursor: "pointer",
  font: "inherit",
  color: "inherit"
}}>
      <span style={{
  display: "inline-flex",
  alignItems: "center",
  justifyContent: "center",
  gap: "0.35rem",
  padding: "0.2rem 0.55rem",
  borderRadius: "9999px",
  fontSize: "0.7rem",
  fontWeight: 700,
  letterSpacing: "0.06em",
  textTransform: "uppercase",
  color: "#5E05C4",
  background: "color-mix(in srgb, #5E05C4 12%, transparent)",
  border: "1px solid color-mix(in srgb, #5E05C4 30%, transparent)",
  whiteSpace: "nowrap",
  flexShrink: 0,
  minWidth: "9rem"
}}>
        Code this
      </span>
      <span style={{
  flex: 1,
  minWidth: 0
}}>
        <span className="text-gray-600 dark:text-gray-300" style={{
  display: "block",
  fontSize: "0.85rem",
  lineHeight: 1.45
}}>
          Generate a script or app that performs this function using the Vanta API.
        </span>
      </span>
      <span className="vibe-prompt__chevron" aria-hidden="true" style={{
  flexShrink: 0,
  display: "inline-flex",
  alignItems: "center",
  justifyContent: "center",
  width: "24px",
  height: "24px",
  color: "#5E05C4",
  transform: defaultOpen ? "rotate(180deg)" : "rotate(0deg)",
  transition: "transform 200ms ease"
}}>
        <Icon icon="chevron-down" iconType="regular" size={14} color="#5E05C4" />
      </span>
    </button>
    <div className="vibe-prompt__body" style={{
  display: defaultOpen ? "block" : "none",
  padding: "0 1.1rem 1.1rem"
}}>
      <div style={{
  margin: 0,
  padding: "0.85rem 1rem",
  borderRadius: "8px",
  background: "rgba(15, 17, 21, 0.92)",
  color: "#f4f4f5",
  fontSize: "0.78rem",
  lineHeight: 1.55,
  fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
  whiteSpace: "pre-wrap",
  wordBreak: "break-word",
  overflowWrap: "anywhere",
  overflowX: "hidden",
  overflowY: "auto",
  maxHeight: "22rem"
}}>
        {prompt}
      </div>
      <div className="not-prose" style={{
  display: "flex",
  flexWrap: "wrap",
  gap: "0.5rem",
  marginTop: "0.75rem"
}}>
        <button type="button" onClick={vibePromptCopy} data-prompt={prompt} data-page-title={pageTitle} style={{
  display: "inline-flex",
  alignItems: "center",
  gap: "0.4rem",
  padding: "0.4rem 0.85rem",
  borderRadius: "8px",
  border: "none",
  cursor: "pointer",
  fontSize: "0.8rem",
  fontWeight: 600,
  color: "#ffffff",
  background: "#5E05C4"
}}>
          <Icon icon="copy" iconType="regular" size={13} color="#ffffff" />
          Copy prompt
        </button>
        <a href="#" onClick={vibePromptOpen} data-target="cursor" data-prompt={prompt} data-page-title={pageTitle} className="vibe-prompt__link" style={{
  display: "inline-flex",
  alignItems: "center",
  gap: "0.4rem",
  padding: "0.4rem 0.75rem",
  borderRadius: "8px",
  border: "1px solid var(--vanta-border, rgba(120, 120, 130, 0.25))",
  fontSize: "0.8rem",
  fontWeight: 500,
  textDecoration: "none",
  color: "inherit",
  background: "transparent"
}}>
          <Icon icon="arrow-up-right-from-square" iconType="regular" size={11} color="#5E05C4" /><span>Cursor</span>
        </a>
        <a href="#" onClick={vibePromptOpen} data-target="claude" data-prompt={prompt} data-page-title={pageTitle} className="vibe-prompt__link" style={{
  display: "inline-flex",
  alignItems: "center",
  gap: "0.4rem",
  padding: "0.4rem 0.75rem",
  borderRadius: "8px",
  border: "1px solid var(--vanta-border, rgba(120, 120, 130, 0.25))",
  fontSize: "0.8rem",
  fontWeight: 500,
  textDecoration: "none",
  color: "inherit",
  background: "transparent"
}}>
          <Icon icon="arrow-up-right-from-square" iconType="regular" size={11} color="#5E05C4" /><span>Claude</span>
        </a>
        <a href="#" onClick={vibePromptOpen} data-target="chatgpt" data-prompt={prompt} data-page-title={pageTitle} className="vibe-prompt__link" style={{
  display: "inline-flex",
  alignItems: "center",
  gap: "0.4rem",
  padding: "0.4rem 0.75rem",
  borderRadius: "8px",
  border: "1px solid var(--vanta-border, rgba(120, 120, 130, 0.25))",
  fontSize: "0.8rem",
  fontWeight: 500,
  textDecoration: "none",
  color: "inherit",
  background: "transparent"
}}>
          <Icon icon="arrow-up-right-from-square" iconType="regular" size={11} color="#5E05C4" /><span>ChatGPT</span>
        </a>
      </div>
    </div>
  </div>;

export const VibePrompts = ({children}) => <section className="vibe-prompts" style={{
  marginTop: "2.5rem",
  marginBottom: "2rem",
  padding: "1.5rem 1.5rem 1.25rem",
  borderRadius: "16px",
  border: "1px solid color-mix(in srgb, #5E05C4 22%, transparent)",
  background: "linear-gradient(180deg, color-mix(in srgb, #5E05C4 6%, transparent) 0%, transparent 100%)"
}}>
    <div style={{
  display: "flex",
  alignItems: "center",
  gap: "0.65rem",
  marginBottom: "0.25rem"
}}>
      <div style={{
  display: "inline-flex",
  alignItems: "center",
  justifyContent: "center",
  width: "32px",
  height: "32px",
  borderRadius: "9px",
  background: "color-mix(in srgb, #5E05C4 14%, transparent)"
}}>
        <Icon icon="wand-magic-sparkles" iconType="regular" size={16} color="#5E05C4" />
      </div>
      <div>
        <div className="text-gray-900 dark:text-white" style={{
  fontFamily: "Reckless, Georgia, serif",
  fontSize: "1.25rem",
  fontWeight: 500,
  lineHeight: 1.15
}}>
          Let AI do this for you
        </div>
        <div className="text-gray-600 dark:text-gray-300" style={{
  fontSize: "0.85rem",
  lineHeight: 1.45,
  marginTop: "0.15rem"
}}>
          Copy the prompt to run this live via the <a href="/docs/vanta-mcp" style={{
  color: "#5E05C4"
}}> MCP server</a> or have AI generate a runnable script.
        </div>
      </div>
    </div>
    {children}
  </section>;

export const RISK_SCENARIOS_BUILD = "You are writing a production-quality Node.js 18+ script that runs on a recurring schedule (cron / GitHub Actions / Cloud Scheduler) to keep risk scenarios in Vanta in sync with a source-of-truth CSV (e.g. exported from a GRC system or spreadsheet). Use the Manage Vanta API (base URL https://api.vanta.com).\n\nSteps:\n\n1. Read VANTA_CLIENT_ID, VANTA_CLIENT_SECRET, CSV_PATH, and RISK_REGISTER_NAME from env. Also accept STATE_PATH (default ./.vanta-risk-scenarios-state.json) and DRY_RUN (default \"false\"). Fail fast on stderr if any required var is missing.\n2. Mint a Vanta API token via POST https://api.vanta.com/oauth/token with Content-Type: application/json and a JSON body containing client_id, client_secret, grant_type=\"client_credentials\", and scope=\"vanta-api.all:read vanta-api.all:write\". The scope field is required — omitting it returns invalid_scope. Read access_token from the response. Re-mint at the start of each run (tokens expire after one hour).\n3. Parse CSV_PATH using a lightweight built-in parser that handles quoted fields and commas inside quotes. Required columns: riskId, description. Optional columns: detailedDescription, likelihood, impact, treatment, owner, categories (semicolon-separated), ciaCategories (semicolon-separated). Every other column header is the literal label of a custom field already defined in Vanta Risk Management settings.\n4. Page through GET https://api.vanta.com/v1/risk-scenarios?pageSize=100 using the pageCursor request param (read results.pageInfo.endCursor and hasNextPage until hasNextPage is false). Build a Map keyed by riskId. Each value is the full risk scenario object.\n5. For each CSV row, look up the scenario by riskId. If it exists, classify as update-candidate. If not, classify as create-candidate. Coerce each custom-field cell to the field's expected JSON shape: empty cell -> skip; picklist -> JSON array of strings split on semicolon; everything else -> string.\n6. Diff each update-candidate's coerced values against the scenario's existing fields. Build a `changes` object with only the fields that differ. If empty, classify the row as skipped.\n7. Load STATE_PATH if present — { \"lastSyncedHash\": { \"<riskId>\": \"<sha-of-fields>\" } } — and skip rows whose computed hash already matches (idempotent re-runs).\n8. Print the plan: riskId | description | classification (create / update / skipped) | changedFields (count).\n9. If DRY_RUN === \"true\", print a JSON summary and exit 0 without writing.\n10. For create-candidates, POST https://api.vanta.com/v1/risk-scenarios with body including description (required), riskRegister=RISK_REGISTER_NAME, and any populated fields. For update-candidates, PATCH https://api.vanta.com/v1/risk-scenarios/{riskScenarioId} with the changed fields only. Send requests sequentially to keep ordering deterministic and stay under rate limits.\n11. After each success, record state.lastSyncedHash[riskId] = sha of fields; write STATE_PATH atomically (temp file + rename). Log riskId, description, action (CREATE / UPDATE / SKIP), status (SUCCESS / ERROR), and any error message.\n12. End with a single JSON summary line on stdout: {\"total\": N, \"created\": C, \"updated\": U, \"skipped\": S, \"errors\": E}.\n\nSample API response item from GET /v1/risk-scenarios (use these field names exactly):\n{ \"riskId\": \"assets-not-identified-and-protected\", \"description\": \"Assets are not identified and protected according to company requirements.\", \"detailedDescription\": null, \"likelihood\": 4, \"impact\": 4, \"residualLikelihood\": 2, \"residualImpact\": 1, \"categories\": [\"Access control\"], \"ciaCategories\": [\"Confidentiality\"], \"treatment\": \"Avoid\", \"owner\": null, \"note\": null, \"riskRegister\": \"Default\", \"customFields\": [], \"reviewStatus\": \"DRAFT\", \"type\": \"Risk Scenario\", \"identificationDate\": \"2024-03-07T18:46:05.944Z\" }\n\nMissing-field handling: if customFields is null on the scenario, treat as []. If the CSV omits an optional column, skip that field in the payload rather than sending null. Never throw on a missing optional field.\n\nError handling:\n- 401: re-mint once and retry the request.\n- 400 saying `RiskCustomAttribute with id: <label> not found`: the custom-field label isn't defined in Vanta Risk Management settings. Log the label, mark the row ERROR, and continue — the API only fills existing custom fields, it does not create field definitions.\n- 400 saying `riskRegister` is required: your tenant has multiple registers. Confirm RISK_REGISTER_NAME matches an existing register name exactly (case-sensitive).\n- 400 saying the value type is wrong: log the field, expected vs actual type, and the offending value; mark ERROR and continue.\n- 404 on PATCH: scenario was deleted between the list and patch. Log and continue.\n- 429: respect Retry-After header if present, otherwise sleep 5s; retry up to 3 times.\n- 5xx: retry with 2s exponential back-off, max 3 attempts; then log and exit non-zero only if every request failed.\n\nDo not:\n- Add external dependencies — use built-in fetch, fs, path, and crypto only. The CSV parser is a small built-in helper, not an npm package.\n- Hard-code any riskId, register name, custom-field label, or value — every customer's risk register and field schema is different. Always read CSV_PATH and RISK_REGISTER_NAME.\n- Send `type` on PATCH — changing a scenario's type isn't supported via update.\n- Apply changes when DRY_RUN is \"true\".\n- Cache the access token across runs.\n- Silently swallow errors.\n\nDone when: a follow-up run with an unchanged CSV reports 0 creates and 0 updates (idempotent). Exit 0 if errors === 0; otherwise exit 1.\n\nScope required: vanta-api.all:read vanta-api.all:write.";

This guide creates and updates risk scenarios via `POST /v1/risk-scenarios` and `PATCH /v1/risk-scenarios/{riskScenarioId}` on the Manage Vanta API. It covers the three things most integrations trip on: targeting a specific **risk register**, setting **custom fields** with the right label and value shape, and modeling attributes (like "source of risk") that aren't in the built-in schema.

<VibePrompts>
  <BuildPrompt prompt={RISK_SCENARIOS_BUILD} />
</VibePrompts>

## Before you begin

This guide is for Vanta admins managing risk data inside their own Vanta account.

You'll need:

* A Manage Vanta [API token](/docs/quickstart/manage-vanta).
* Scopes `vanta-api.all:read` and `vanta-api.all:write` on the token. There is no risk-specific scope — risk scenarios are covered by the broad `vanta-api.all:*` scopes. See [API authentication](/docs/concepts/authentication).
* Any custom fields you plan to set must already be defined in **Risk Management → Settings → Custom Fields** in the Vanta UI. The API fills custom field values; it can't create the field definitions.

The `CreateRiskScenarioInput` schema has a fixed set of fields. There is no built-in `source` field, no built-in `jiraTicket` field, and no per-scenario "risk owner group". Anything not in the table below has to be modeled as a **custom field** (see Step 2 below):

| Field                                   | Type                                             | Notes                                                                          |
| --------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------ |
| `description`                           | string                                           | **Required.** Short title of the risk.                                         |
| `detailedDescription`                   | string                                           | Long-form context (max 10,000 chars).                                          |
| `riskId`                                | string                                           | Stable identifier. Auto-generated if omitted. Reuse it to update.              |
| `likelihood` / `impact`                 | integer                                          | Inherent risk scores, default range 1–5 (customizable in settings).            |
| `residualLikelihood` / `residualImpact` | integer                                          | Post-mitigation scores.                                                        |
| `categories`                            | string\[]                                        | New values become new categories automatically.                                |
| `ciaCategories`                         | `Confidentiality` / `Integrity` / `Availability` |                                                                                |
| `treatment`                             | `Mitigate` / `Transfer` / `Avoid` / `Accept`     |                                                                                |
| `owner`                                 | string                                           | **Email address** of a Vanta user.                                             |
| `note`                                  | string                                           | Justification for the scores.                                                  |
| `riskRegister`                          | string                                           | **Name** of the register (not an id). Required if you have multiple registers. |
| `customFields`                          | array                                            | Label/value pairs for org-specific attributes — see Step 2 below.              |
| `type`                                  | `Risk Scenario` / `Enterprise Risk`              | Enterprise risks can't be attached to a register. Defaults to `Risk Scenario`. |
| `identificationDate`                    | ISO 8601                                         | Defaults to creation time.                                                     |

There's also a deprecated `isSensitive` boolean still accepted by the API; new integrations shouldn't rely on it.

<Steps>
  <Step title="Create a risk scenario in a specific register">
    **Your terminal** — `POST /v1/risk-scenarios`. Only `description` is strictly required, but if your tenant has more than one risk register you must pass `riskRegister` **by name** (case-sensitive) or the API returns 400.

    <CodeGroup>
      ```javascript Node.js theme={"system"}
      const res = await fetch("https://api.vanta.com/v1/risk-scenarios", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer YOUR_TOKEN",
        },
        body: JSON.stringify({
          description: "Unauthorized access to production database",
          riskRegister: "Default",
          likelihood: 3,
          impact: 4,
          treatment: "Mitigate",
          owner: "risk-owner@example.com",
          ciaCategories: ["Confidentiality"],
        }),
      });
      const scenario = await res.json();
      console.log(scenario.riskId);
      ```

      ```python Python theme={"system"}
      import requests

      r = requests.post(
          "https://api.vanta.com/v1/risk-scenarios",
          headers={"Authorization": "Bearer YOUR_TOKEN"},
          json={
              "description": "Unauthorized access to production database",
              "riskRegister": "Default",
              "likelihood": 3,
              "impact": 4,
              "treatment": "Mitigate",
              "owner": "risk-owner@example.com",
              "ciaCategories": ["Confidentiality"],
          },
      )
      r.raise_for_status()
      print(r.json()["riskId"])
      ```

      ```bash Terminal theme={"system"}
      curl -X POST 'https://api.vanta.com/v1/risk-scenarios' \
        -H 'Content-Type: application/json' \
        -H 'Accept: application/json' \
        -H 'Authorization: Bearer YOUR_TOKEN' \
        -d '{
          "description": "Unauthorized access to production database",
          "riskRegister": "Default",
          "likelihood": 3,
          "impact": 4,
          "treatment": "Mitigate",
          "owner": "risk-owner@example.com",
          "ciaCategories": ["Confidentiality"]
        }'
      ```
    </CodeGroup>

    A `200` response returns the full risk scenario, including the `riskId` you'll use for later updates.

    <AccordionGroup>
      <Accordion title="Which register name should I send?">
        `riskRegister` takes the register's **name**, not its id. Open **Risk Management → Registers** in Vanta and copy the exact name (spaces, capitalization, and punctuation all matter). Tenants with a single register can omit the field.
      </Accordion>

      <Accordion title="Got `400` saying `owner` is not a valid user?">
        `owner` must be the email address of an existing Vanta user, not a display name or a person id. Look up the address with `GET /v1/people` filtered to `employmentStatus=CURRENT`.
      </Accordion>

      <Accordion title="Creating an Enterprise Risk instead?">
        Pass `type: "Enterprise Risk"` and omit `riskRegister` — enterprise risks aren't attached to a register. Requires the Enterprise Risk Management SKU.
      </Accordion>
    </AccordionGroup>
  </Step>

  <Step title="Set custom fields">
    Anything outside the built-in schema — "Source of risk", a Jira ticket URL, an internal risk tier, a business unit — is a **custom field**. Custom fields must be **defined ahead of time** in **Risk Management → Settings → Custom Fields**; the API fills values but never creates field definitions.

    Pass them via the `customFields` array. Each entry has a `label` (matches the field name in settings exactly, case-sensitive) and a `value` matching the field's type:

    * **Text / date / number / currency** — JSON string: `{ "label": "Source of risk", "value": "Internal audit finding" }`
    * **Picklist** — JSON array of strings: `{ "label": "Business unit", "value": ["Engineering", "Security"] }`

    <CodeGroup>
      ```bash Terminal theme={"system"}
      curl -X POST 'https://api.vanta.com/v1/risk-scenarios' \
        -H 'Content-Type: application/json' \
        -H 'Authorization: Bearer YOUR_TOKEN' \
        -d '{
          "description": "Unauthorized access to production database",
          "riskRegister": "Default",
          "customFields": [
            { "label": "Source of risk", "value": "Internal audit finding" },
            { "label": "Jira ticket", "value": "https://your-org.atlassian.net/browse/SEC-1234" },
            { "label": "Business unit", "value": ["Engineering", "Security"] }
          ]
        }'
      ```
    </CodeGroup>

    <AccordionGroup>
      <Accordion title="Got `400 RiskCustomAttribute with id: <label> not found`?">
        The `label` you sent doesn't match any custom field defined in **Risk Management → Settings → Custom Fields**. This includes system-style identifiers like `managed_by_email` — the API does not resolve those. Open the settings page, copy the field name exactly, and retry. Custom field definitions cannot be created through the API.
      </Accordion>

      <Accordion title="Got a 400 saying the value type is wrong?">
        Your JSON value doesn't match the field's declared type. Picklist fields need an array of strings even when you're only setting one option. Text/date/number/currency fields need a plain string.
      </Accordion>

      <Accordion title="Where does the built-in Source, Jira, or Ticket field live?">
        There isn't one. `riskId`, `description`, `detailedDescription`, `note`, `categories`, `ciaCategories`, `treatment`, `owner`, `riskRegister`, `likelihood`, `impact`, `residualLikelihood`, `residualImpact`, `type`, and `identificationDate` (plus the deprecated `isSensitive` flag) are the only non-custom fields on a risk scenario — everything else has to be a custom field.
      </Accordion>
    </AccordionGroup>
  </Step>

  <Step title="Update an existing scenario">
    **Your terminal** — `PATCH /v1/risk-scenarios/{riskScenarioId}`. Send only the fields you want to change; omitted fields keep their current values. `customFields` follows the same shape as create.

    <CodeGroup>
      ```javascript Node.js theme={"system"}
      const RISK_ID = "YOUR_RISK_ID";

      const res = await fetch(`https://api.vanta.com/v1/risk-scenarios/${RISK_ID}`, {
        method: "PATCH",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer YOUR_TOKEN",
        },
        body: JSON.stringify({
          residualLikelihood: 2,
          residualImpact: 2,
          customFields: [
            { label: "Jira ticket", value: "https://your-org.atlassian.net/browse/SEC-1234" },
          ],
        }),
      });
      console.log(await res.json());
      ```

      ```bash Terminal theme={"system"}
      RISK_ID="YOUR_RISK_ID"

      curl -X PATCH "https://api.vanta.com/v1/risk-scenarios/$RISK_ID" \
        -H 'Content-Type: application/json' \
        -H 'Authorization: Bearer YOUR_TOKEN' \
        -d '{
          "residualLikelihood": 2,
          "residualImpact": 2,
          "customFields": [
            { "label": "Jira ticket", "value": "https://your-org.atlassian.net/browse/SEC-1234" }
          ]
        }'
      ```
    </CodeGroup>

    <AccordionGroup>
      <Accordion title="Need to clear a custom field?">
        Send the field with `value: ""` (text/date/number/currency) or `value: []` (picklist). The `label` still has to match a defined field.
      </Accordion>

      <Accordion title="Can I change `type` on update?">
        No — changing a scenario's `type` (`Risk Scenario` ↔ `Enterprise Risk`) is not supported via `PATCH`. Requests that include `type` are rejected. Create a new scenario with the desired type and archive the old one.
      </Accordion>
    </AccordionGroup>
  </Step>
</Steps>

## Congratulations

You can now create risk scenarios in the right register, populate every organization-specific attribute via custom fields, and update scores or metadata idempotently.

## Next steps

<CardGroup cols={2}>
  <Card title="Assign a control owner" icon="user-check" href="/docs/guides/add-an-owner-to-a-control">
    Make a specific user accountable for the controls that mitigate a risk.
  </Card>

  <Card title="Set custom fields on vendors" icon="tags" href="/docs/guides/use-custom-fields-with-vendors">
    Same `customFields` pattern applied to the Vendors API.
  </Card>

  <Card title="Try it in Postman" icon="paper-plane" href="/docs/postman-setup">
    Import the collection and hit `POST /v1/risk-scenarios` against a sandbox.
  </Card>

  <Card title="Manage Vanta API reference" icon="book" href="/reference/manage-vanta/overview">
    Browse every Manage Vanta endpoint — risk scenarios, controls, tests, documents, people.
  </Card>
</CardGroup>


## Related topics

- [Update risk scenario](/api-reference/risk-scenarios/update-risk-scenario.md)
- [Create risk scenario](/api-reference/risk-scenarios/create-risk-scenario.md)
- [List risk scenarios](/api-reference/risk-scenarios/list-risk-scenarios.md)
- [Get risk scenario by ID](/api-reference/risk-scenarios/get-risk-scenario-by-id.md)
- [Submit risk scenario for approval](/api-reference/risk-scenarios/submit-risk-scenario-for-approval.md)
