← Zuora Coding AgentCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Zuora Coding Agent
Snapshot Sep 30, 2026 · 23:14 UTC · version 1.5.4
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Generate Order API implementation code by converting customer's Subscription/Amendment/Subscribe Action API code (supports both preview and create modes)",
"included_files": [],
"name": "zuora-order-migration-build",
"skill_md_contents": "---\nname: zuora-order-migration-build\ndescription: Generate Order API implementation code by converting customer's Subscription/Amendment/Subscribe Action API code (supports both preview and create modes)\nargument-hint: [customer code file paths or migration plan reference]\nallowed-tools: [Read, Write, Edit, Glob, Grep, Bash, Agent, mcp__zuora-mcp__zuora_codegen, mcp__zuora-mcp__ask_zuora, mcp__zuora-mcp__query_objects, mcp__zuora-mcp__create_subscriptions, mcp__zuora-mcp__manage_subscriptions]\n---\n\nCodex-only path resolution: When an instruction refers to `${CLAUDE_PLUGIN_ROOT}`, treat it as the root of this installed plugin. In Codex, resolve that root as the ancestor directory containing `skills/`, `references/`, and `.codex-plugin/`.\n\n\nYou are generating Order API implementation code by converting customer integration code from Subscription/Amendment API and Subscribe Action API. The Subscribe Action API supports two distinct modes (preview vs create) which map to different Order API endpoints. The user should have a migration plan (from `/zuora-order-migration-design`) or provide their source code directly.\n\n## Input\n\nThe user's request: $ARGUMENTS\n\nThis could be:\n- Customer source code file paths\n- Reference to a migration plan document\n- Specific operations to convert (cancel, suspend, resume, renew, create, update)\n\n## Tool routing\n\nUse local file reads and edits for conversion work, bundled mapping references for known S/A-to-Order transformations, and `mcp__zuora-mcp__zuora_codegen` for exact Order API endpoint/model details. Use subscription MCP tools only for their specific create/cancel/renew operations when validation requires them. `mcp__zuora-mcp__ask_zuora` is allowed only as a fallback for a specific Order API capability or migration-tradeoff question that remains after references and codegen are checked. If business intent is ambiguous, ask the user to confirm the mapping.\n\n## Workflow\n\n**⚠️ CRITICAL PRINCIPLE: Always Modify Existing Files**\n\nWhen converting customer integration code:\n- ✅ DO: Use Edit tool to modify existing customer files in-place\n- ✅ DO: Comment out old code and add converted code in the same location\n- ✅ DO: Create clear BEFORE/AFTER markers in the same file\n- ❌ DON'T: Create new files like `*_converted.py` or `*_order_api.py`\n- ❌ DON'T: Use Write tool for existing integration files\n\n**Why:** PR reviews need to see the diff between old and new code. New files hide the changes and make it impossible to review what actually changed.\n\n**Exception:** New supporting files (validation scripts, checklists, documentation) can be created with Write tool since they don't replace existing code.\n\n### Step 1: Review Context\n\n**If migration plan exists:**\n- Read the migration plan to understand:\n - Which S/A API calls were detected\n - The field mappings for each operation\n - Programming language used\n - Edge cases identified\n\n**If no plan exists:**\n- Read the customer's source code files\n- Identify the programming language\n- Detect API patterns (Subscription, Amendment, Subscribe Action)\n- Recommend running `/zuora-order-migration-design` first for comprehensive analysis\n\n### Step 2: Read Reference Mappings\n\nFor each operation being converted, read the corresponding reference document from `${CLAUDE_PLUGIN_ROOT}/references/`:\n\n**Available Reference Mappings:**\n\n1. **Subscription Cancel** → `${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-cancel-api-mapping.md`\n2. **Subscription Suspend** → `${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-suspend-api-mapping.md`\n3. **Subscription Resume** → `${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-resume-api-mapping.md`\n4. **Subscription Renew** → `${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-renew-api-mapping.md`\n5. **Subscription Create** → `${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-create-api-mapping.md`\n6. **Subscription Update** → `${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-update-api-mapping.md`\n7. **Subscribe Action** → `${CLAUDE_PLUGIN_ROOT}/references/action-subscribe-api-mapping.md`\n - **Note**: Subscribe API supports two modes (preview vs create) controlled by `PreviewOptions`\n - **Preview mode** (PreviewOptions present) → `/v1/orders/preview` with `previewAccountInfo`\n - **Create mode** (PreviewOptions absent) → `/v1/orders` with `newAccount` or `existingAccountNumber`\n - See \"Subscribe API: Preview vs Create Mode Detection\" in Step 4 for complete handling\n\nThese documents provide field-accurate mappings verified against Zuora Billing source code.\n\n### Step 3: Generate Converted Code\n\nFor each API call in the customer's code (Subscription, Amendment, or Subscribe Action), generate the Order API equivalent following these guidelines:\n\n#### Code Generation Guidelines\n\n**CRITICAL: Always Modify Existing Files, Never Create New Files**\n\n**Why:** When converting integration code, changes must be visible in PR diffs. Creating new files makes it impossible to see what changed from the original code. Always use the Edit tool to modify existing customer files directly.\n\n**How:**\n1. Read the existing customer file first\n2. Locate the exact S/A API code to convert\n3. Use Edit tool to replace the old code with converted code in-place\n4. Keep commented BEFORE/AFTER blocks to show the transformation\n5. Preserve all surrounding code unchanged\n\n**1. Preserve Structure**\n- Keep similar code organization and flow\n- Maintain the same variable names where possible\n- Preserve error handling patterns\n- Keep the same file and function names\n\n**2. Match Coding Style**\n- Use same indentation (spaces vs tabs)\n- Follow same naming conventions\n- Maintain consistent formatting\n- Match the customer's code style exactly\n\n**3. Add Explanatory Comments**\n- Mark the original S/A API code with \"BEFORE\" comment (keep original as comment)\n- Mark the new Order API code with \"AFTER\" comment\n- Explain what changed and why\n- Reference the field mapping source\n- This creates clear before/after comparison in PR diff\n\n**4. Include TODO Markers**\n- Mark areas requiring customer input (account numbers, dates, etc.)\n- Highlight new required fields that don't have obvious sources\n- Flag response handling changes that need attention\n\n**5. Update Response Handling**\n- Show old response structure vs new (as comments)\n- Update field extraction code\n- Handle new response fields (`orderNumber`, nested structures)\n\n**6. Add Error Handling**\n- Include Order API specific error handling\n- Handle validation errors from new required fields\n- Add transaction-level error handling\n\n#### Output Format - Modify Existing Files In-Place\n\n**Step-by-step process:**\n\n1. **Read the existing customer file:**\n ```\n Read(file_path=\"customer_code.py\")\n ```\n\n2. **Identify the exact code block to convert** (e.g., lines 45-52)\n\n3. **Use Edit tool to replace the old code with converted code:**\n ```\n Edit(\n file_path=\"customer_code.py\",\n old_string=\"<exact original code>\",\n new_string=\"<converted code with comments>\"\n )\n ```\n\n**Example of converted code structure in the file:**\n\n```python\n# ============================================================================\n# BEFORE - Subscription Cancel API (Original code below, kept for reference)\n# ============================================================================\n# response = requests.put(\n# f\"https://rest.zuora.com/v1/subscriptions/{subscription_key}/cancel\",\n# json={\n# \"cancellationPolicy\": \"SpecificDate\",\n# \"cancellationEffectiveDate\": cancel_date,\n# \"invoiceCollect\": True\n# },\n# headers=headers\n# )\n# subscription_id = response.json()['subscriptionId']\n\n# ============================================================================\n# AFTER - Order API Equivalent\n# Converted using: ${CLAUDE_PLUGIN_ROOT}/references/amendment-rest-v1-cancel-api-mapping.md\n# ============================================================================\n\n# TODO: Add account_number variable\n# You can get this from:\n# - Subscription lookup before cancellation\n# - Configuration/settings\n# - Database query\naccount_number = \"A00000001\" # TODO: Replace with actual account number\n\n# TODO: Set orderDate (typically today or the effective date)\norder_date = datetime.today().strftime('%Y-%m-%d') # or use cancel_date\n\nresponse = requests.post(\n \"https://rest.zuora.com/v1/orders\",\n json={\n \"orderDate\": order_date, # New required field\n \"existingAccountNumber\": account_number, # New required field\n \"processingOptions\": {\n \"runBilling\": True, # Replaces invoiceCollect\n \"collect\": True # Replaces invoiceCollect\n },\n \"subscriptions\": [{\n \"subscriptionNumber\": subscription_key,\n \"orderActions\": [{\n \"type\": \"CancelSubscription\", # Explicit action type\n \"triggerDates\": [{\n \"name\": \"ContractEffective\",\n \"triggerDate\": cancel_date # Same date as before\n }],\n \"cancelSubscription\": {\n \"cancellationPolicy\": \"SpecificDate\", # Same value\n \"cancellationEffectiveDate\": cancel_date # Same value\n }\n }]\n }]\n },\n headers=headers\n)\n\n# ============================================================================\n# RESPONSE HANDLING CHANGES\n# Old response: {\"subscriptionId\": \"2c92...\", \"success\": true}\n# New response: {\"orderNumber\": \"O-00000123\", \"subscriptions\": [...], \"success\": true}\n# ============================================================================\norder_number = response.json()['orderNumber'] # New field\nsubscription_id = response.json()['subscriptions'][0]['subscriptionId'] # New nested path\n```\n\n**Key principles for in-place editing:**\n\n- Comment out the original S/A API code (don't delete it)\n- Add the converted Order API code below with clear BEFORE/AFTER markers\n- All changes should be in the same file at the same location\n- The PR diff will clearly show: old code commented out, new code added\n- Never create separate new files like `customer_code_converted.py`\n\n### Step 4: Handle Special Cases\n\n#### Subscribe API: Preview vs Create Mode Detection\n\nSubscribe Action API supports two distinct modes controlled by the `PreviewOptions` parameter. These must be detected and routed to different Order API endpoints:\n\n**Detection Logic:**\n```python\n# Check if PreviewOptions exists and is not empty\nhas_preview_options = 'PreviewOptions' in subscribe_request and subscribe_request['PreviewOptions']\n\nif has_preview_options:\n # Route to PREVIEW MODE\nelse:\n # Route to CREATE MODE\n```\n\n**Preview Mode (PreviewOptions present):**\n\nWhen the Subscribe API includes `PreviewOptions`, it returns preview results **without creating** any records. This maps to the Order Preview API.\n\n```python\n# BEFORE - Subscribe API with PreviewOptions\nrequests.post(\"/v1/action/subscribe\", json={\n \"Account\": {\n \"name\": \"Example Corp\",\n \"currency\": \"USD\",\n \"billCycleDay\": 1,\n \"billToContact\": {...}\n },\n \"PreviewOptions\": {\n \"enablePreviewMode\": True,\n \"numberOfPeriods\": 3\n },\n \"SubscriptionData\": {\n \"Subscription\": {\n \"termType\": \"TERMED\",\n \"contractEffectiveDate\": \"2026-05-01\",\n \"initialTerm\": 12\n },\n \"RatePlanData\": [{\n \"RatePlan\": {\"productRatePlanId\": \"2c92...\"}\n }]\n }\n})\n\n# AFTER - Order Preview API\nrequests.post(\"/v1/orders/preview\", json={ # Different endpoint!\n \"orderDate\": \"2026-05-01\",\n \"previewAccountInfo\": { # Changed from newAccount\n \"name\": \"Example Corp\",\n \"currency\": \"USD\",\n \"billCycleDay\": 1,\n \"billToContact\": {...}\n },\n \"previewOptions\": { # Required for preview mode\n \"previewTypes\": [\"BillingDocs\", \"ChargeMetrics\"], # Required! Subscribe API only supports these two\n \"previewNumberOfPeriods\": 3 # Converted from PreviewOptions.numberOfPeriods\n },\n # NO processingOptions in preview mode!\n \"subscriptions\": [{\n \"orderActions\": [{\n \"type\": \"CreateSubscription\",\n \"triggerDates\": [{\n \"name\": \"ContractEffective\",\n \"triggerDate\": \"2026-05-01\"\n }],\n \"createSubscription\": {\n \"terms\": {...},\n \"subscribeToRatePlans\": [{...}]\n }\n }]\n }]\n})\n```\n\n**Key differences for Preview Mode:**\n- **Endpoint**: Use `/v1/orders/preview` (NOT `/v1/orders`)\n- **New Account Field**: Use `previewAccountInfo` (NOT `newAccount`)\n- **Existing Account Field**: Still use `existingAccountNumber` (same as create mode)\n- **Required Field**: Must include `previewOptions` with `previewTypes: [\"BillingDocs\", \"ChargeMetrics\"]` (Subscribe API only supports these two types)\n- **Skip**: Do NOT include `processingOptions` (not applicable in preview)\n- **Response**: Returns preview data (billing docs, metrics) instead of actual IDs\n\n**Create Mode (PreviewOptions absent or empty):**\n\nWhen `PreviewOptions` is NOT provided, the Subscribe API creates actual records. This maps to the Order Create API.\n\n```python\n# BEFORE - Subscribe API without PreviewOptions\nrequests.post(\"/v1/action/subscribe\", json={\n \"Account\": {\n \"name\": \"Example Corp\",\n \"currency\": \"USD\",\n \"billToContact\": {...}\n },\n \"SubscribeOptions\": {\n \"generateInvoice\": True,\n \"processPayments\": True\n },\n \"SubscriptionData\": {\n \"Subscription\": {\n \"termType\": \"TERMED\",\n \"contractEffectiveDate\": \"2026-04-20\",\n \"initialTerm\": 12\n },\n \"RatePlanData\": [{...}]\n }\n})\n\n# AFTER - Order Create API\nrequests.post(\"/v1/orders\", json={ # Standard endpoint\n \"orderDate\": \"2026-04-20\",\n \"newAccount\": { # Use newAccount for new accounts\n \"name\": \"Example Corp\",\n \"currency\": \"USD\",\n \"billToContact\": {...}\n },\n \"processingOptions\": { # Include billing/payment options\n \"runBilling\": True, # From SubscribeOptions.generateInvoice\n \"collect\": True # From SubscribeOptions.processPayments\n },\n \"subscriptions\": [{\n \"orderActions\": [{\n \"type\": \"CreateSubscription\",\n \"triggerDates\": [{\n \"name\": \"ContractEffective\",\n \"triggerDate\": \"2026-04-20\"\n }],\n \"createSubscription\": {\n \"terms\": {...},\n \"subscribeToRatePlans\": [{...}]\n }\n }]\n }]\n})\n```\n\n**Key differences for Create Mode:**\n- **Endpoint**: Use `/v1/orders`\n- **New Account Field**: Use `newAccount`\n- **Existing Account Field**: Use `existingAccountNumber`\n- **Include**: Add `processingOptions` for billing/payment control\n- **Response**: Returns actual `orderNumber`, `subscriptionId`, `invoiceId`, etc.\n\n**Complete conversion example with mode detection:**\n\n```python\n# ============================================================================\n# BEFORE - Subscribe Action API (mode depends on PreviewOptions)\n# ============================================================================\n# subscribe_request = {\n# \"Account\": {\"name\": \"Example Corp\", \"currency\": \"USD\", ...},\n# \"PreviewOptions\": {\"enablePreviewMode\": True, \"numberOfPeriods\": 3}, # or absent\n# \"SubscribeOptions\": {\"generateInvoice\": True, \"processPayments\": True},\n# \"SubscriptionData\": {...}\n# }\n# response = requests.post(\"/v1/action/subscribe\", json=subscribe_request, headers=headers)\n\n# ============================================================================\n# AFTER - Order API with mode detection\n# ============================================================================\n\n# Detect mode based on PreviewOptions presence\nhas_preview = 'PreviewOptions' in subscribe_request and subscribe_request['PreviewOptions']\n\nif has_preview:\n # PREVIEW MODE - Use Order Preview API\n endpoint = f\"{base_url}/v1/orders/preview\"\n \n order_request = {\n \"orderDate\": subscribe_request['SubscriptionData']['Subscription']['contractEffectiveDate'],\n \"previewOptions\": { # Required for preview\n \"previewTypes\": [\"BillingDocs\", \"ChargeMetrics\"], # Subscribe API only supports these two\n \"previewNumberOfPeriods\": subscribe_request['PreviewOptions'].get('numberOfPeriods', 1)\n }\n }\n \n # Handle account info\n if 'accountKey' in subscribe_request['Account']:\n # Existing account - same as create mode\n order_request['existingAccountNumber'] = subscribe_request['Account']['accountKey']\n else:\n # New account - use previewAccountInfo\n order_request['previewAccountInfo'] = {\n \"name\": subscribe_request['Account']['name'],\n \"currency\": subscribe_request['Account']['currency'],\n \"billCycleDay\": subscribe_request['Account'].get('billCycleDay', 0),\n \"billToContact\": subscribe_request['Account'].get('billToContact')\n }\n \n # NO processingOptions in preview mode\n \nelse:\n # CREATE MODE - Use Order Create API\n endpoint = f\"{base_url}/v1/orders\"\n \n order_request = {\n \"orderDate\": subscribe_request['SubscriptionData']['Subscription']['contractEffectiveDate'],\n \"processingOptions\": {\n \"runBilling\": subscribe_request['SubscribeOptions'].get('generateInvoice', False),\n \"collect\": subscribe_request['SubscribeOptions'].get('processPayments', False)\n }\n }\n \n # Handle account info\n if 'accountKey' in subscribe_request['Account']:\n # Existing account\n order_request['existingAccountNumber'] = subscribe_request['Account']['accountKey']\n else:\n # New account - use newAccount\n order_request['newAccount'] = {\n \"name\": subscribe_request['Account']['name'],\n \"currency\": subscribe_request['Account']['currency'],\n \"billCycleDay\": subscribe_request['Account'].get('billCycleDay', 0),\n \"billToContact\": subscribe_request['Account'].get('billToContact'),\n \"paymentMethod\": subscribe_request['Account'].get('paymentMethod') # If provided\n }\n\n# Common subscription structure for both modes\norder_request['subscriptions'] = [{\n \"orderActions\": [{\n \"type\": \"CreateSubscription\",\n \"triggerDates\": [{\n \"name\": \"ContractEffective\",\n \"triggerDate\": subscribe_request['SubscriptionData']['Subscription']['contractEffectiveDate']\n }],\n \"createSubscription\": {\n \"terms\": {\n # Convert term configuration (same for both modes)\n \"initialTerm\": {\n \"period\": subscribe_request['SubscriptionData']['Subscription']['initialTerm'],\n \"periodType\": \"Month\",\n \"termType\": subscribe_request['SubscriptionData']['Subscription']['termType']\n },\n \"autoRenew\": subscribe_request['SubscriptionData']['Subscription'].get('autoRenew', False)\n },\n \"subscribeToRatePlans\": [\n # Convert rate plans (same for both modes)\n ]\n }\n }]\n}]\n\n# Execute the request\nresponse = requests.post(endpoint, json=order_request, headers=headers)\n\n# Handle response (different structure for preview vs create)\nif has_preview:\n # Preview response contains billing docs, metrics, etc.\n preview_invoices = response.json().get('invoices', [])\n preview_metrics = response.json().get('orderMetrics', {})\nelse:\n # Create response contains actual IDs\n order_number = response.json()['orderNumber']\n subscription_id = response.json()['subscriptions'][0]['subscriptionId']\n```\n\n**Important Notes:**\n\n1. **Always detect mode first** before building the request\n2. **Preview mode requires** `previewOptions.previewTypes` array - Subscribe API only supports `[\"BillingDocs\", \"ChargeMetrics\"]` (do NOT include OrderMetrics or other types)\n3. **Preview mode uses** `previewAccountInfo` for new accounts (NOT `newAccount`)\n4. **Create mode requires** `processingOptions` for billing control\n5. **Credit card field names** are different: `creditCardNumber` → `cardNumber`, `creditCardType` → `cardType`\n6. **Response structures** are different between preview and create modes\n\n**Reference:** See `${CLAUDE_PLUGIN_ROOT}/references/action-subscribe-api-mapping.md` for complete field mappings, especially:\n- **Scenario 1 & 2**: Create mode mappings\n- **Scenario 3**: Preview mode mappings\n- **Pattern 0**: Mode detection logic\n\n#### Suspend with Resume Date\n\nThis requires TWO separate actions in Order API:\n\n```python\n# BEFORE - S/A API: Single call with resumeDate\nrequests.put(f\"/v1/subscriptions/{key}/suspend\", json={\n \"suspendPolicy\": \"SpecificDate\",\n \"suspendDate\": \"2026-04-01\",\n \"resumeDate\": \"2026-05-01\"\n})\n\n# AFTER - Order API: Two separate actions\n{\n \"orderActions\": [\n {\n \"type\": \"Suspend\",\n \"triggerDates\": [{\n \"name\": \"ContractEffective\",\n \"triggerDate\": \"2026-04-01\"\n }],\n \"suspend\": {\n \"suspendPolicy\": \"SpecificDate\",\n \"suspendDate\": \"2026-04-01\"\n }\n },\n {\n \"type\": \"Resume\",\n \"resume\": {\n \"resumePolicy\": \"SpecificDate\",\n \"resumeSpecificDate\": \"2026-05-01\",\n \"extendsTerm\": True # Note: extendsTerm goes here, not in Suspend\n }\n }\n ]\n}\n```\n\n#### Multiple Operations in One Order\n\nOrder API allows batching multiple operations:\n\n```python\n# Combine multiple S/A API calls into one Order API call\n{\n \"subscriptions\": [\n {\n \"subscriptionNumber\": \"A-S00000001\",\n \"orderActions\": [\n {\"type\": \"UpdateProduct\", ...},\n {\"type\": \"AddProduct\", ...}\n ]\n },\n {\n \"subscriptionNumber\": \"A-S00000002\",\n \"orderActions\": [\n {\"type\": \"CancelSubscription\", ...}\n ]\n }\n ]\n}\n```\n\n#### Subscribe API: New Account vs Existing Account\n\nSubscribe API can create a new account or use an existing one. This must be detected and handled differently:\n\n```python\n# BEFORE - Subscribe API with NEW account\nrequests.post(\"/v1/action/subscribe\", json={\n \"Account\": {\n \"name\": \"New Customer\",\n \"currency\": \"USD\",\n \"billToContact\": {...},\n \"paymentMethod\": {\n \"type\": \"CreditCard\",\n \"creditCardNumber\": \"4111111111111111\",\n \"creditCardType\": \"Visa\"\n }\n },\n \"SubscriptionData\": {...}\n})\n\n# AFTER - Order API with NEW account\nrequests.post(\"/v1/orders\", json={\n \"orderDate\": \"2026-04-20\",\n \"newAccount\": {\n \"name\": \"New Customer\",\n \"currency\": \"USD\",\n \"billToContact\": {...},\n \"paymentMethod\": {\n \"cardNumber\": \"4111111111111111\", # Field name changed\n \"cardType\": \"Visa\" # Field name changed\n }\n },\n \"subscriptions\": [{\n \"orderActions\": [{\n \"type\": \"CreateSubscription\",\n \"createSubscription\": {...}\n }]\n }]\n})\n\n# BEFORE - Subscribe API with EXISTING account\nrequests.post(\"/v1/action/subscribe\", json={\n \"Account\": {\n \"accountKey\": \"A00000001\" # Using existing account\n },\n \"SubscriptionData\": {...}\n})\n\n# AFTER - Order API with EXISTING account\nrequests.post(\"/v1/orders\", json={\n \"orderDate\": \"2026-04-20\",\n \"existingAccountNumber\": \"A00000001\", # Changed from Account.accountKey\n \"subscriptions\": [{\n \"orderActions\": [{\n \"type\": \"CreateSubscription\",\n \"createSubscription\": {...}\n }]\n }]\n})\n```\n\n**Important:** Order API cannot create payment methods for existing accounts. If the Subscribe API includes a payment method for an existing account, you must:\n1. Note this in a TODO comment\n2. Suggest using the Payment Methods API separately\n3. Or use an existing payment method on the account\n\n#### Subscribe API: Term Configuration\n\nSubscribe API uses simple fields for terms, Order API uses structured objects:\n\n```python\n# BEFORE - Subscribe API with TERMED subscription\n{\n \"Subscription\": {\n \"termType\": \"TERMED\",\n \"initialTerm\": 12,\n \"renewalTerm\": 12,\n \"autoRenew\": True\n }\n}\n\n# AFTER - Order API with TERMED subscription\n{\n \"createSubscription\": {\n \"terms\": {\n \"initialTerm\": {\n \"period\": 12,\n \"periodType\": \"Month\",\n \"termType\": \"TERMED\"\n },\n \"autoRenew\": True,\n \"renewalSetting\": \"RENEW_WITH_SPECIFIC_TERM\",\n \"renewalTerms\": [{\n \"period\": 12,\n \"periodType\": \"Month\"\n }]\n }\n }\n}\n\n# BEFORE - Subscribe API with EVERGREEN subscription\n{\n \"Subscription\": {\n \"termType\": \"EVERGREEN\"\n }\n}\n\n# AFTER - Order API with EVERGREEN subscription\n{\n \"createSubscription\": {\n \"terms\": {\n \"initialTerm\": {\n \"termType\": \"EVERGREEN\"\n },\n \"autoRenew\": False\n }\n }\n}\n```\n\n### Step 5: Generate Supporting Artifacts\n\n**Note:** Supporting artifacts (validation scripts, checklists) are NEW files and can be created with Write tool. Only the actual customer integration code must be modified in-place with Edit tool.\n\n#### Validation Script\n\nGenerate a script to validate the migration in sandbox:\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nOrder API Migration Validation Script\nTests converted code against sandbox environment\n\"\"\"\n\nimport requests\nfrom datetime import datetime\n\n# Configuration\nZUORA_BASE_URL = \"https://rest.sandbox.zuora.com\"\n# TODO: Add authentication credentials\n\ndef test_subscription_cancel():\n \"\"\"Test subscription cancellation with Order API\"\"\"\n # TODO: Get test subscription number from sandbox\n test_subscription = \"A-S00000001\"\n \n # TODO: Implement test\n print(\"Testing subscription cancel...\")\n # [Generated test code based on customer's cancel operation]\n \ndef test_subscription_suspend():\n \"\"\"Test subscription suspension with Order API\"\"\"\n # TODO: Implement test\n pass\n\ndef compare_results(s_a_result, order_result):\n \"\"\"Compare S/A API result with Order API result\"\"\"\n # Check if subscription ended up in same state\n # Compare billing outcomes\n # Validate field values\n pass\n\nif __name__ == \"__main__\":\n test_subscription_cancel()\n test_subscription_suspend()\n # Add more tests based on detected operations\n```\n\n#### Migration Checklist\n\nGenerate a checklist document:\n\n```markdown\n# Order API Migration Implementation Checklist\n\n## Pre-Migration\n\n- [ ] Review migration plan from `/zuora-order-migration-design`\n- [ ] Sandbox environment has Order API enabled\n- [ ] Test accounts and subscriptions created in sandbox\n- [ ] Authentication credentials configured for sandbox\n\n## Code Changes\n\n### Subscription Cancel Operation (customer_code.py:45-52)\n\n- [ ] Added `orderDate` field\n- [ ] Added `existingAccountNumber` field (TODO: source account number)\n- [ ] Converted `invoiceCollect` to `processingOptions`\n- [ ] Moved subscription key from URL to request body\n- [ ] Added `type: \"CancelSubscription\"` field\n- [ ] Converted `cancellationEffectiveDate` to `triggerDates`\n- [ ] Updated response handling code\n- [ ] Added error handling for Order API errors\n\n### Subscribe Action API Operation (customer_code.py:XX-YY)\n\n**Mode Detection:**\n- [ ] Detected if PreviewOptions present in original code\n- [ ] Routed to correct Order API endpoint based on mode\n\n**If Preview Mode (PreviewOptions present):**\n- [ ] Changed endpoint to `/v1/orders/preview`\n- [ ] Changed `newAccount` to `previewAccountInfo` (for new accounts)\n- [ ] Added required `previewOptions.previewTypes` array\n- [ ] Removed `processingOptions` (not applicable in preview)\n- [ ] Converted `PreviewOptions.numberOfPeriods` to `previewOptions.previewNumberOfPeriods`\n- [ ] Updated response handling for preview structure (billing docs, metrics)\n\n**If Create Mode (PreviewOptions absent):**\n- [ ] Used endpoint `/v1/orders`\n- [ ] Used `newAccount` or `existingAccountNumber` based on Account.accountKey presence\n- [ ] Converted `SubscribeOptions` to `processingOptions`\n- [ ] Updated credit card field names (creditCardNumber → cardNumber, creditCardType → cardType)\n- [ ] Updated response handling for create structure (orderNumber, subscriptionId)\n\n**Common to Both Modes:**\n- [ ] Added `orderDate` field\n- [ ] Converted term configuration to structured format (initialTerm, renewalTerms)\n- [ ] Added `renewalSetting` when autoRenew is true\n- [ ] Converted `contractEffectiveDate` to `triggerDates`\n- [ ] Converted `RatePlanData` to `subscribeToRatePlans`\n- [ ] Noted payment method limitation for existing accounts (if applicable)\n\n[Repeat for each operation]\n\n## Testing\n\n- [ ] Unit tests pass locally\n- [ ] Sandbox test for cancel operation\n- [ ] Sandbox test for suspend operation\n- [ ] Sandbox test for resume operation\n- [ ] Sandbox test for renew operation\n- [ ] Sandbox test for Subscribe Action API (create mode) - verify actual subscription created\n- [ ] Sandbox test for Subscribe Action API (preview mode) - verify no records created, preview data returned\n- [ ] Verify subscription states in Zuora UI\n- [ ] Verify billing/invoices generated correctly\n- [ ] Test error scenarios\n\n## Integration Updates\n\n- [ ] Updated downstream systems for new response structure\n- [ ] Updated logging/monitoring for orderNumber\n- [ ] Updated webhooks/callbacks if needed\n\n## Production Readiness\n\n- [ ] Code review completed\n- [ ] All tests passing\n- [ ] Rollback plan documented\n- [ ] Production deployment scheduled\n```\n\n### Step 6: Use Zuora Codegen (Optional)\n\nIf using `mcp__zuora-mcp__zuora_codegen` for additional guidance:\n\n1. Call `code_guidance` with \"Order API migration\"\n2. Call `get_api_details` for Order API endpoints\n3. Call `get_model_details` for Order request/response models\n4. Call `code_rules` for validation rules\n\n### Step 7: Provide Testing Guidance\n\n**Unit Testing:**\n```python\ndef test_order_api_cancel_request():\n \"\"\"Test Order API cancel request structure\"\"\"\n request = build_cancel_order_request(\n subscription_key=\"A-S00000123\",\n account_number=\"A00000001\",\n cancel_date=\"2026-09-01\"\n )\n \n assert request['orderDate'] is not None\n assert request['existingAccountNumber'] == \"A00000001\"\n assert len(request['subscriptions']) == 1\n assert request['subscriptions'][0]['orderActions'][0]['type'] == \"CancelSubscription\"\n```\n\n**Integration Testing in Sandbox:**\n\n1. Create test subscription in sandbox\n2. Execute converted code against sandbox\n3. Verify subscription state changed correctly\n4. Check billing/invoice generation\n5. Compare with expected S/A API behavior\n\n### Step 8: Document Key Changes\n\nSummarize what changed (emphasizing in-place modifications):\n\n```markdown\n## Summary of Changes\n\n### File: customer_code.py (Modified in-place)\n\n**Lines 45-65: Subscription Cancel (Original code commented out, converted code added)**\n- Changed endpoint: PUT /v1/subscriptions/{key}/cancel → POST /v1/orders\n- Added required fields: orderDate, existingAccountNumber\n- Converted invoiceCollect → processingOptions.runBilling + processingOptions.collect\n- Moved subscription key from URL to request body\n- Updated response handling: subscriptionId path changed\n- **PR diff will show:** Old code commented out (lines with #), new Order API code added\n\n**Lines 120-145: Subscription Suspend (Original code commented out, converted code added)**\n- Changed endpoint: PUT /v1/subscriptions/{key}/suspend → POST /v1/orders\n- Added suspend with resume date handling (two separate actions)\n- Added extendsTerm field in Resume action (not Suspend)\n- Updated response handling\n- **PR diff will show:** Clear before/after comparison in the same file\n\n[Continue for each file and operation]\n\n## New Dependencies\n\n- None (using same HTTP client library)\n\n## Configuration Changes\n\n- Need to source account numbers (not in S/A API calls)\n- Need to set orderDate for each request\n\n## Breaking Changes\n\n- Response structure changed\n- Error response format changed\n- Field names changed (invoiceCollect → processingOptions)\n\n## Testing Requirements\n\n- Sandbox testing required before production\n- All operations must be tested\n- Edge cases must be validated\n```\n\n### Step 9: Suggest Next Steps\n\nAfter generating code:\n\n1. **Verify all modifications were done in-place** (no new `*_converted` files created)\n2. Review PR diff to confirm before/after is clearly visible\n3. Review all converted code with customer\n4. Address all TODO items (account numbers, dates, etc.)\n5. Run validation script in sandbox\n6. Update integration points\n7. Run `/zuora-validate` on modified code\n8. Plan production deployment\n\n**Final Checklist:**\n- [ ] All customer integration files modified with Edit tool (not Write tool)\n- [ ] Original API code preserved as comments (BEFORE section)\n- [ ] Converted Order API code added with clear markers (AFTER section)\n- [ ] No new `*_converted.py` or `*_order_api.py` files created\n- [ ] PR diff clearly shows what changed in each file\n- [ ] For Subscribe API: Detected if preview mode (PreviewOptions present) or create mode\n- [ ] For Subscribe API: Preview mode uses `/v1/orders/preview` endpoint with `previewAccountInfo`\n- [ ] For Subscribe API: Create mode uses `/v1/orders` endpoint with `newAccount` or `existingAccountNumber`\n- [ ] For Subscribe API: Preview mode includes required `previewOptions.previewTypes` array\n- [ ] For Subscribe API: Create mode includes `processingOptions` (not used in preview)\n- [ ] For Subscribe API: Detected if new or existing account\n- [ ] For Subscribe API: Credit card field names updated (creditCardNumber → cardNumber)\n- [ ] For Subscribe API: Term configuration converted to structured format\n- [ ] For Subscribe API: Payment method handling noted (Order API limitation for existing accounts)\n- [ ] Supporting artifacts (validation scripts, checklists) created as separate new files\n"
}SHA-256 of public snapshot: fc9b4082c4431ec075b4af3785c450498a5f3bbf68547077ac23135e51ed5069