# Preview publishing a draft

A dry run of publishing, without a request body and without any change: the scoring impact of the draft against the latest published version (the built-in questionnaire for a first publish), the same violations and warnings as validate plus the weight-raised warning `W6_WEIGHT_RAISED_3X`, and the permissions of the caller.

`POST /supplier-assessment-templates/{templateId}/publish/preview`

Scope `supplier_template:read` | Plan **Growth+**

A dry run of publishing, without a request body and without any change: the scoring impact of the draft against the latest published version (the built-in questionnaire for a first publish), the same violations and warnings as validate plus the weight-raised warning `W6_WEIGHT_RAISED_3X`, and the permissions of the caller. Publishing itself is refused for every token. A read: requires the supplier_template:read scope.

## Path parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `templateId` | string | yes | Questionnaire document id (`satpl_...`), or `satpl_builtin_supplier_security_privacy_v1` for the built-in one. |

## Returns

The `data` field of the standard `{ data, error, meta }` envelope:

- `impact`: object What publishing the draft would change in scoring, against the baseline version.
  - `fromVersion`: integer or null
  - `toVersion`: integer
  - `baselineIsBuiltin`: boolean
  - `baselineKey`: string
  - `maxPenalty`: array of object
    - `mode`: string
    - `before`: integer
    - `after`: integer
    - `change`: integer
    - `unloseableBefore`: integer
    - `unloseableAfter`: integer
    - `deltaPct`: number
  - `criticalOptionCount`: object
    - `before`: integer
    - `after`: integer
    - `change`: integer
  - `scoreableQuestionCount`: object
    - `before`: integer
    - `after`: integer
    - `change`: integer
    - `added`: integer
    - `removed`: integer
  - `weightChanges`: array of object
    - `questionId`: string
    - `sectionId`: string
    - `text`: string
    - `before`: integer
    - `after`: integer
    - `zeroRiskOnly`: boolean
  - `riskValueChanges`: array of object
    - `questionId`: string
    - `optionId`: string
    - `label`: string
    - `before`: integer
    - `after`: integer
  - `severityChanges`: array of object
    - `questionId`: string
    - `optionId`: string
    - `label`: string
    - `before`: string
    - `after`: string
    - `downgrade`: boolean
    - `removed`: optional boolean True when the option or its question no longer exists in the draft.
  - `addedQuestions`: array of object
    - `questionId`: string
    - `sectionId`: string
    - `text`: string
    - `weight`: integer
    - `scoreable`: boolean
  - `removedQuestions`: array of object
    - `questionId`: string
    - `sectionId`: string
    - `text`: string
    - `weight`: integer
    - `scoreable`: boolean
  - `changes`: array of object
    - `kind`: string weight, riskValue, severity, required, allowNa, questionAdded, questionRemoved, optionAdded, optionRemoved, conditionalRemoved or text.
    - `questionId`: string
    - `sectionId`: string
    - `optionId`: optional string
    - `textEn`: string
    - `before`: any or null Previous value; its type depends on `kind`. Null on questionAdded, questionRemoved, optionAdded and optionRemoved rows.
    - `after`: any or null New value; its type depends on `kind`. Null on questionAdded, questionRemoved, optionAdded and optionRemoved rows.
    - `shareBefore`: number
    - `shareAfter`: number
    - `shareMode`: string
    - `allOptionsZeroRisk`: boolean
    - `reducesRisk`: boolean
    - `tier`: string
      - `notice`
      - `significant`
      - `severe`
    - `actor`: optional object
      - `type`: string user, api_token or mcp.
      - `userId`: optional string
      - `name`: optional string
      - `email`: optional string
      - `tokenId`: optional string
      - `tokenName`: optional string
      - `surface`: optional string console, api_token or mcp.
  - `requiresAcknowledgement`: boolean True when a person must acknowledge a risk reduction to publish.
  - `acknowledgementReasons`: array of string
  - `acknowledgementRowCount`: integer
- `violations`: array of object
  - `code`: string V1 to V12.
  - `path`: string
  - `message`: string
