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

# Create widget

> Create a new KYB widget with a full configuration.

Creates a new onboarding widget. New widgets are created in `draft` status. The full `config` object is required and must contain every section.

Requires `Authorization: Bearer $TOKEN`.

## Body

<ParamField body="name" type="string" required>
  Human-readable name for this widget. 1–120 characters.
</ParamField>

<ParamField body="templateId" type="string" default="blank">
  Template identifier the widget was built from. 1–60 characters.
</ParamField>

<ParamField body="environment" type="string" default="sandbox">
  One of `sandbox` or `live`.
</ParamField>

<ParamField body="config" type="object" required>
  Full widget configuration. All six sections below are required.
</ParamField>

### config.branding

<ParamField body="config.branding.brandName" type="string" required>1–120 characters.</ParamField>
<ParamField body="config.branding.logoUrl" type="string" default="">Logo URL, up to 2048 characters.</ParamField>
<ParamField body="config.branding.logoPublicId" type="string">Storage public ID, up to 512 characters.</ParamField>
<ParamField body="config.branding.accentColor" type="string" required>Hex colour, e.g. `#6466AE`.</ParamField>
<ParamField body="config.branding.cornerRadius" type="string" required>One of `sharp`, `soft`, `round`.</ParamField>
<ParamField body="config.branding.welcomeTitle" type="string" required>1–200 characters.</ParamField>
<ParamField body="config.branding.welcomeMessage" type="string" required>1–600 characters.</ParamField>
<ParamField body="config.branding.completionTitle" type="string" required>1–200 characters.</ParamField>
<ParamField body="config.branding.completionMessage" type="string" required>1–600 characters.</ParamField>
<ParamField body="config.branding.supportEmail" type="string" default="">Up to 200 characters.</ParamField>

### config.modules

<ParamField body="config.modules" type="object" required>
  A map keyed by module ID (e.g. `business_profile`, `cac_verification`). Each value is `{ "enabled": boolean, "required": boolean }`. See [Module catalog](/api-reference/onboarding/module-catalog) for the 19 valid module IDs.
</ParamField>

### config.flow

<ParamField body="config.flow.order" type="string[]" required>Ordered array of module IDs.</ParamField>

<ParamField body="config.flow.enableSavedProgress" type="boolean" required />

<ParamField body="config.flow.enableResume" type="boolean" required />

<ParamField body="config.flow.sessionTimeoutMinutes" type="integer" required>5–240.</ParamField>
<ParamField body="config.flow.successRedirectUrl" type="string" default="">Up to 2048 characters.</ParamField>
<ParamField body="config.flow.failureRedirectUrl" type="string" default="">Up to 2048 characters.</ParamField>
<ParamField body="config.flow.abandonRedirectUrl" type="string" default="">Up to 2048 characters.</ParamField>

### config.security

<ParamField body="config.security.allowedDomains" type="string[]" required>Up to 50 entries, each up to 255 characters.</ParamField>
<ParamField body="config.security.allowedCountries" type="string[]" required>Up to 250 two-letter country codes.</ParamField>

<ParamField body="config.security.enableIpAllowlist" type="boolean" required />

<ParamField body="config.security.ipAllowlist" type="string[]" required>Up to 100 entries, each up to 64 characters.</ParamField>

<ParamField body="config.security.requireSignedRequests" type="boolean" required />

### config.risk

<ParamField body="config.risk.tier" type="string" required>One of `low`, `standard`, `enhanced`.</ParamField>
<ParamField body="config.risk.autoApproveThreshold" type="integer" required>0–100.</ParamField>
<ParamField body="config.risk.autoRejectThreshold" type="integer" required>0–100.</ParamField>

<ParamField body="config.risk.reviewOnPepMatch" type="boolean" required />

<ParamField body="config.risk.reviewOnAdverseMedia" type="boolean" required />

<ParamField body="config.risk.reviewOnSanctionsMatch" type="boolean" required />

### config.notifications

<ParamField body="config.notifications.notifyApplicantEmail" type="boolean" required />

<ParamField body="config.notifications.notifyApplicantSms" type="boolean" required />

<ParamField body="config.notifications.notifyAdminEmail" type="string" default="">Up to 200 characters.</ParamField>
<ParamField body="config.notifications.webhookEvents" type="string[]" required>Up to 20 entries, each up to 60 characters.</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.vouchmark.com/v1/kyb/widgets \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Acme KYB",
      "templateId": "blank",
      "environment": "sandbox",
      "config": {
        "branding": {
          "brandName": "Acme",
          "logoUrl": "",
          "accentColor": "#6466AE",
          "cornerRadius": "soft",
          "welcomeTitle": "Verify your business",
          "welcomeMessage": "This takes about 10 minutes.",
          "completionTitle": "All done!",
          "completionMessage": "We will review within 24 hours.",
          "supportEmail": "support@acme.com"
        },
        "modules": {
          "business_profile": { "enabled": true, "required": true },
          "cac_verification": { "enabled": true, "required": true },
          "tin_verification": { "enabled": true, "required": true }
        },
        "flow": {
          "order": ["business_profile", "cac_verification", "tin_verification"],
          "enableSavedProgress": true,
          "enableResume": true,
          "sessionTimeoutMinutes": 60,
          "successRedirectUrl": "",
          "failureRedirectUrl": "",
          "abandonRedirectUrl": ""
        },
        "security": {
          "allowedDomains": ["acme.com"],
          "allowedCountries": ["NG"],
          "enableIpAllowlist": false,
          "ipAllowlist": [],
          "requireSignedRequests": false
        },
        "risk": {
          "tier": "standard",
          "autoApproveThreshold": 80,
          "autoRejectThreshold": 30,
          "reviewOnPepMatch": true,
          "reviewOnAdverseMedia": true,
          "reviewOnSanctionsMatch": true
        },
        "notifications": {
          "notifyApplicantEmail": true,
          "notifyApplicantSms": false,
          "notifyAdminEmail": "compliance@acme.com",
          "webhookEvents": ["applicant.approved", "applicant.rejected"]
        }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "success": true,
    "data": {
      "id": "wgt_aBcD...",
      "name": "Acme KYB",
      "status": "draft",
      "environment": "sandbox",
      "templateId": "blank",
      "config": { "branding": { "...": "..." }, "modules": { "...": "..." }, "flow": { "...": "..." }, "security": { "...": "..." }, "risk": { "...": "..." }, "notifications": { "...": "..." } },
      "embedLinkToken": "elt_...",
      "createdAt": "2026-06-01T10:00:00Z",
      "updatedAt": "2026-06-01T10:00:00Z"
    }
  }
  ```
</ResponseExample>

Returns `201` with the full widget object. Set the widget to `live` with [Set widget status](/api-reference/onboarding/set-widget-status) when ready.
