{"id":18035,"plugin_id":"plugins_6a82b32a6ee8819191258c0368112b78","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:14:35.104Z","digest":"37c8eeda9b2e00ae2f54d110bab5cfc0262cc7453cc32013027855559391ebd2","against":null,"payload":{"description":"Apply a tenant configuration plan to a Zuora tenant using manage_settings","included_files":[],"name":"zuora-tenant-config-build","skill_md_contents":"---\nname: zuora-tenant-config-build\ndescription: Apply a tenant configuration plan to a Zuora tenant using manage_settings\nargument-hint: <configuration plan from /zuora-tenant-config-design or direct instructions>\nallowed-tools: [Read, Write, Glob, Grep, mcp__zuora-mcp__manage_settings, mcp__zuora-mcp__manage_custom_fields, mcp__zuora-mcp__query_objects, mcp__zuora-mcp__ask_zuora]\n---\n\nYou are applying Zuora tenant configuration changes directly to the tenant using MCP tools. This skill executes — it does NOT generate code.\n\n## How `manage_settings` works under the hood\n\nAll three operations go through the Zuora Settings batch API (`POST /settings/batch-requests`):\n\n| Operation | HTTP method | When to use |\n|-----------|-------------|-------------|\n| `list_setting_keys` | — | Discover available paths — fall back to this only if a path is not found in `settings-schema.json` |\n| `get_settings` | GET | Read current value before any update |\n| `update_settings` | PUT | Update an existing setting or collection item |\n| `create_settings` | POST | Create a new collection item (e.g., new payment term) |\n\nKey mechanics:\n- **`settingValueJson` must always be a JSON object `{...}`, never a bare array `[...]`**. The tool rejects arrays immediately.\n- For **per-ID collection updates**, include the item ID in `settingKey` (e.g., `/payment-terms/abc123`), not in the payload body.\n- For **full array replace settings** (e.g., `/currencies`), a single PUT replaces the entire collection — include all items, both changed and unchanged.\n- For **new collection items** (e.g., a payment term that doesn't exist yet), use `create_settings` with the base collection key (e.g., `/payment-terms`).\n- **Payment gateways are an exception** — gateway creation requires provisioning outside this tool; only updates are supported via `update_settings`.\n\nAlways check `\"success\": true` in the response before moving to the next operation.\n\n---\n\n## Input\n\nThe user's configuration plan or instructions: $ARGUMENTS\n\nThe plan from `/zuora-tenant-config-design` carries values in UI terms (`field_key` + option strings from `settings-fields.json`). Your job is to translate those into API payloads using `settings-field-mappings.json`, then apply them via `manage_settings`.\n\nIf no design plan exists and the request involves more than two settings, recommend running `/zuora-tenant-config-design` first.\n\n---\n\n## Step 1: Confirm target tenant\n\nBefore loading any references or applying any changes, fetch the tenant profile and confirm with the user:\n\n```\nTool: manage_settings\noperation: get_settings\nsettingKey: /entity-profile-info\n```\n\nPresent the result clearly and ask for explicit confirmation:\n\n> **Target tenant:**\n> - Name: `<tenantName>`\n> - ID: `<tenantId>`\n> - Environment: `<bannerLabel>` (`<bannerColor>`)\n> - Status: `<status>`\n>\n> Is this the correct tenant? Please confirm before I apply any changes.\n\nDo not proceed until the user confirms. If the tenant looks wrong (e.g., production when sandbox was expected), stop and ask the user to check their MCP credentials (`ZUORA_BASE_URL`, `ZUORA_CLIENT_ID`, `ZUORA_CLIENT_SECRET`).\n\n---\n\n## Step 2: Load reference files\n\nRead these in parallel:\n- `${CLAUDE_PLUGIN_ROOT}/references/settings-field-mappings.json` — for each `group_key` → `field_key`: the API field name (`api_field`), value type, and `value_map` (UI option string → API value). This is your primary translation dictionary.\n- `${CLAUDE_PLUGIN_ROOT}/references/settings-schema.json` — API schema per path: field types, enum values, required fields, min/max. Use to validate payloads before sending.\n- `${CLAUDE_PLUGIN_ROOT}/references/tenant-config-settings.md` — collection patterns (SINGLETON / ITEM-BY-ID / FULL ARRAY REPLACE) and read-only fields.\n\n---\n\n## Step 3: Retrieve before every update\n\nFor each setting key you will modify, call `get_settings` first — even when the plan already includes a payload:\n\n- You need current item IDs to construct per-ID update keys (e.g., `/payment-terms/abc123`).\n- For full array replace settings you need the complete current item list to avoid unintentional deletions.\n- You need the live field structure to avoid sending stale or conflicting values.\n\n```\nTool: manage_settings\noperation: get_settings\nsettingKey: /billing-rules\n```\n\nRun independent retrieves in parallel.\n\n---\n\n## Step 4: Translate plan values → API payload\n\nFor each field in the plan, first check `settings-fields.json`:\n- If the field has `\"ui_only\": true`, **skip it entirely** — it cannot be set via the API. Record it in the Step 9 report under \"Requires manual setup in Zuora UI\" with the intended value and a Zuora UI navigation path.\n\nFor all other fields, use `settings-field-mappings.json` to construct the API payload:\n\n1. Look up `group_key` → `fields` → `field_key` entry in the mappings file.\n2. Get `api_field` — the camelCase API field name to use in the payload.\n   - **If the `field_key` is not found in `settings-field-mappings.json`**: look up the setting path in `settings-schema.json` to find the correct API field name. Use only field names that appear explicitly in the schema.\n   - **Never invent or guess an API field name from training knowledge.** If the field cannot be found in either `settings-field-mappings.json` or `settings-schema.json`, skip it and flag it in the report as unresolved.\n3. Get `value_map` — look up the UI option string to get the API value.\n   - If the option string matches a key in `value_map`, use the mapped value exactly.\n   - If there is no `value_map` (plain string/integer fields), use the value directly after any type coercion (e.g., `\"30\"` → `30` for integer fields).\n   - If the option string is not in `value_map` but is a clear substring match of a key, use that match. If genuinely ambiguous, use the `default` value from the mapping and flag a warning in the report.\n4. Validate the resulting API value against `settings-schema.json` — confirm it matches the `enum` list if one exists, and satisfies `min`/`max` for integers. If the value is not valid per the schema, do not send it — flag it in the report as unresolved.\n\nExample translation:\n```\nPlan:  enable_customer_hierarchy = \"Yes\"\nMapping: api_field=\"customerHierarchy\", value_map={\"Yes\": true, \"No\": false}\nSchema confirms: customerHierarchy is boolean ✓\nPayload field: \"customerHierarchy\": true\n\nPlan:  available_to_credit_validation_for_credit_memos = \"Header-level only\"\nMapping: api_field=\"availableToCreditValidationLevel\", value_map={\"Header-level only\": \"HeaderLevel\", \"Line-level\": \"HeaderAndItemLevel\"}\nSchema confirms: availableToCreditValidationLevel is string ✓\nPayload field: \"availableToCreditValidationLevel\": \"HeaderLevel\"\n```\n\nDo this translation for all fields in the plan before making any API calls. Any field that could not be resolved must be listed in the Step 9 report under \"Unresolved fields\" — do not silently drop them.\n\n---\n\n## Step 5: Apply SINGLETON settings\n\nSend only the fields you want to change. Omit read-only fields. PUT is a partial update for singletons — fields not included in the payload are preserved.\n\n```\nTool: manage_settings\noperation: update_settings\nsettingKey: /billing-rules\nsettingValueJson: {\"availableToCreditValidationLevel\": \"HeaderLevel\", \"catchUpBillRun\": true}\n```\n\n---\n\n## Step 6: Apply COLLECTION settings\n\n### Per-ID update — existing items (e.g., `/payment-terms`, `/payment-gateways`)\n\nFrom the retrieve response, find the item's `id`. Use it in the `settingKey`:\n\n```\nTool: manage_settings\noperation: update_settings\nsettingKey: /payment-terms/abc123\nsettingValueJson: {\"name\": \"Net 30\", \"isActive\": true, \"isDefault\": true, \"intervalNumber\": 30, \"type\": \"NetPaymentTerm\"}\n```\n\n### Create — new items (e.g., a payment term that doesn't exist yet)\n\nUse `create_settings` with the base collection key:\n\n```\nTool: manage_settings\noperation: create_settings\nsettingKey: /payment-terms\nsettingValueJson: {\"name\": \"Net 60\", \"isActive\": true, \"isDefault\": false, \"intervalNumber\": 60, \"type\": \"NetPaymentTerm\"}\n```\n\n**Payment gateways are the exception** — gateway creation requires provisioning outside this tool. If the plan calls for a new gateway, mark it as a manual step.\n\n### Full array replace — e.g., `/currencies`\n\nRetrieve the full current list first. PUT back ALL items (modified + unchanged) as an object wrapping the array. Omitting an existing item from the PUT may deactivate it.\n\n```\nTool: manage_settings\noperation: update_settings\nsettingKey: /currencies\nsettingValueJson: {\n  \"items\": [\n    {\"currencyCode\": \"USD\", \"active\": true, \"default\": true, \"roundingMode\": \"HalfUp\", \"roundingIncrement\": 0.01, \"rate\": 1.0},\n    {\"currencyCode\": \"EUR\", \"active\": true, \"default\": false, \"roundingMode\": \"HalfUp\", \"roundingIncrement\": 0.01, \"rate\": 0.92}\n  ]\n}\n```\n\nThe outer `{\"items\": [...]}` wrapper is required — a bare array will be rejected.\n\n---\n\n## Step 7: Apply custom fields (if in scope)\n\nCustom fields are managed by `manage_custom_fields`, not `manage_settings`.\n\n**List existing before creating:**\n```\nTool: manage_custom_fields\noperation: list_custom_fields\nobjectType: Account\n```\n\n**Add only if it doesn't already exist:**\n```\nTool: manage_custom_fields\noperation: add_custom_field\nobjectType: Account\nfieldName: Region__c\nlabel: Region\nfieldType: string\n```\n\n---\n\n## Step 8: Verify changes\n\nAfter all updates, retrieve each modified setting key and confirm values match the desired state.\n\n```\nTool: manage_settings\noperation: get_settings\nsettingKey: /billing-rules\n```\n\nReport the verified state for each setting. Flag any discrepancies.\n\n---\n\n## Step 9: Report outcome\n\n```\n## Configuration Applied\n\n### Successful\n- /billing-rules: availableToCreditValidationLevel=HeaderLevel, catchUpBillRun=true ✓\n- /payment-terms/abc123: Net 30 updated ✓\n- /payment-terms (new): Net 60 created ✓\n\n### Requires manual setup in Zuora UI\nThese settings cannot be applied via the API — please configure them directly in Zuora:\n- **Time Zone:** Pacific Time → Settings > Company Profile > Tenant Profile\n- **<field_name>:** <value> → <Zuora UI navigation path>\n\n### Other manual steps\n- New payment gateway — must be provisioned outside this tool, then updated via manage_settings\n\n### Unresolved fields (not sent)\n- <field_name>: could not find API field name in settings-field-mappings.json or settings-schema.json — verify the field key and retry\n- <field_name>: value \"<value>\" is not valid per settings-schema.json enum — expected one of [...]\n\n### Errors\n- <any failure with the error message from the response and suggested resolution>\n```\n\n---\n\n## Critical constraints\n\n- **`settingValueJson` is always a JSON object `{...}`** — never a bare array. Wrap array-valued payloads in an object (e.g., `{\"items\": [...]}`).\n- **Per-ID updates need the ID in `settingKey`** (e.g., `/payment-terms/abc123`), not in the payload.\n- **New items use `create_settings`; existing items use `update_settings`.** Sending a create to an existing item (or an update without an ID) will fail or target the wrong resource.\n- **Never omit items from full array replace payloads** — retrieve first, include all existing items in the PUT.\n- **UI-only fields** — any field with `\"ui_only\": true` in `settings-fields.json` must be skipped; it will fail if sent to the API. These are surfaced in the report under \"Requires manual setup in Zuora UI\".\n- **Security policy integer fields**: `enforcePasswordHistory` accepts only `0`, `4`, `7`; `passwordExpiration` only `0`, `30`, `60`, `90`; `minimumPasswordLength` only `7`, `8`, `10`, `12`. Round to the nearest accepted value and confirm with the user before sending.\n- **Document prefixes**: changing prefixes or start numbers after billing documents have been issued may cause numbering conflicts. Warn the user before applying.\n- **Default currency**: exactly one currency item must have `\"default\": true`. Validate before sending the full array.\n\n---\n\n## Tool routing\n\n- `manage_settings` — `get_settings` to read, `update_settings` (PUT) to modify, `create_settings` (POST) to create new collection items.\n- `manage_custom_fields` — create or list custom fields only.\n- `query_objects` — look up live tenant data or IDs when not returned by retrieve.\n- `ask_zuora` — only for an unresolved product-behaviour question after the reference and retrieve results have been checked. Name the exact question.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}