- `warnings`: array of object
  - `code`: string W1_NO_ZERO_RISK_OPTION, W2_MISSING_TRANSLATION, W3_NO_CONTROL_IDS, W4_TOP_OF_SCALE_SKEW, W5_ALL_OPTIONS_ZERO_RISK, or (preview only) W6_WEIGHT_RAISED_3X.
  - `path`: string
  - `parameters`: object
- `permissions`: object What the caller may do with this version right now.
  - `canEdit`: boolean
  - `canSubmit`: boolean
  - `canWithdraw`: boolean
  - `canReject`: boolean
  - `canPublish`: boolean or null
  - `canSetDefault`: boolean
  - `canArchive`: boolean
  - `canDelete`: boolean
  - `publishBlockedReason`: string or null

## Errors

| Status | Code | Retry | Meaning |
|---|---|---|---|
| 401 | `INVALID_TOKEN` | no | Missing (UNAUTHORIZED) or invalid, expired or revoked (INVALID_TOKEN) token. |
| 402 | `FEATURE_GATED` | no | The tenant plan does not include supply chain security. code FEATURE_GATED; args.feature, args.minTier, args.minTierName. |
| 403 | `INSUFFICIENT_SCOPE` | no | The token lacks the required scope (INSUFFICIENT_SCOPE), or the request is refused (FORBIDDEN, INSUFFICIENT_ROLE for a draft the caller may not read). |
| 404 | `NOT_FOUND` | no | Unknown or foreign-tenant questionnaire, version or clone source. code NOT_FOUND. |
| 429 | `RATE_LIMITED` | yes | Too many failed authentication attempts from this address. code RATE_LIMITED; wait Retry-After seconds. |
| 500 | `DB_ERROR` | no | Unexpected server error. code DB_ERROR; quote error.id to support. |
| 503 | `BILLING_UNAVAILABLE` | yes | Billing is temporarily unavailable, so the plan could not be checked. code BILLING_UNAVAILABLE. Retry later. |

## Example

### curl

```bash
curl -X POST "https://api.autociso.io/api/v1/supplier-assessment-templates/<templateId>/publish/preview" \
  -H "Authorization: Bearer <your-api-token>"
```

### Python

```python
import requests

response = requests.post(
    "https://api.autociso.io/api/v1/supplier-assessment-templates/<templateId>/publish/preview",
    headers={"Authorization": "Bearer <your-api-token>"},
)
print(response.json())
```

### JavaScript

```javascript
const response = await fetch("https://api.autociso.io/api/v1/supplier-assessment-templates/<templateId>/publish/preview", {
  method: "POST",
  headers: { "Authorization": "Bearer <your-api-token>" },
});
console.log(await response.json());
```

## Response (200)

```json
{
  "data": {
    "impact": {
      "fromVersion": null,
      "toVersion": 1,
      "baselineIsBuiltin": true,
      "baselineKey": "supplier_security_privacy",
      "maxPenalty": [
        {
          "mode": "general",
          "before": 100,
          "after": 100,
          "change": 0,
          "unloseableBefore": 0,
          "unloseableAfter": 0,
          "deltaPct": 0
        }
      ],
      "criticalOptionCount": {
        "before": 4,
        "after": 4,
        "change": 0
      },
      "scoreableQuestionCount": {
        "before": 60,
        "after": 60,
        "change": 0,
        "added": 0,
        "removed": 0
      },
      "weightChanges": [],
      "riskValueChanges": [],
      "severityChanges": [],
      "addedQuestions": [],
      "removedQuestions": [],
      "changes": [],
      "requiresAcknowledgement": false,
      "acknowledgementReasons": [],
      "acknowledgementRowCount": 0
    },
    "violations": [],
    "warnings": [],
    "permissions": {
      "canEdit": true,
      "canSubmit": true,
      "canWithdraw": false,
      "canReject": false,
      "canPublish": false,
      "canSetDefault": false,
      "canArchive": false,
      "canDelete": true,
      "publishBlockedReason": null
    }
  }
}
```
