{"info":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[],"description":"<html><head></head><body></body></html>","owner":"42632822","collectionId":"53f3b62c-89a1-4d64-8456-aac75f451f9c","publishedId":"2sB2x5Ht3y","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"0f5ef9"},"publishDate":"2025-06-11T18:45:26.000Z"},"item":[{"name":"Checkout API","item":[{"name":"Customers","item":[{"name":"Blacklist Customer","id":"1db97e4f-9cec-4fb7-b697-c5d7b9ad4925","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"chargeback","type":"text"},{"key":"types[]","value":"email","type":"text","disabled":true},{"key":"types[]","value":"phone","type":"text","disabled":true},{"key":"cancel_subscriptions","value":"true","type":"text","disabled":true},{"key":"cancel_fulfillments","value":"true","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/customers/{{customer_number}}/blacklist","description":"<h1 id=\"blacklist-customer\">Blacklist Customer</h1>\n<p>Add a customer to the blacklist to prevent future transactions</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:customers.blacklist.add</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>types</td>\n<td><em>array (optional)</em>  <br />Types of customer data to blacklist. If not provided, all types will be blacklisted. Valid values: <code>email</code>, <code>phone</code>, <code>ip</code>, <code>address</code></td>\n</tr>\n<tr>\n<td>reason</td>\n<td><strong>string (required)</strong>  <br />Reason for blacklisting the customer. Minimum length: 3 characters, Maximum length: 500 characters</td>\n</tr>\n<tr>\n<td>cancel_subscriptions</td>\n<td><em>boolean (optional)</em>  <br />Whether to cancel active subscriptions. Default: true. Accepted values: true, false, 1, 0</td>\n</tr>\n<tr>\n<td>cancel_fulfillments</td>\n<td><em>boolean (optional)</em>  <br />Whether to cancel pending fulfillments. Default: true. Accepted values: true, false, 1, 0</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.customer_id</td>\n<td><strong>string</strong>  <br />The UUID of the blacklisted customer</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong>  <br />The unique customer number</td>\n</tr>\n<tr>\n<td>data.blacklisted_items</td>\n<td><strong>array</strong>  <br />List of items that were blacklisted (e.g., [\"Email: <a href=\"https://mailto:john@example.com\">john@example.com</a>\", \"Phone: +1234567890\"])</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions</td>\n<td><strong>object</strong>  <br />Information about canceled subscriptions</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions.count</td>\n<td><strong>integer</strong>  <br />Number of subscriptions that were canceled</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions.subscription_numbers</td>\n<td><strong>array</strong>  <br />List of subscription numbers that were canceled</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments</td>\n<td><strong>object</strong>  <br />Information about canceled fulfillments</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments.count</td>\n<td><strong>integer</strong>  <br />Number of fulfillments that were canceled</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments.fulfillment_ids</td>\n<td><strong>array</strong>  <br />List of fulfillment IDs that were canceled</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>Customer is already blacklisted</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Customer not found</td>\n</tr>\n<tr>\n<td>500</td>\n<td>Failed to blacklist customer due to server error</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","customers","{{customer_number}}","blacklist"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"c64b336f-257b-4546-bc17-48ac55834786","name":"Success","originalRequest":{"method":"POST","header":[],"url":{"raw":"https://api.sparkcrm.io/checkout/customers/{{customer_number}}/blacklist?reason=chargeback","protocol":"https","host":["api","sparkcrm","io"],"path":["checkout","customers","{{customer_number}}","blacklist"],"query":[{"key":"reason","value":"chargeback"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.10"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Fri, 01 Aug 2025 03:39:08 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Customer successfully blacklisted\",\n    \"data\": {\n        \"customer_number\": \"CUST-250724-00093\",\n        \"blacklisted_items\": [\n            \"Email: ssmitham@example.net\",\n            \"Phone: +13528407944\",\n            \"IP: 164.165.94.14\",\n            \"Address: 274 Myah Valley Suite 430, New Sasha\"\n        ],\n        \"canceled_subscriptions\": {\n            \"count\": 0,\n            \"subscription_numbers\": []\n        },\n        \"canceled_fulfillments\": {\n            \"count\": 0,\n            \"fulfillment_ids\": []\n        }\n    }\n}"}],"_postman_id":"1db97e4f-9cec-4fb7-b697-c5d7b9ad4925"},{"name":"Remove Blacklist","id":"d1bc9c7f-36c9-4c6f-8769-2f67aee74c73","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"reversal","type":"text","uuid":"793c8c4d-7700-4ee0-a5d8-bac04a3465b9"}]},"url":"https://api.sparkcrm.io/checkout/customers/{{customer_number}}/remove-blacklist","description":"<h1 id=\"remove-customer-from-blacklist\">Remove Customer from Blacklist</h1>\n<p>Remove a customer from the blacklist to allow future transactions</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:customers.blacklist.remove</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>reason</td>\n<td><strong>string (required)</strong>  <br />Reason for removing the customer from blacklist. Minimum length: 3 characters, Maximum length: 500 characters</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.customer_id</td>\n<td><strong>string</strong>  <br />The UUID of the customer</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong>  <br />The unique customer number</td>\n</tr>\n<tr>\n<td>data.entries_deactivated</td>\n<td><strong>integer</strong>  <br />Number of blacklist entries that were deactivated</td>\n</tr>\n<tr>\n<td>data.previously_blacklisted</td>\n<td><strong>array</strong>  <br />List of items that were previously blacklisted (e.g., [\"Email: <a href=\"https://mailto:john@example.com\">john@example.com</a>\", \"Phone: +1234567890\"])</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>Customer is not blacklisted</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Customer not found</td>\n</tr>\n<tr>\n<td>500</td>\n<td>Failed to remove customer from blacklist due to server error</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","customers","{{customer_number}}","remove-blacklist"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"194190d4-ffd5-4477-a872-e291ce277ef4","name":"Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"reversal","type":"text","uuid":"793c8c4d-7700-4ee0-a5d8-bac04a3465b9"}]},"url":"https://sparkcrm.test/checkout/customers/{{customer_number}}/remove-blacklist"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.10"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Fri, 01 Aug 2025 03:58:15 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Customer successfully removed from blacklist\",\n    \"data\": {\n        \"customer_number\": \"CUST-250724-00093\",\n        \"entries_deactivated\": 4,\n        \"previously_blacklisted\": [\n            \"email\",\n            \"phone\",\n            \"ip\",\n            \"address\"\n        ]\n    }\n}"}],"_postman_id":"d1bc9c7f-36c9-4c6f-8769-2f67aee74c73"},{"name":"Blacklist Status","id":"f1abed56-afe9-47c5-9311-6042cb54d0be","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[]},"url":"https://api.sparkcrm.io/checkout/customers/{{customer_number}}/blacklist-status","description":"<h1 id=\"check-customer-blacklist-status\">Check Customer Blacklist Status</h1>\n<p>Check if a customer is blacklisted and view their blacklist details</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:customers.blacklist.check</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body required. The customer is identified by the customer_number in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the customer blacklist information</td>\n</tr>\n<tr>\n<td>data.customer_id</td>\n<td><strong>string</strong>  <br />The UUID of the customer</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong>  <br />The unique customer number</td>\n</tr>\n<tr>\n<td>data.is_blacklisted</td>\n<td><strong>boolean</strong>  <br />Indicates whether the customer is currently blacklisted</td>\n</tr>\n<tr>\n<td>data.blacklisted_types</td>\n<td><strong>array</strong>  <br />List of blacklisted items if customer is blacklisted (e.g., [\"Email: <a href=\"https://mailto:john@example.com\">john@example.com</a>\", \"Phone: +1234567890\"]). Empty array if not blacklisted</td>\n</tr>\n<tr>\n<td>data.active_subscriptions</td>\n<td><strong>integer</strong>  <br />Number of active subscriptions the customer has</td>\n</tr>\n<tr>\n<td>data.pending_fulfillments</td>\n<td><strong>integer</strong>  <br />Number of pending fulfillments the customer has</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>404</td>\n<td>Customer not found</td>\n</tr>\n<tr>\n<td>500</td>\n<td>Failed to check blacklist status due to server error</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","customers","{{customer_number}}","blacklist-status"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"249f1cac-6e4f-41b6-a682-cb4e318e851e","name":"Success","originalRequest":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[]},"url":"https://api.sparkcrm.io/checkout/customers/{{customer_number}}/blacklist-status"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.10"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Fri, 01 Aug 2025 04:13:28 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"customer_number\": \"CUST-250724-00093\",\n        \"is_blacklisted\": false,\n        \"blacklisted_types\": [],\n        \"active_subscriptions\": 0,\n        \"pending_fulfillments\": 0\n    }\n}"}],"_postman_id":"f1abed56-afe9-47c5-9311-6042cb54d0be"},{"name":"Cancel Subscriptions","id":"33b5e5f8-b6b2-4cef-a266-41a623e9e882","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"poor","type":"text","uuid":"06a95777-6816-4d2c-aa42-9aa01939306c"},{"key":"subscription_number","value":"","type":"text","uuid":"731a002f-d3fe-418a-ab56-67433e2bb1ed","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/customers/{{identifier}}/cancel-subscriptions","description":"<h1 id=\"cancel-customer-subscriptions\">Cancel Customer Subscriptions</h1>\n<p>Cancel all or specific subscriptions for a customer</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:customers.subscriptions.cancel</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>reason</td>\n<td><strong>string (required)</strong>  <br />Reason for canceling the subscription(s). Minimum length: 3 characters, Maximum length: 500 characters</td>\n</tr>\n<tr>\n<td>subscription_number</td>\n<td><em>string (optional)</em>  <br />Specific subscription number to cancel. If not provided, all cancelable subscriptions for the customer will be canceled</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.customer_id</td>\n<td><strong>string</strong>  <br />The UUID of the customer</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong>  <br />The unique customer number</td>\n</tr>\n<tr>\n<td>data.canceled_count</td>\n<td><strong>integer</strong>  <br />Number of subscriptions that were canceled</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions</td>\n<td><strong>array</strong>  <br />List of canceled subscription details</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].subscription_id</td>\n<td><strong>integer</strong>  <br />Internal ID of the subscription</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].subscription_number</td>\n<td><strong>string</strong>  <br />Unique subscription number</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].previous_status</td>\n<td><strong>string</strong>  <br />Status of the subscription before cancellation</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].billing_interval</td>\n<td><strong>string</strong>  <br />Billing interval (e.g., \"monthly\", \"weekly\")</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].billing_cycle</td>\n<td><strong>integer</strong>  <br />Current billing cycle number</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].total_cycles</td>\n<td><strong>integer</strong>  <br />Total number of billing cycles (null for unlimited)</td>\n</tr>\n<tr>\n<td>data.canceled_subscriptions[].next_billing_at</td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp of when the next billing was scheduled (before cancellation)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>No cancelable subscriptions found or subscription does not belong to customer</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Customer or subscription not found</td>\n</tr>\n<tr>\n<td>500</td>\n<td>Failed to cancel subscriptions due to server error</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"notes\">Notes</h2>\n<ul>\n<li><p>The endpoint accepts either a customer_number or subscription_number as the identifier in the URL path</p>\n</li>\n<li><p>If a subscription_number is provided in the URL, only that subscription will be canceled</p>\n</li>\n<li><p>If a customer_number is provided in the URL and no subscription_number in the request body, all cancelable subscriptions will be canceled</p>\n</li>\n<li><p>If both URL identifier and request body subscription_number are provided, the subscription must belong to the specified customer</p>\n</li>\n</ul>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","customers","{{identifier}}","cancel-subscriptions"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"1a2dce6b-2260-4c3c-88cc-13d501218821","name":"Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"poor","type":"text","uuid":"06a95777-6816-4d2c-aa42-9aa01939306c"},{"key":"subscription_number","value":"","type":"text","uuid":"731a002f-d3fe-418a-ab56-67433e2bb1ed","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/customers/{{identifier}}/cancel-subscriptions"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.10"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Fri, 01 Aug 2025 04:23:38 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Subscriptions successfully canceled\",\n    \"data\": {\n        \"customer_number\": \"CUST-250724-00142\",\n        \"canceled_count\": 2,\n        \"canceled_subscriptions\": [\n            {\n                \"subscription_number\": \"SUB-250724-00042\",\n                \"previous_status\": \"paused\",\n                \"billing_interval\": 365,\n                \"billing_cycle\": 8,\n                \"total_cycles\": null,\n                \"next_billing_at\": \"2025-09-30T07:57:11+00:00\"\n            },\n            {\n                \"subscription_number\": \"SUB-250724-00041\",\n                \"previous_status\": \"paused\",\n                \"billing_interval\": 365,\n                \"billing_cycle\": 10,\n                \"total_cycles\": null,\n                \"next_billing_at\": \"2025-08-02T17:18:16+00:00\"\n            }\n        ]\n    }\n}"}],"_postman_id":"33b5e5f8-b6b2-4cef-a266-41a623e9e882"},{"name":"Cancel Fulfillments","id":"99415fd4-f76a-472b-ab04-8a3dbaf85095","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"poor","type":"text","uuid":"c1329ab8-7023-4758-a085-f473bb644afa"},{"key":"fulfillment_number","value":"","type":"text","uuid":"6e111c27-83c0-4b6a-a628-d026b9f9c029","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/customers/{{identifier}}/cancel-fulfillments","description":"<h1 id=\"cancel-customer-fulfillments\">Cancel Customer Fulfillments</h1>\n<p>Cancel all or specific fulfillments for a customer</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:customers.fulfillments.cancel</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>reason</td>\n<td><strong>string (required)</strong>  <br />Reason for canceling the fulfillment(s). Minimum length: 3 characters, Maximum length: 500 characters</td>\n</tr>\n<tr>\n<td>fulfillment_number</td>\n<td><em>string (optional)</em>  <br />Specific fulfillment number to cancel. If not provided, all cancelable fulfillments for the customer will be canceled</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.customer_id</td>\n<td><strong>string</strong>  <br />The UUID of the customer</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong>  <br />The unique customer number</td>\n</tr>\n<tr>\n<td>data.canceled_count</td>\n<td><strong>integer</strong>  <br />Number of fulfillments that were canceled</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments</td>\n<td><strong>array</strong>  <br />List of canceled fulfillment details</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].fulfillment_id</td>\n<td><strong>integer</strong>  <br />Internal database ID of the fulfillment</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].fulfillment_number</td>\n<td><strong>string</strong>  <br />Unique fulfillment number (format: FUL-YYMMDD-00001)</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].shipping_group_number</td>\n<td><strong>string</strong>  <br />Shipping group identifier</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].order_number</td>\n<td><strong>string</strong>  <br />Order number associated with this fulfillment</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].previous_status</td>\n<td><strong>string</strong>  <br />Status of the fulfillment before cancellation</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items</td>\n<td><strong>array</strong>  <br />List of items in the fulfillment</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].product_id</td>\n<td><strong>integer</strong>  <br />Base product ID</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].product_name</td>\n<td><strong>string</strong>  <br />Name of the product</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].product_sku</td>\n<td><strong>string</strong>  <br />Product SKU</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].quantity</td>\n<td><strong>integer</strong>  <br />Quantity of the product</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].unit_price</td>\n<td><strong>string</strong>  <br />Price per unit</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].total_price</td>\n<td><strong>number</strong>  <br />Total price for this line item</td>\n</tr>\n<tr>\n<td>data.canceled_fulfillments[].items[].product_options</td>\n<td><strong>object/null</strong>  <br />Product options/variations if applicable</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>No cancelable fulfillments found, fulfillment not cancelable, or fulfillment does not belong to customer</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Customer or fulfillment not found</td>\n</tr>\n<tr>\n<td>500</td>\n<td>Failed to cancel fulfillments due to server error</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"notes\">Notes</h2>\n<ul>\n<li><p>The endpoint accepts either a customer_number or fulfillment_number as the identifier in the URL path</p>\n</li>\n<li><p>If a fulfillment_number is provided in the URL, only that fulfillment will be canceled</p>\n</li>\n<li><p>If a customer_number is provided in the URL and no fulfillment_number in the request body, all cancelable fulfillments will be canceled</p>\n</li>\n<li><p>If both URL identifier and request body fulfillment_number are provided, the fulfillment must belong to the specified customer</p>\n</li>\n<li><p>Only fulfillments with status PENDING, PROCESSING, or ON_HOLD can be canceled</p>\n</li>\n</ul>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","customers","{{identifier}}","cancel-fulfillments"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"473f29a4-e422-46c1-a24b-e9db8bd8f2cb","name":"Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"reason","value":"poor","type":"text","uuid":"c1329ab8-7023-4758-a085-f473bb644afa"},{"key":"fulfillment_number","value":"","type":"text","uuid":"6e111c27-83c0-4b6a-a628-d026b9f9c029","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/customers/{{identifier}}/cancel-fulfillments"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.10"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Fri, 01 Aug 2025 04:49:06 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Fulfillments successfully canceled\",\n    \"data\": {\n        \"customer_number\": \"CUST-250724-00047\",\n        \"canceled_count\": 1,\n        \"canceled_fulfillments\": [\n            {\n                \"fulfillment_number\": \"FUL-250819-00002\",\n                \"shipping_group_number\": \"1708ba8e-b831-36c2-b6c5-2ecfaaff2de9\",\n                \"order_number\": \"ORD-250724-00098\",\n                \"previous_status\": \"canceled\",\n                \"items\": [\n                    {\n                        \"quantity\": 1,\n                        \"product_id\": 1,\n                        \"unit_price\": \"299.99\",\n                        \"product_sku\": \"SKU-4553wt\",\n                        \"total_price\": 299.99,\n                        \"product_name\": \"Smart Watch Pro\",\n                        \"base_quantity\": 1,\n                        \"order_quantity\": 1,\n                        \"product_options\": null\n                    },\n                    {\n                        \"quantity\": 1,\n                        \"product_id\": 4,\n                        \"unit_price\": \"399.99\",\n                        \"product_sku\": \"SKU-0517id\",\n                        \"total_price\": 399.99,\n                        \"product_name\": \"Robot Vacuum Cleaner\",\n                        \"base_quantity\": 1,\n                        \"order_quantity\": 1,\n                        \"product_options\": null\n                    },\n                    {\n                        \"quantity\": 1,\n                        \"product_id\": 5,\n                        \"unit_price\": \"49.99\",\n                        \"product_sku\": \"SKU-6171je\",\n                        \"total_price\": 49.99,\n                        \"product_name\": \"Classic Leather Wallet\",\n                        \"base_quantity\": 1,\n                        \"order_quantity\": 1,\n                        \"product_options\": null\n                    },\n                    {\n                        \"quantity\": 1,\n                        \"product_id\": 6,\n                        \"unit_price\": \"129.99\",\n                        \"product_sku\": \"SKU-2358bq\",\n                        \"total_price\": 129.99,\n                        \"product_name\": \"Sunglasses\",\n                        \"base_quantity\": 1,\n                        \"order_quantity\": 1,\n                        \"product_options\": null\n                    },\n                    {\n                        \"quantity\": 1,\n                        \"product_id\": 7,\n                        \"unit_price\": \"39.99\",\n                        \"product_sku\": \"SKU-7205vh\",\n                        \"total_price\": 39.99,\n                        \"product_name\": \"Yoga Mat\",\n                        \"base_quantity\": 1,\n                        \"order_quantity\": 1,\n                        \"product_options\": null\n                    }\n                ]\n            }\n        ]\n    }\n}"}],"_postman_id":"99415fd4-f76a-472b-ab04-8a3dbaf85095"}],"id":"57d3637c-b297-41e1-b977-f4a780362db5","_postman_id":"57d3637c-b297-41e1-b977-f4a780362db5","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Orders","item":[{"name":"Create Lead","id":"f7dea564-ff3c-4527-9555-316d6f205996","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250321-00001","description":"<p>Optional. Forces an update of this order instead of creating a new lead, as long as it is not in a complete/terminal status.</p>\n","type":"text","disabled":true},{"key":"customer[email]","value":"test@example.com","type":"text"},{"key":"customer[first_name]","value":"John","type":"text"},{"key":"customer[last_name]","value":"Doe","type":"text"},{"key":"customer[phone]","value":"5551234567","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"New York","type":"text"},{"key":"shipping[state]","value":"NY","type":"text"},{"key":"shipping[postal_code]","value":"10001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"best deals","type":"text"},{"key":"utm_content","value":"banner1","type":"text"},{"key":"affiliate","value":"AFF123","type":"text"},{"key":"sub1","value":"SUB456","type":"text"},{"key":"custom_fields[partner_ref]","value":"ACME-2024-Q4","type":"text"},{"key":"custom_fields[landing_variant]","value":"hero-v3","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[1][offer_id]","value":"2","type":"text"},{"key":"products[1][quantity]","value":"1","type":"text"},{"key":"ip_address","value":"192.168.1.1","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"},{"key":"enrich","value":"true","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/leads","description":"<h2 id=\"create-lead\">Create Lead</h2>\n<p>Create a new lead within Spark CRM.</p>\n<blockquote>\n<p><strong>Updating an existing order:</strong> Pass <code>order_number</code> to force this request to <strong>update</strong> that specific order instead of creating a new lead. The order must belong to your team and must <strong>not</strong> be in a completed, successful, or terminal status (completed, processing, refunded, partially/externally/RDR/alert refunded, disputed, chargeback, voided, or canceled) — otherwise the request is rejected with a <code>422</code>. If no order matches the <code>order_number</code> for your team, the request is also rejected with a <code>422</code>.</p>\n</blockquote>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><em>string (optional)</em>  <br />When provided, forces an <strong>update</strong> of the matching order for this contact instead of creating a new lead. The order must not be in a complete/successful or terminal status, otherwise the request is rejected. If no order matches this <code>order_number</code> for your team, the request is rejected. Maximum length: 50 characters</td>\n</tr>\n<tr>\n<td>customer[email]</td>\n<td><strong>string (required)</strong>  <br />The customer's email address</td>\n</tr>\n<tr>\n<td>customer[first_name]</td>\n<td><em>string (optional)</em>  <br />The customer's first name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>customer[last_name]</td>\n<td><em>string (optional)</em>  <br />The customer's last name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>customer[phone]</td>\n<td><em>string (optional)</em>  <br />The customer's phone number. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>shipping</td>\n<td><em>object (optional)</em>  <br />Shipping address. If omitted, the lead is created without an address. If provided, all sub-fields below (except <code>address2</code> and <code>phone</code>) must be included.</td>\n</tr>\n<tr>\n<td>shipping[address1]</td>\n<td><em>string (optional)</em>  <br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping[address2]</td>\n<td><em>string (optional)</em>  <br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping[city]</td>\n<td><em>string (optional)</em>  <br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>shipping[state]</td>\n<td><em>string (optional)</em>  <br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>shipping[postal_code]</td>\n<td><em>string (optional)</em>  <br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>shipping[country]</td>\n<td><em>string (optional)</em>  <br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n<tr>\n<td>shipping[phone]</td>\n<td><em>string (optional)</em>  <br />Phone number for shipping-related inquiries. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>campaign_id</td>\n<td><strong>string (required)</strong>  <br />Internal ID for the campaign</td>\n</tr>\n<tr>\n<td>currency</td>\n<td><strong>string (required)</strong>  <br />Three-letter currency code (ISO 4217). Must be exactly 3 characters</td>\n</tr>\n<tr>\n<td>cohort</td>\n<td><em>string (optional)</em>  <br />Cohort identifier. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_source</td>\n<td><em>string (optional)</em>  <br />UTM source parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_medium</td>\n<td><em>string (optional)</em>  <br />UTM medium parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_campaign</td>\n<td><em>string (optional)</em>  <br />UTM campaign parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_term</td>\n<td><em>string (optional)</em>  <br />UTM term parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_content</td>\n<td><em>string (optional)</em>  <br />UTM content parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>affiliate</td>\n<td><em>string (optional)</em>  <br />Affiliate name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub1</td>\n<td><em>string (optional)</em>  <br />Sub-affiliate parameter 1. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub2</td>\n<td><em>string (optional)</em>  <br />Sub-affiliate parameter 2. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub3</td>\n<td><em>string (optional)</em>  <br />Sub-affiliate parameter 3. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub4</td>\n<td><em>string (optional)</em>  <br />Sub-affiliate parameter 4. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub5</td>\n<td><em>string (optional)</em>  <br />Sub-affiliate parameter 5. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>custom_fields</td>\n<td><em>object (optional)</em>  <br />Arbitrary key/value tracking data. Send as <code>custom_fields[key]=value</code>. Max 50 keys; key ≤64 chars, value ≤1000 chars.</td>\n</tr>\n<tr>\n<td>products</td>\n<td><strong>array (required)</strong>  <br />Array of product objects to be ordered</td>\n</tr>\n<tr>\n<td>products[].offer_id</td>\n<td><strong>string (required)</strong>  <br />Internal ID for the campaign offer</td>\n</tr>\n<tr>\n<td>products[].quantity</td>\n<td><strong>integer (required)</strong>  <br />Quantity of this product. Minimum value: 1</td>\n</tr>\n<tr>\n<td>products[].price</td>\n<td><em>numeric (optional)</em>  <br />Unit price for this product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>products[].shipping_price</td>\n<td><em>numeric (optional)</em>  <br />Shipping price for this product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>ip_address</td>\n<td><em>string (optional)</em>  <br />Customer's IP address. Must be a valid IP format</td>\n</tr>\n<tr>\n<td>user_agent</td>\n<td><em>string (optional)</em>  <br />Customer's browser user agent string</td>\n</tr>\n<tr>\n<td>enrich</td>\n<td><em>string (optional)</em>  <br />Request synchronous validation and enrichment data. Accepts: true, false, 1, 0, yes, no</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result. <code>Lead created successfully</code> for a new lead (HTTP 201) or <code>Lead updated successfully</code> when an existing order was updated (HTTP 200)</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the order created or updated from the lead</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the customer created from the lead</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","leads"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"4a5fb82a-83de-4a55-99ca-2e0de3a35bf1","name":"Create Lead Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"customer[email]","value":"test@example.com","type":"text"},{"key":"customer[first_name]","value":"John","type":"text"},{"key":"customer[last_name]","value":"Doe","type":"text"},{"key":"customer[phone]","value":"5551234567","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"New York","type":"text"},{"key":"shipping[state]","value":"NY","type":"text"},{"key":"shipping[postal_code]","value":"10001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"best deals","type":"text"},{"key":"utm_content","value":"banner1","type":"text"},{"key":"affiliate_id","value":"AFF123","type":"text"},{"key":"sub_affiliate_id","value":"SUB456","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[1][offer_id]","value":"2","type":"text"},{"key":"products[1][quantity]","value":"1","type":"text"},{"key":"ip_address","value":"192.168.1.1","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/leads"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 01:59:46 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=Nc5ftQchAVTQV3lbJ7RkWGNq3cU8lWX4b8fJkJTzPIRmVEuzrVuWNkPp1oNww0lyGHqKXoOMR5ZR%2Fmdvarjw%2BhgGwirsqT6MfLMr5QmR%2B9izl1z8zoBKpVW9VMS743FO2K8%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"9239da10699572e4-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=15506&min_rtt=12915&rtt_var=6694&sent=4&recv=5&lost=0&retrans=0&sent_bytes=2808&recv_bytes=1526&delivery_rate=226093&cwnd=241&unsent_bytes=0&cid=476eec69ddb92594&ts=178&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Lead created successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-250321-00001\",\n        \"customer_number\": \"CUST-250321-00001\"\n    }\n}"}],"_postman_id":"f7dea564-ff3c-4527-9555-316d6f205996"},{"name":"Process Payment","id":"f17491b4-9a64-4b34-b96b-965d375d3fe8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"type":"text","key":"order_number","value":"ORD-250321-00001"},{"description":"<p>Optional. Updates the order's contact email. Empty values are ignored.</p>\n","key":"customer[email]","value":"updated@example.com","type":"text","disabled":true},{"description":"<p>Optional. Updates the contact first name. Empty values are ignored.</p>\n","key":"customer[first_name]","value":"Jane","type":"text","disabled":true},{"description":"<p>Optional. Updates the contact last name. Empty values are ignored.</p>\n","key":"customer[last_name]","value":"Doe","type":"text","disabled":true},{"description":"<p>Optional. Updates the contact phone. Empty values are ignored.</p>\n","key":"customer[phone]","value":"5559876543","type":"text","disabled":true},{"type":"text","key":"payment[method]","value":"card"},{"type":"text","key":"payment[card_number]","value":"4111111111111111"},{"type":"text","key":"payment[card_exp_month]","value":"12"},{"type":"text","key":"payment[card_exp_year]","value":"2025"},{"type":"text","key":"payment[card_cvv]","value":"123"},{"type":"text","key":"billing[address1]","value":"123 Main St"},{"type":"text","key":"billing[address2]","value":"Apt 4B"},{"type":"text","key":"billing[city]","value":"New York"},{"type":"text","key":"billing[state]","value":"NY"},{"type":"text","key":"billing[postal_code]","value":"10001"},{"type":"text","key":"billing[country]","value":"US"},{"type":"text","key":"coupon_code","value":"","disabled":true},{"type":"text","key":"campaign_id","value":"","disabled":true},{"type":"text","key":"shipping[address1]","value":"456 Oak Ave","disabled":true},{"type":"text","key":"shipping[address2]","value":"Suite 100","disabled":true},{"type":"text","key":"shipping[city]","value":"Los Angeles","disabled":true},{"type":"text","key":"shipping[state]","value":"CA","disabled":true},{"type":"text","key":"shipping[postal_code]","value":"90001","disabled":true},{"type":"text","key":"shipping[country]","value":"US","disabled":true},{"type":"text","key":"shipping[phone]","value":"555-123-4567","disabled":true},{"type":"text","key":"billing[phone]","value":"555-987-6543","disabled":true},{"type":"text","key":"products[0][offer_id]","value":"offer_abc123","disabled":true},{"type":"text","key":"products[0][quantity]","value":"1","disabled":true},{"type":"text","key":"products[0][price]","value":"29.99","disabled":true},{"type":"text","key":"products[0][shipping_price]","value":"4.99","disabled":true},{"type":"text","key":"tax_amount","value":"2.62","disabled":true},{"type":"text","key":"tax_rate","value":"0.0875","disabled":true},{"type":"text","key":"forceQA","value":"false","disabled":true},{"type":"text","key":"gateway_id","value":"1","disabled":true},{"type":"text","key":"payment_orchestrator_id","value":"1","disabled":true},{"type":"text","key":"terms_accepted","value":"true","disabled":true},{"type":"text","key":"privacy_accepted","value":"true","disabled":true},{"type":"text","key":"custom_fields[partner_ref]","value":"ACME-2024-Q4","disabled":true},{"type":"text","key":"custom_fields[stage]","value":"checkout","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/payment","description":"<h1 id=\"process-payment\">Process Payment</h1>\n<p>Process a payment for an existing lead that was created from the <a href=\"#0617be4e-81c0-4fa2-8747-31a0c164bab5\">Create Lead endpoint</a></p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong>  <br />The order number to process payment for</td>\n</tr>\n<tr>\n<td>campaign_id</td>\n<td><em>string (optional)</em>  <br />Internal ID for the campaign. Must be a valid campaign</td>\n</tr>\n<tr>\n<td>customer</td>\n<td><em>object (optional)</em>  <br />Customer fields to update on the order's existing contact. Any provided field updates the contact in place; <strong>empty values are ignored</strong> so they never overwrite existing data. Useful for completing a lead that was created without a name or phone.</td>\n</tr>\n<tr>\n<td>customer[email]</td>\n<td><em>string (optional)</em>  <br />Updated email address</td>\n</tr>\n<tr>\n<td>customer[first_name]</td>\n<td><em>string (optional)</em>  <br />Updated first name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>customer[last_name]</td>\n<td><em>string (optional)</em>  <br />Updated last name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>customer[phone]</td>\n<td><em>string (optional)</em>  <br />Updated phone number. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>payment[method]</td>\n<td><strong>string (required)</strong>  <br />Payment method type. Allowed values: <code>card</code> (provide card details), <code>onfile</code> (use customer's saved payment method), <code>external</code> (external/manual payment such as Zelle, Cash App, Venmo, Bank Transfer), <code>paypal_wallet</code> (PayPal Wallet with redirect flow)</td>\n</tr>\n<tr>\n<td>payment[card_number]</td>\n<td><strong>string (required for card payments)</strong>  <br />Credit/debit card number</td>\n</tr>\n<tr>\n<td>payment[card_exp]</td>\n<td><strong>string (conditionally required for card payments)</strong>  <br />Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if card_exp_month and card_exp_year are not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_month]</td>\n<td><strong>string (conditionally required for card payments)</strong>  <br />Two-digit expiration month (01-12). Must be exactly 2 characters. Required if card_exp is not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_year]</td>\n<td><strong>string (conditionally required for card payments)</strong>  <br />Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if card_exp is not provided</td>\n</tr>\n<tr>\n<td>payment[card_cvv]</td>\n<td><strong>string (required for card payments)</strong>  <br />Card verification value. Length: 3-4 characters</td>\n</tr>\n<tr>\n<td>payment[external_payment_id]</td>\n<td><em>integer (optional)</em>  <br />The ID of a configured alternative payment method. Use <code>GET /v1/alternative-payments</code> to retrieve available IDs. When used with <code>method: \"external\"</code>, the transaction will be linked to the specific payment type (e.g., Zelle, Cash App). When used with <code>method: \"paypal_wallet\"</code>, selects a specific PayPal configuration if multiple exist</td>\n</tr>\n<tr>\n<td>payment[return_url]</td>\n<td><strong>string (required for paypal_wallet)</strong>  <br />URL to redirect the customer to after they approve the PayPal payment. Must be a valid URL</td>\n</tr>\n<tr>\n<td>payment[cancel_url]</td>\n<td><strong>string (required for paypal_wallet)</strong>  <br />URL to redirect the customer to if they cancel the PayPal payment. Must be a valid URL</td>\n</tr>\n<tr>\n<td>forceQA</td>\n<td><em>boolean (optional)</em>  <br />Forces the order into QA (quality assurance) review. Accepts: \"true\", \"false\", \"1\", \"0\"</td>\n</tr>\n<tr>\n<td>coupon_code</td>\n<td><em>string (optional)</em>  <br />Coupon code to apply to the order. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping</td>\n<td><em>array (optional)</em>  <br />Shipping address object</td>\n</tr>\n<tr>\n<td>shipping[address1]</td>\n<td><strong>string (required if shipping provided)</strong>  <br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping[address2]</td>\n<td><em>string (optional)</em>  <br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping[city]</td>\n<td><strong>string (required if shipping provided)</strong>  <br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>shipping[state]</td>\n<td><strong>string (required if shipping provided)</strong>  <br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>shipping[postal_code]</td>\n<td><strong>string (required if shipping provided)</strong>  <br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>shipping[country]</td>\n<td><strong>string (required if shipping provided)</strong>  <br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n<tr>\n<td>shipping[phone]</td>\n<td><em>string (optional)</em>  <br />Phone number. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>billing</td>\n<td><em>array (optional)</em>  <br />Billing address object</td>\n</tr>\n<tr>\n<td>billing[address1]</td>\n<td><em>string (optional)</em>  <br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>billing[address2]</td>\n<td><em>string (optional)</em>  <br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>billing[city]</td>\n<td><em>string (optional)</em>  <br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>billing[state]</td>\n<td><em>string (optional)</em>  <br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>billing[postal_code]</td>\n<td><em>string (optional)</em>  <br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>billing[country]</td>\n<td><em>string (optional)</em>  <br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n<tr>\n<td>billing[phone]</td>\n<td><em>string (optional)</em>  <br />Phone number for billing-related inquiries. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em>integer (optional)</em>  <br />The gateway ID to <strong>force</strong> for this charge, bypassing the campaign's normal gateway/orchestrator routing. Must reference an <strong>active</strong> gateway, otherwise the request fails with <code>gateway_not_found</code>. Leave empty/null (or omit) to use normal routing.</td>\n</tr>\n<tr>\n<td>payment_orchestrator_id</td>\n<td><em>integer (optional)</em>  <br />The payment orchestrator ID to route this charge through. Must reference an <strong>active</strong> orchestrator. Leave empty/null (or omit) to use the campaign's configured routing. Ignored when <code>gateway_id</code> is also provided (a forced gateway takes precedence).</td>\n</tr>\n<tr>\n<td>products</td>\n<td><em>array (optional)</em>  <br />Array of product objects to update in the order</td>\n</tr>\n<tr>\n<td>products[].offer_id</td>\n<td><strong>string (required if products provided)</strong>  <br />Internal ID for the campaign offer</td>\n</tr>\n<tr>\n<td>products[].quantity</td>\n<td><strong>integer (required if products provided)</strong>  <br />Quantity of this product. Minimum value: 1</td>\n</tr>\n<tr>\n<td>products[].price</td>\n<td><em>numeric (optional)</em>  <br />Unit price for this product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>products[].shipping_price</td>\n<td><em>numeric (optional)</em>  <br />Shipping price for this product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>tax_amount</td>\n<td><em>numeric (optional)</em>  <br />Pre-calculated sales tax to charge the customer. Typically obtained from a prior call to <code>POST /checkout/tax</code>. Always honored when provided — the customer will be billed this amount regardless of the campaign's tax provider configuration. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>tax_rate</td>\n<td><em>numeric (optional)</em>  <br />Effective tax rate used when <code>tax_amount</code> was calculated (e.g. <code>0.0875</code> for 8.875%). Stored on the order for reporting; does not affect the charged amount. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>terms_accepted</td>\n<td><em>boolean (optional)</em>  <br />Indicates customer acceptance of terms and conditions. Accepts: \"true\", \"false\", \"1\", \"0\"</td>\n</tr>\n<tr>\n<td>privacy_accepted</td>\n<td><em>boolean (optional)</em>  <br />Indicates customer acceptance of privacy policy. Accepts: \"true\", \"false\", \"1\", \"0\"</td>\n</tr>\n<tr>\n<td>custom_fields</td>\n<td><em>object (optional)</em>  <br />Arbitrary key/value tracking data, merged into the lead's existing custom fields. Send as <code>custom_fields[key]=value</code>. Max 50 keys; key ≤64 chars, value ≤1000 chars.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"updating-the-customer\">Updating the Customer</h2>\n<p>Pass any <code>customer[...]</code> fields to update the order's existing contact at payment time — handy for completing a lead created with only an email. Provided fields are written to the contact; <strong>empty values are skipped</strong> so a blank never overwrites an existing name, email, or phone.</p>\n<h2 id=\"payment-method-flows\">Payment Method Flows</h2>\n<h3 id=\"card--on-file\">Card / On File</h3>\n<p>Standard payment processing. The order is created and payment is captured immediately.</p>\n<h3 id=\"external-zelle-cash-app-venmo-bank-transfer\">External (Zelle, Cash App, Venmo, Bank Transfer)</h3>\n<p>For payments processed outside the platform. Set <code>payment.method</code> to <code>\"external\"</code> and optionally pass <code>payment.external_payment_id</code> to link the transaction to a specific alternative payment method configured in the CRM. The order completes immediately with no gateway interaction.</p>\n<h3 id=\"paypal-wallet\">PayPal Wallet</h3>\n<p>Redirect-based payment flow requiring three steps:</p>\n<ol>\n<li><p><strong>Process Payment</strong> — Call this endpoint with <code>payment.method</code> set to <code>\"paypal_wallet\"</code>, along with <code>return_url</code> and <code>cancel_url</code>. The response includes a <code>redirect_url</code>.</p>\n</li>\n<li><p><strong>Customer Approval</strong> — Redirect the customer to the <code>redirect_url</code>. They log in to PayPal and approve the payment. PayPal redirects them back to your <code>return_url</code>.</p>\n</li>\n<li><p><strong>Capture Payment</strong> — Call <code>POST /checkout/orders/capture</code> with the <code>order_number</code> to finalize the charge. Money does not move until this step.</p>\n</li>\n</ol>\n<h2 id=\"tax-handling\">Tax Handling</h2>\n<p>Two ways to populate the order's tax:</p>\n<ul>\n<li><strong>Pass it in</strong> — supply <code>tax_amount</code> (and optionally <code>tax_rate</code>) in the request body. Typical flow: call <code>POST /checkout/tax</code> first to get the calculated values, then pass them here to lock in what the customer saw on the checkout page. The customer is always charged the <code>tax_amount</code> you supply.</li>\n<li><strong>Let the server compute it</strong> — omit both fields. When the campaign has an active TaxJar provider, the server auto-calculates tax against the shipping address at payment time.</li>\n</ul>\n<p><strong>Charge vs. report are separate decisions:</strong></p>\n<ul>\n<li><code>tax_amount</code> controls what the customer pays.</li>\n<li>Whether the order is forwarded to TaxJar depends on the campaign's <code>tax_enabled</code> flag + active provider. If the campaign has tax disabled, the customer is still charged the supplied <code>tax_amount</code>, but nothing is reported to TaxJar's books.</li>\n</ul>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the order that was processed</td>\n</tr>\n<tr>\n<td>data.transaction_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the payment transaction</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Current status of the order after payment processing (\"processing\")</td>\n</tr>\n<tr>\n<td>data.gateway_descriptor</td>\n<td><strong>string</strong>  <br />Statement descriptor from the payment gateway used for the transaction. Only included if the gateway has a descriptor configured</td>\n</tr>\n<tr>\n<td>data.gateway_id</td>\n<td><strong>integer | null</strong>  <br />The gateway ID that processed (or attempted) the charge. Returned on both approved and declined payments; <code>null</code> for external/PayPal payments or when no gateway was attempted. Pass this back as the request <code>gateway_id</code> to force the same gateway on a retry.</td>\n</tr>\n<tr>\n<td>data.subscription_created</td>\n<td><strong>boolean</strong>  <br />Indicates if a subscription was created during payment processing</td>\n</tr>\n<tr>\n<td>data.total</td>\n<td><strong>number</strong>  <br />Total amount of the order (subtotal + shipping + tax)</td>\n</tr>\n<tr>\n<td>data.tax_amount</td>\n<td><strong>string</strong>  <br />Sales tax portion of the order total, formatted to 2 decimals. <code>0.00</code> when no tax was applied.</td>\n</tr>\n<tr>\n<td>data.tax_rate</td>\n<td><strong>number</strong>  <br />Effective tax rate recorded on the order (e.g. <code>0.0875</code> for 8.875%). <code>0</code> when no rate was set.</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code (ISO 4217) used for the transaction</td>\n</tr>\n<tr>\n<td>data.redirect_url</td>\n<td><strong>string (paypal_wallet only)</strong>  <br />PayPal checkout URL to redirect the customer to for payment approval. Only returned when <code>payment.method</code> is <code>\"paypal_wallet\"</code></td>\n</tr>\n<tr>\n<td>data.payment_status</td>\n<td><strong>string</strong>  <br />Status of the payment transaction. Values: <code>completed</code>, <code>declined</code>, <code>pending_redirect</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders","payment"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"335c9b5d-93c5-47f7-aa00-e01f4b77f2ae","name":"Process Payment Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250321-00001","type":"text"},{"key":"payment[method]","value":"card","type":"text"},{"key":"payment[card_number]","value":"4111111111111111","type":"text"},{"key":"payment[card_exp_month]","value":"12","type":"text"},{"key":"payment[card_exp_year]","value":"2025","type":"text"},{"key":"payment[card_cvv]","value":"123","type":"text"},{"key":"billing[address1]","value":"123 Main St","type":"text"},{"key":"billing[address2]","value":"Apt 4B","type":"text"},{"key":"billing[city]","value":"New York","type":"text"},{"key":"billing[state]","value":"NY","type":"text"},{"key":"billing[postal_code]","value":"10001","type":"text"},{"key":"billing[country]","value":"US","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/payment"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:13:55 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=wO7xtC5U8FgDQWDTrTPEKHwSKTpLPTzYxZc77sfAX678LxELygJpa7tG9DB7XQAnHUMw4DGaXSFdbkXp7IWnpq1r86RKDUyt%2FLz7Usxut%2BmJmJ4R35P%2B2esK5XTKxDYjIRc%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"9239eec33ecbd240-ORD"},{"key":"Content-Encoding","value":"br"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=14917&min_rtt=14417&rtt_var=6407&sent=4&recv=5&lost=0&retrans=0&sent_bytes=2809&recv_bytes=1094&delivery_rate=158506&cwnd=176&unsent_bytes=0&cid=81e16b49815f1fb3&ts=2202&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Payment processed successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-250321-00001\",\n        \"transaction_number\": \"TXN-250321-000001\",\n        \"status\": \"processing\",\n        \"subscription_created\": true,\n        \"subscription_number\": \"SUB-250321-000001\",\n        \"gateway_descriptor\": \"test descriptor\",\n        \"gateway_id\": 1,\n        \"total\": 689.97,\n        \"currency\": \"USD\"\n    }\n}"}],"_postman_id":"f17491b4-9a64-4b34-b96b-965d375d3fe8"},{"name":"Create Order","id":"1899e07a-8eae-420d-a0b5-e672a69746ed","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"value":"test4@example.com","key":"customer[email]","type":"text"},{"value":"George","key":"customer[first_name]","type":"text"},{"value":"Foreman","key":"customer[last_name]","type":"text"},{"value":"7777777777","key":"customer[phone]","type":"text"},{"value":"123 Main St","key":"shipping[address1]","type":"text"},{"value":"Apt 4B","key":"shipping[address2]","type":"text"},{"value":"Los Angeles","key":"shipping[city]","type":"text"},{"value":"CA","key":"shipping[state]","type":"text"},{"value":"90001","key":"shipping[postal_code]","type":"text"},{"value":"US","key":"shipping[country]","type":"text"},{"value":"5551234567","key":"shipping[phone]","type":"text"},{"value":"123 Main St","key":"billing[address1]","type":"text"},{"value":"Apt 4B","key":"billing[address2]","type":"text"},{"value":"Los Angeles","key":"billing[city]","type":"text"},{"value":"CA","key":"billing[state]","type":"text"},{"value":"90001","key":"billing[postal_code]","type":"text"},{"value":"US","key":"billing[country]","type":"text"},{"value":"5551234567","key":"billing[phone]","type":"text"},{"value":"card","key":"payment[method]","type":"text"},{"value":"4111111111111111","key":"payment[card_number]","type":"text"},{"value":"12","key":"payment[card_exp_month]","type":"text"},{"value":"2025","key":"payment[card_exp_year]","type":"text"},{"value":"123","key":"payment[card_cvv]","type":"text"},{"value":"1","key":"campaign_id","type":"text"},{"value":"USD","key":"currency","type":"text"},{"value":"google","key":"utm_source","type":"text"},{"value":"cpc","key":"utm_medium","type":"text"},{"value":"summer_sale","key":"utm_campaign","type":"text"},{"value":"dtc_products","key":"utm_term","type":"text"},{"value":"banner_1","key":"utm_content","type":"text"},{"value":"AFF001","key":"affiliate","type":"text"},{"value":"SUB001","key":"sub1","type":"text"},{"value":"ACME-2024-Q4","key":"custom_fields[partner_ref]","type":"text"},{"value":"hero-v3","key":"custom_fields[landing_variant]","type":"text"},{"value":"1","key":"products[0][offer_id]","type":"text"},{"value":"1","key":"products[0][quantity]","type":"text"},{"value":"49.98","key":"products[0][price]","type":"text","disabled":true},{"value":"4.70","key":"products[0][shipping_price]","type":"text","disabled":true},{"value":"2","key":"products[1][offer_id]","type":"text","disabled":true},{"value":"2","key":"products[1][quantity]","type":"text","disabled":true},{"value":"29.99","key":"products[1][price]","type":"text","disabled":true},{"value":"0.00","key":"products[1][shipping_price]","type":"text","disabled":true},{"value":"4.37","key":"tax_amount","type":"text","disabled":true},{"value":"0.0875","key":"tax_rate","type":"text","disabled":true},{"value":"192.168.1.2","key":"ip_address","type":"text"},{"value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","key":"user_agent","type":"text"},{"type":"text","value":"true","key":"is_subscription","description":"<p>Set to true when the order is being placed as a 3rd-party-managed subscription so it appears in the customer's subscription records and subscription reports.</p>\n","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders","description":"<h1 id=\"create-order\">Create Order</h1>\n<p>Create a new order within the CRM</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>customer[email]</td>\n<td><strong>string (required)</strong><br />The customer's email address</td>\n</tr>\n<tr>\n<td>customer[first_name]</td>\n<td><strong>string (required)</strong><br />The customer's first name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>customer[last_name]</td>\n<td><strong>string (required)</strong><br />The customer's last name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>customer[phone]</td>\n<td><em>string (optional)</em><br />The customer's phone number. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>shipping[address1]</td>\n<td><strong>string (required)</strong><br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping[address2]</td>\n<td><em>string (optional)</em><br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>shipping[city]</td>\n<td><strong>string (required)</strong><br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>shipping[state]</td>\n<td><strong>string (required)</strong><br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>shipping[postal_code]</td>\n<td><strong>string (required)</strong><br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>shipping[country]</td>\n<td><strong>string (required)</strong><br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n<tr>\n<td>shipping[phone]</td>\n<td><em>string (optional)</em><br />Phone number for shipping-related inquiries. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>billing[address1]</td>\n<td><em>string (optional)</em><br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>billing[address2]</td>\n<td><em>string (optional)</em><br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>billing[city]</td>\n<td><em>string (optional)</em><br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>billing[state]</td>\n<td><em>string (optional)</em><br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>billing[postal_code]</td>\n<td><em>string (optional)</em><br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>billing[country]</td>\n<td><em>string (optional)</em><br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n<tr>\n<td>billing[phone]</td>\n<td><em>string (optional)</em><br />Phone number for billing-related inquiries. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>payment[method]</td>\n<td><strong>string (required)</strong><br />Payment method type. Allowed values: <code>card</code> (provide card details), <code>onfile</code> (use customer's saved payment method), <code>external</code> (external/manual payment such as Zelle, Cash App, Venmo, Bank Transfer), <code>paypal_wallet</code> (PayPal Wallet with redirect flow)</td>\n</tr>\n<tr>\n<td>payment[card_number]</td>\n<td><strong>string (required for card payments)</strong><br />Credit/debit card number</td>\n</tr>\n<tr>\n<td>payment[card_exp]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if card_exp_month and card_exp_year are not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_month]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Two-digit expiration month (01-12). Must be exactly 2 characters. Required if card_exp is not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_year]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if card_exp is not provided</td>\n</tr>\n<tr>\n<td>payment[card_cvv]</td>\n<td><strong>string (required for card payments)</strong><br />Card verification value. Length: 3-4 characters</td>\n</tr>\n<tr>\n<td>payment[external_payment_id]</td>\n<td><em>integer (optional)</em><br />The ID of a configured alternative payment method. Use <code>GET /v1/alternative-payments</code> to retrieve available IDs. When used with <code>method: \"external\"</code>, the transaction will be linked to the specific payment type (e.g., Zelle, Cash App). When used with <code>method: \"paypal_wallet\"</code>, selects a specific PayPal configuration if multiple exist</td>\n</tr>\n<tr>\n<td>payment[return_url]</td>\n<td><strong>string (required for paypal_wallet)</strong><br />URL to redirect the customer to after they approve the PayPal payment. Must be a valid URL</td>\n</tr>\n<tr>\n<td>payment[cancel_url]</td>\n<td><strong>string (required for paypal_wallet)</strong><br />URL to redirect the customer to if they cancel the PayPal payment. Must be a valid URL</td>\n</tr>\n<tr>\n<td>coupon_code</td>\n<td><em>string (optional)</em><br />Coupon code to apply to the order. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em>integer (optional)</em><br />The gateway ID to <strong>force</strong> for this charge, bypassing the campaign's normal gateway/orchestrator routing. Must reference an <strong>active</strong> gateway, otherwise the request fails with <code>gateway_not_found</code>. Leave empty/null (or omit) to use normal routing.</td>\n</tr>\n<tr>\n<td>payment_orchestrator_id</td>\n<td><em>integer (optional)</em><br />The payment orchestrator ID to route this charge through. Must reference an <strong>active</strong> orchestrator. Leave empty/null (or omit) to use the campaign's configured routing. Ignored when <code>gateway_id</code> is also provided (a forced gateway takes precedence).</td>\n</tr>\n<tr>\n<td>forceQA</td>\n<td><em>boolean (optional)</em><br />Forces the order into QA (quality assurance) review. Accepts: \"true\", \"false\", \"1\", \"0\"</td>\n</tr>\n<tr>\n<td>is_subscription</td>\n<td><em>boolean (optional)</em><br />Marks the order as a 3rd-party-managed subscription. When true, an externally-managed subscription record is created on the order so it appears in the customer's subscription records and subscription reports. Spark does not bill or schedule this subscription — lifecycle is handled by the external manager. Accepts: \"true\", \"false\", \"1\", \"0\". Default: false</td>\n</tr>\n<tr>\n<td>campaign_id</td>\n<td><strong>integer (required)</strong><br />Internal ID for the campaign</td>\n</tr>\n<tr>\n<td>currency</td>\n<td><strong>string (required)</strong><br />Three-letter currency code (ISO 4217). Must be exactly 3 characters</td>\n</tr>\n<tr>\n<td>cohort</td>\n<td><em>string (optional)</em><br />Cohort identifier. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_source</td>\n<td><em>string (optional)</em><br />UTM source parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_medium</td>\n<td><em>string (optional)</em><br />UTM medium parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_campaign</td>\n<td><em>string (optional)</em><br />UTM campaign parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_term</td>\n<td><em>string (optional)</em><br />UTM term parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>utm_content</td>\n<td><em>string (optional)</em><br />UTM content parameter. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>affiliate</td>\n<td><em>string (optional)</em><br />Affiliate name. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub1</td>\n<td><em>string (optional)</em><br />Sub-affiliate parameter 1. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub2</td>\n<td><em>string (optional)</em><br />Sub-affiliate parameter 2. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub3</td>\n<td><em>string (optional)</em><br />Sub-affiliate parameter 3. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub4</td>\n<td><em>string (optional)</em><br />Sub-affiliate parameter 4. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub5</td>\n<td><em>string (optional)</em><br />Sub-affiliate parameter 5. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>custom_fields</td>\n<td><em>object (optional)</em><br />Arbitrary key/value tracking data. Send as <code>custom_fields[key]=value</code>. Max 50 keys; key ≤64 chars, value ≤1000 chars.</td>\n</tr>\n<tr>\n<td>products</td>\n<td><strong>array (required)</strong><br />Array of product objects to be ordered</td>\n</tr>\n<tr>\n<td>products[].offer_id</td>\n<td><strong>integer (required)</strong><br />Internal ID for the campaign offer</td>\n</tr>\n<tr>\n<td>products[].quantity</td>\n<td><strong>integer (required)</strong><br />Quantity of this product. Minimum value: 1</td>\n</tr>\n<tr>\n<td>products[].price</td>\n<td><em>numeric (optional)</em><br />Unit price for this product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>products[].shipping_price</td>\n<td><em>numeric (optional)</em><br />Shipping price for this product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>tax_amount</td>\n<td><em>numeric (optional)</em><br />Pre-calculated sales tax to charge the customer. Typically obtained from a prior call to <code>POST /checkout/tax</code>. Always honored when provided — the customer will be billed this amount regardless of the campaign's tax provider configuration. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>tax_rate</td>\n<td><em>numeric (optional)</em><br />Effective tax rate used when <code>tax_amount</code> was calculated (e.g. <code>0.0875</code> for 8.875%). Stored on the order for reporting; does not affect the charged amount. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>ip_address</td>\n<td><em>string (optional)</em><br />Customer's IP address. Must be a valid IP format</td>\n</tr>\n<tr>\n<td>user_agent</td>\n<td><em>string (optional)</em><br />Customer's browser user agent string</td>\n</tr>\n<tr>\n<td>terms_accepted</td>\n<td><em>boolean (optional)</em><br />Indicates customer acceptance of terms and conditions. Accepts: \"true\", \"false\", \"1\", \"0\"</td>\n</tr>\n<tr>\n<td>privacy_accepted</td>\n<td><em>boolean (optional)</em><br />Indicates customer acceptance of privacy policy. Accepts: \"true\", \"false\", \"1\", \"0\"</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"payment-method-flows\">Payment Method Flows</h2>\n<h3 id=\"card--on-file\">Card / On File</h3>\n<p>Standard payment processing. The order is created and payment is captured immediately.</p>\n<h3 id=\"external-zelle-cash-app-venmo-bank-transfer\">External (Zelle, Cash App, Venmo, Bank Transfer)</h3>\n<p>For payments processed outside the platform. Set <code>payment.method</code> to <code>\"external\"</code> and optionally pass <code>payment.external_payment_id</code> to link the transaction to a specific alternative payment method configured in the CRM. The order completes immediately with no gateway interaction.</p>\n<h3 id=\"paypal-wallet\">PayPal Wallet</h3>\n<p>Redirect-based payment flow requiring three steps:</p>\n<ol>\n<li><strong>Create Order</strong> — Call this endpoint with <code>payment.method</code> set to <code>\"paypal_wallet\"</code>, along with <code>return_url</code> and <code>cancel_url</code>. The response includes a <code>redirect_url</code>.</li>\n<li><strong>Customer Approval</strong> — Redirect the customer to the <code>redirect_url</code>. They log in to PayPal and approve the payment. PayPal redirects them back to your <code>return_url</code>.</li>\n<li><strong>Capture Payment</strong> — Call <code>POST /checkout/orders/capture</code> with the <code>order_number</code> to finalize the charge. Money does not move until this step.</li>\n</ol>\n<h2 id=\"tax-handling\">Tax Handling</h2>\n<p>Two ways to populate the order's tax:</p>\n<ul>\n<li><strong>Pass it in</strong> — supply <code>tax_amount</code> (and optionally <code>tax_rate</code>) in the request body. Typical flow: call <code>POST /checkout/tax</code> first to get the calculated values, then pass them here to lock in what the customer saw on the checkout page. The customer is always charged the <code>tax_amount</code> you supply.</li>\n<li><strong>Let the server compute it</strong> — omit both fields. When the campaign has an active TaxJar provider, the server auto-calculates tax against the shipping address at order-save time.</li>\n</ul>\n<p><strong>Charge vs. report are separate decisions:</strong></p>\n<ul>\n<li><code>tax_amount</code> controls what the customer pays.</li>\n<li>Whether the order is forwarded to TaxJar depends on the campaign's <code>tax_enabled</code> flag + active provider. If the campaign has tax disabled, the customer is still charged the supplied <code>tax_amount</code>, but nothing is reported to TaxJar's books.</li>\n</ul>\n<h2 id=\"3rd-party-managed-subscriptions\">3rd-Party-Managed Subscriptions</h2>\n<p>Set <code>is_subscription=true</code> when this order is being placed for a customer whose subscription lifecycle is handled by an external subscription manager. Spark records a synthetic externally-managed subscription on the order so it surfaces in the customer's subscription records and subscription reports — but does <strong>not</strong> schedule billing, fire process-reminder webhooks, or attempt renewals on it. The external system is responsible for billing the customer.</p>\n<p>This flag is independent of any subscription-typed offer/upsell on the order. If the order's offer/upsell is configured with sale type <code>3rd Party Subscription Manager</code>, that path produces its own externally-managed subscription with the configured <code>external_provider</code>, <code>process_reminder_hours_before</code>, and <code>billing_interval_days</code> — <code>is_subscription</code> is only needed for one-off external-subscription orders that don't use a configured offer.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong><br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong><br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong><br />Unique identifier for the newly created order</td>\n</tr>\n<tr>\n<td>data.customer_number</td>\n<td><strong>string</strong><br />Unique identifier for the customer</td>\n</tr>\n<tr>\n<td>data.transaction_number</td>\n<td><strong>string</strong><br />Unique identifier for the payment transaction</td>\n</tr>\n<tr>\n<td>data.total</td>\n<td><strong>number</strong><br />Total amount of the order (subtotal + shipping + tax)</td>\n</tr>\n<tr>\n<td>data.tax_amount</td>\n<td><strong>string</strong><br />Sales tax portion of the order total, formatted to 2 decimals. <code>0.00</code> when no tax was applied.</td>\n</tr>\n<tr>\n<td>data.tax_rate</td>\n<td><strong>number</strong><br />Effective tax rate recorded on the order (e.g. <code>0.0875</code> for 8.875%). <code>0</code> when no rate was set.</td>\n</tr>\n<tr>\n<td>data.gateway_descriptor</td>\n<td><strong>string</strong><br />Statement descriptor from the payment gateway used for the transaction. Only included if the gateway has a descriptor configured</td>\n</tr>\n<tr>\n<td>data.gateway_id</td>\n<td><strong>integer | null</strong><br />The gateway ID that processed (or attempted) the charge. Returned on both approved and declined payments; <code>null</code> for external/PayPal payments or when no gateway was attempted. Pass this back as the request <code>gateway_id</code> to force the same gateway on a retry.</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong><br />Three-letter currency code (ISO 4217) used for the order</td>\n</tr>\n<tr>\n<td>data.subscription_created</td>\n<td><strong>boolean</strong><br />Indicates if a subscription was created with this order</td>\n</tr>\n<tr>\n<td>data.order_reused</td>\n<td><strong>boolean</strong><br />Indicates if an existing order was reused instead of creating a new one</td>\n</tr>\n<tr>\n<td>data.redirect_url</td>\n<td><strong>string (paypal_wallet only)</strong><br />PayPal checkout URL to redirect the customer to for payment approval. Only returned when <code>payment.method</code> is <code>\"paypal_wallet\"</code></td>\n</tr>\n<tr>\n<td>data.payment_status</td>\n<td><strong>string</strong><br />Status of the payment transaction. Values: <code>completed</code>, <code>declined</code>, <code>pending_redirect</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"ad46bacb-4f37-465d-803f-5bc814b91ec4","name":"Create Order Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"customer[email]","value":"test2@example.com","type":"text"},{"key":"customer[first_name]","value":"Test","type":"text"},{"key":"customer[last_name]","value":"Tester","type":"text"},{"key":"customer[phone]","value":"7777777777","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"Los Angeles","type":"text"},{"key":"shipping[state]","value":"CA","type":"text"},{"key":"shipping[postal_code]","value":"90001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"shipping[phone]","value":"5551234567","type":"text"},{"key":"billing[address1]","value":"123 Main St","type":"text"},{"key":"billing[address2]","value":"Apt 4B","type":"text"},{"key":"billing[city]","value":"Los Angeles","type":"text"},{"key":"billing[state]","value":"CA","type":"text"},{"key":"billing[postal_code]","value":"90001","type":"text"},{"key":"billing[country]","value":"US","type":"text"},{"key":"billing[phone]","value":"5551234567","type":"text"},{"key":"payment[method]","value":"card","type":"text"},{"key":"payment[card_number]","value":"4111111111111111","type":"text"},{"key":"payment[card_exp_month]","value":"12","type":"text"},{"key":"payment[card_exp_year]","value":"2025","type":"text"},{"key":"payment[card_cvv]","value":"123","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"dtc_products","type":"text"},{"key":"utm_content","value":"banner_1","type":"text"},{"key":"affiliate_id","value":"AFF001","type":"text"},{"key":"sub_affiliate_id","value":"SUB001","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[0][price]","value":"49.98","type":"text","disabled":true},{"key":"products[0][shipping_price]","value":"4.70","type":"text","disabled":true},{"key":"products[1][offer_id]","value":"2","type":"text","disabled":true},{"key":"products[1][quantity]","value":"2","type":"text","disabled":true},{"key":"products[1][price]","value":"29.99","type":"text","disabled":true},{"key":"products[1][shipping_price]","value":"0.00","type":"text","disabled":true},{"key":"ip_address","value":"192.168.1.2","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:24:52 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=G52BtvYuUSc3Jjjcxy8hMfD5NZxR3gynJGJFzPQtENFQ7DDfZqHHREhTXU2Jn34uZ%2FwmfxBmd73xA%2BuZvRaT2zE8X4rvKEOmi6CK8PIB2uBKxkA13pVsK0wXJuPhyW1JcIQ%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"9239fececdefead8-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=20596&min_rtt=14117&rtt_var=9664&sent=54&recv=55&lost=0&retrans=0&sent_bytes=5626&recv_bytes=3412&delivery_rate=302925&cwnd=239&unsent_bytes=0&cid=4e9c5de4e4a6f6b3&ts=48106&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Order created successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-250321-00002\",\n        \"customer_number\": \"CUST-250321-00002\",\n        \"transaction_number\": \"TXN-250321-000004\",\n        \"subscription_number\": \"SUB-250321-000004\",\n        \"gateway_descriptor\": \"test descriptor\",\n        \"gateway_id\": 1,\n        \"total\": 289.98,\n        \"currency\": \"USD\",\n        \"subscription_created\": false,\n        \"order_reused\": false\n    }\n}"},{"id":"ebf2e064-1a67-795a-b502-d81c2c703a04","name":"422 — Max Orders Per Email Reached","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"value":"test4@example.com","key":"customer[email]","type":"text"},{"value":"George","key":"customer[first_name]","type":"text"},{"value":"Foreman","key":"customer[last_name]","type":"text"},{"value":"7777777777","key":"customer[phone]","type":"text"},{"value":"123 Main St","key":"shipping[address1]","type":"text"},{"value":"Apt 4B","key":"shipping[address2]","type":"text"},{"value":"Los Angeles","key":"shipping[city]","type":"text"},{"value":"CA","key":"shipping[state]","type":"text"},{"value":"90001","key":"shipping[postal_code]","type":"text"},{"value":"US","key":"shipping[country]","type":"text"},{"value":"5551234567","key":"shipping[phone]","type":"text"},{"value":"123 Main St","key":"billing[address1]","type":"text"},{"value":"Apt 4B","key":"billing[address2]","type":"text"},{"value":"Los Angeles","key":"billing[city]","type":"text"},{"value":"CA","key":"billing[state]","type":"text"},{"value":"90001","key":"billing[postal_code]","type":"text"},{"value":"US","key":"billing[country]","type":"text"},{"value":"5551234567","key":"billing[phone]","type":"text"},{"value":"card","key":"payment[method]","type":"text"},{"value":"4111111111111111","key":"payment[card_number]","type":"text"},{"value":"12","key":"payment[card_exp_month]","type":"text"},{"value":"2025","key":"payment[card_exp_year]","type":"text"},{"value":"123","key":"payment[card_cvv]","type":"text"},{"value":"1","key":"campaign_id","type":"text"},{"value":"USD","key":"currency","type":"text"},{"value":"google","key":"utm_source","type":"text"},{"value":"cpc","key":"utm_medium","type":"text"},{"value":"summer_sale","key":"utm_campaign","type":"text"},{"value":"dtc_products","key":"utm_term","type":"text"},{"value":"banner_1","key":"utm_content","type":"text"},{"value":"AFF001","key":"affiliate","type":"text"},{"value":"SUB001","key":"sub1","type":"text"},{"value":"ACME-2024-Q4","key":"custom_fields[partner_ref]","type":"text"},{"value":"hero-v3","key":"custom_fields[landing_variant]","type":"text"},{"value":"1","key":"products[0][offer_id]","type":"text"},{"value":"1","key":"products[0][quantity]","type":"text"},{"value":"49.98","key":"products[0][price]","type":"text","disabled":true},{"value":"4.70","key":"products[0][shipping_price]","type":"text","disabled":true},{"value":"2","key":"products[1][offer_id]","type":"text","disabled":true},{"value":"2","key":"products[1][quantity]","type":"text","disabled":true},{"value":"29.99","key":"products[1][price]","type":"text","disabled":true},{"value":"0.00","key":"products[1][shipping_price]","type":"text","disabled":true},{"value":"4.37","key":"tax_amount","type":"text","disabled":true},{"value":"0.0875","key":"tax_rate","type":"text","disabled":true},{"value":"192.168.1.2","key":"ip_address","type":"text"},{"value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","key":"user_agent","type":"text"},{"type":"text","value":"true","key":"is_subscription","description":"Set to true when the order is being placed as a 3rd-party-managed subscription so it appears in the customer's subscription records and subscription reports.","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders","description":"# Create Order\n\nCreate a new order within the CRM\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| customer\\[email\\] | **string (required)**<br>The customer's email address |\n| customer\\[first_name\\] | **string (required)**<br>The customer's first name. Maximum length: 255 characters |\n| customer\\[last_name\\] | **string (required)**<br>The customer's last name. Maximum length: 255 characters |\n| customer\\[phone\\] | _string (optional)_<br>The customer's phone number. Maximum length: 20 characters |\n| shipping\\[address1\\] | **string (required)**<br>Primary address line. Maximum length: 255 characters |\n| shipping\\[address2\\] | _string (optional)_<br>Secondary address line (apartment, suite, etc). Maximum length: 255 characters |\n| shipping\\[city\\] | **string (required)**<br>City name. Maximum length: 100 characters |\n| shipping\\[state\\] | **string (required)**<br>State or province. Maximum length: 100 characters |\n| shipping\\[postal_code\\] | **string (required)**<br>ZIP or postal code. Maximum length: 20 characters |\n| shipping\\[country\\] | **string (required)**<br>Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters |\n| shipping\\[phone\\] | _string (optional)_<br>Phone number for shipping-related inquiries. Maximum length: 20 characters |\n| billing\\[address1\\] | _string (optional)_<br>Primary address line. Maximum length: 255 characters |\n| billing\\[address2\\] | _string (optional)_<br>Secondary address line (apartment, suite, etc). Maximum length: 255 characters |\n| billing\\[city\\] | _string (optional)_<br>City name. Maximum length: 100 characters |\n| billing\\[state\\] | _string (optional)_<br>State or province. Maximum length: 100 characters |\n| billing\\[postal_code\\] | _string (optional)_<br>ZIP or postal code. Maximum length: 20 characters |\n| billing\\[country\\] | _string (optional)_<br>Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters |\n| billing\\[phone\\] | _string (optional)_<br>Phone number for billing-related inquiries. Maximum length: 20 characters |\n| payment\\[method\\] | **string (required)**<br>Payment method type. Allowed values: `card` (provide card details), `onfile` (use customer's saved payment method), `external` (external/manual payment such as Zelle, Cash App, Venmo, Bank Transfer), `paypal_wallet` (PayPal Wallet with redirect flow) |\n| payment\\[card_number\\] | **string (required for card payments)**<br>Credit/debit card number |\n| payment\\[card_exp\\] | **string (conditionally required for card payments)**<br>Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if card_exp_month and card_exp_year are not provided |\n| payment\\[card_exp_month\\] | **string (conditionally required for card payments)**<br>Two-digit expiration month (01-12). Must be exactly 2 characters. Required if card_exp is not provided |\n| payment\\[card_exp_year\\] | **string (conditionally required for card payments)**<br>Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if card_exp is not provided |\n| payment\\[card_cvv\\] | **string (required for card payments)**<br>Card verification value. Length: 3-4 characters |\n| payment\\[external_payment_id\\] | _integer (optional)_<br>The ID of a configured alternative payment method. Use `GET /v1/alternative-payments` to retrieve available IDs. When used with `method: \"external\"`, the transaction will be linked to the specific payment type (e.g., Zelle, Cash App). When used with `method: \"paypal_wallet\"`, selects a specific PayPal configuration if multiple exist |\n| payment\\[return_url\\] | **string (required for paypal_wallet)**<br>URL to redirect the customer to after they approve the PayPal payment. Must be a valid URL |\n| payment\\[cancel_url\\] | **string (required for paypal_wallet)**<br>URL to redirect the customer to if they cancel the PayPal payment. Must be a valid URL |\n| coupon_code | _string (optional)_<br>Coupon code to apply to the order. Maximum length: 255 characters |\n| gateway_id | _integer (optional)_<br>The gateway ID to **force** for this charge, bypassing the campaign's normal gateway/orchestrator routing. Must reference an **active** gateway, otherwise the request fails with `gateway_not_found`. Leave empty/null (or omit) to use normal routing. |\n| payment_orchestrator_id | _integer (optional)_<br>The payment orchestrator ID to route this charge through. Must reference an **active** orchestrator. Leave empty/null (or omit) to use the campaign's configured routing. Ignored when `gateway_id` is also provided (a forced gateway takes precedence). |\n| forceQA | _boolean (optional)_<br>Forces the order into QA (quality assurance) review. Accepts: \"true\", \"false\", \"1\", \"0\" |\n| is_subscription | _boolean (optional)_<br>Marks the order as a 3rd-party-managed subscription. When true, an externally-managed subscription record is created on the order so it appears in the customer's subscription records and subscription reports. Spark does not bill or schedule this subscription — lifecycle is handled by the external manager. Accepts: \"true\", \"false\", \"1\", \"0\". Default: false |\n| campaign_id | **integer (required)**<br>Internal ID for the campaign |\n| currency | **string (required)**<br>Three-letter currency code (ISO 4217). Must be exactly 3 characters |\n| cohort | _string (optional)_<br>Cohort identifier. Maximum length: 255 characters |\n| utm_source | _string (optional)_<br>UTM source parameter. Maximum length: 255 characters |\n| utm_medium | _string (optional)_<br>UTM medium parameter. Maximum length: 255 characters |\n| utm_campaign | _string (optional)_<br>UTM campaign parameter. Maximum length: 255 characters |\n| utm_term | _string (optional)_<br>UTM term parameter. Maximum length: 255 characters |\n| utm_content | _string (optional)_<br>UTM content parameter. Maximum length: 255 characters |\n| affiliate | _string (optional)_<br>Affiliate name. Maximum length: 255 characters |\n| sub1 | _string (optional)_<br>Sub-affiliate parameter 1. Maximum length: 255 characters |\n| sub2 | _string (optional)_<br>Sub-affiliate parameter 2. Maximum length: 255 characters |\n| sub3 | _string (optional)_<br>Sub-affiliate parameter 3. Maximum length: 255 characters |\n| sub4 | _string (optional)_<br>Sub-affiliate parameter 4. Maximum length: 255 characters |\n| sub5 | _string (optional)_<br>Sub-affiliate parameter 5. Maximum length: 255 characters |\n| custom_fields | _object (optional)_<br>Arbitrary key/value tracking data. Send as `custom_fields[key]=value`. Max 50 keys; key ≤64 chars, value ≤1000 chars. |\n| products | **array (required)**<br>Array of product objects to be ordered |\n| products\\[\\].offer_id | **integer (required)**<br>Internal ID for the campaign offer |\n| products\\[\\].quantity | **integer (required)**<br>Quantity of this product. Minimum value: 1 |\n| products\\[\\].price | _numeric (optional)_<br>Unit price for this product. Minimum value: 0 |\n| products\\[\\].shipping_price | _numeric (optional)_<br>Shipping price for this product. Minimum value: 0 |\n| tax_amount | _numeric (optional)_<br>Pre-calculated sales tax to charge the customer. Typically obtained from a prior call to `POST /checkout/tax`. Always honored when provided — the customer will be billed this amount regardless of the campaign's tax provider configuration. Minimum value: 0. |\n| tax_rate | _numeric (optional)_<br>Effective tax rate used when `tax_amount` was calculated (e.g. `0.0875` for 8.875%). Stored on the order for reporting; does not affect the charged amount. Minimum value: 0. |\n| ip_address | _string (optional)_<br>Customer's IP address. Must be a valid IP format |\n| user_agent | _string (optional)_<br>Customer's browser user agent string |\n| terms_accepted | _boolean (optional)_<br>Indicates customer acceptance of terms and conditions. Accepts: \"true\", \"false\", \"1\", \"0\" |\n| privacy_accepted | _boolean (optional)_<br>Indicates customer acceptance of privacy policy. Accepts: \"true\", \"false\", \"1\", \"0\" |\n\n## Payment Method Flows\n\n### Card / On File\nStandard payment processing. The order is created and payment is captured immediately.\n\n### External (Zelle, Cash App, Venmo, Bank Transfer)\nFor payments processed outside the platform. Set `payment.method` to `\"external\"` and optionally pass `payment.external_payment_id` to link the transaction to a specific alternative payment method configured in the CRM. The order completes immediately with no gateway interaction.\n\n### PayPal Wallet\nRedirect-based payment flow requiring three steps:\n\n1. **Create Order** — Call this endpoint with `payment.method` set to `\"paypal_wallet\"`, along with `return_url` and `cancel_url`. The response includes a `redirect_url`.\n2. **Customer Approval** — Redirect the customer to the `redirect_url`. They log in to PayPal and approve the payment. PayPal redirects them back to your `return_url`.\n3. **Capture Payment** — Call `POST /checkout/orders/capture` with the `order_number` to finalize the charge. Money does not move until this step.\n\n## Tax Handling\n\nTwo ways to populate the order's tax:\n\n- **Pass it in** — supply `tax_amount` (and optionally `tax_rate`) in the request body. Typical flow: call `POST /checkout/tax` first to get the calculated values, then pass them here to lock in what the customer saw on the checkout page. The customer is always charged the `tax_amount` you supply.\n- **Let the server compute it** — omit both fields. When the campaign has an active TaxJar provider, the server auto-calculates tax against the shipping address at order-save time.\n\n**Charge vs. report are separate decisions:**\n- `tax_amount` controls what the customer pays.\n- Whether the order is forwarded to TaxJar depends on the campaign's `tax_enabled` flag + active provider. If the campaign has tax disabled, the customer is still charged the supplied `tax_amount`, but nothing is reported to TaxJar's books.\n\n## 3rd-Party-Managed Subscriptions\n\nSet `is_subscription=true` when this order is being placed for a customer whose subscription lifecycle is handled by an external subscription manager. Spark records a synthetic externally-managed subscription on the order so it surfaces in the customer's subscription records and subscription reports — but does **not** schedule billing, fire process-reminder webhooks, or attempt renewals on it. The external system is responsible for billing the customer.\n\nThis flag is independent of any subscription-typed offer/upsell on the order. If the order's offer/upsell is configured with sale type `3rd Party Subscription Manager`, that path produces its own externally-managed subscription with the configured `external_provider`, `process_reminder_hours_before`, and `billing_interval_days` — `is_subscription` is only needed for one-off external-subscription orders that don't use a configured offer.\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| success | **boolean**<br>Indicates if the API request was successful |\n| message | **string**<br>Human-readable description of the result |\n| data | **object**<br>Contains the detailed response data |\n| data.order_number | **string**<br>Unique identifier for the newly created order |\n| data.customer_number | **string**<br>Unique identifier for the customer |\n| data.transaction_number | **string**<br>Unique identifier for the payment transaction |\n| data.total | **number**<br>Total amount of the order (subtotal + shipping + tax) |\n| data.tax_amount | **string**<br>Sales tax portion of the order total, formatted to 2 decimals. `0.00` when no tax was applied. |\n| data.tax_rate | **number**<br>Effective tax rate recorded on the order (e.g. `0.0875` for 8.875%). `0` when no rate was set. |\n| data.gateway_descriptor | **string**<br>Statement descriptor from the payment gateway used for the transaction. Only included if the gateway has a descriptor configured |\n| data.gateway_id | **integer \\| null**<br>The gateway ID that processed (or attempted) the charge. Returned on both approved and declined payments; `null` for external/PayPal payments or when no gateway was attempted. Pass this back as the request `gateway_id` to force the same gateway on a retry. |\n| data.currency | **string**<br>Three-letter currency code (ISO 4217) used for the order |\n| data.subscription_created | **boolean**<br>Indicates if a subscription was created with this order |\n| data.order_reused | **boolean**<br>Indicates if an existing order was reused instead of creating a new one |\n| data.redirect_url | **string (paypal_wallet only)**<br>PayPal checkout URL to redirect the customer to for payment approval. Only returned when `payment.method` is `\"paypal_wallet\"` |\n| data.payment_status | **string**<br>Status of the payment transaction. Values: `completed`, `declined`, `pending_redirect` |\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": false,\n    \"message\": \"Order limit reached\",\n    \"errors\": {\n        \"max_orders_per_email_reached\": \"Customer has reached the maximum of 1 order(s) on this campaign.\"\n    }\n}"}],"_postman_id":"1899e07a-8eae-420d-a0b5-e672a69746ed"},{"name":"Process Upsell","id":"c63a7325-1b93-4cb6-91e8-c4613444f65f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"value":"ORD-250321-00001","key":"order_number","type":"text"},{"value":"1","key":"upsell_id","type":"text"},{"value":"1","key":"quantity","type":"text"},{"value":"29.99","key":"price","type":"text"},{"value":"4.99","key":"shipping_price","type":"text"},{"value":"2.62","key":"tax_amount","type":"text","disabled":true},{"value":"0.0875","key":"tax_rate","type":"text","disabled":true},{"value":"USD","key":"currency","type":"text"},{"value":"card","key":"payment[method]","type":"text","description":"<p>card or onfile. Omit the whole payment object to charge the card on file.</p>\n","disabled":true},{"value":"4111111111111111","key":"payment[card_number]","type":"text","disabled":true},{"value":"12","key":"payment[card_exp_month]","type":"text","disabled":true},{"value":"2027","key":"payment[card_exp_year]","type":"text","disabled":true},{"value":"123","key":"payment[card_cvv]","type":"text","description":"<p>Required for method=card. With method=onfile, supply only this to charge the card on file with a CVV.</p>\n","disabled":true},{"value":"123 Main St","key":"payment[billing_address][address1]","type":"text","disabled":true},{"value":"Apt 4B","key":"payment[billing_address][address2]","type":"text","disabled":true},{"value":"New York","key":"payment[billing_address][city]","type":"text","disabled":true},{"value":"NY","key":"payment[billing_address][state]","type":"text","disabled":true},{"value":"10001","key":"payment[billing_address][postal_code]","type":"text","disabled":true},{"value":"US","key":"payment[billing_address][country]","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/upsell","description":"<h1 id=\"process-upsell\">Process Upsell</h1>\n<p>Process a transaction as an upsell for an existing order from within the CRM</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong>  <br />The original order number to attach the upsell to</td>\n</tr>\n<tr>\n<td>upsell_id</td>\n<td><strong>string (required)</strong>  <br />Internal ID for the campaign upsell</td>\n</tr>\n<tr>\n<td>quantity</td>\n<td><strong>integer (required)</strong>  <br />Quantity of the upsell product. Minimum value: 1</td>\n</tr>\n<tr>\n<td>price</td>\n<td><em>numeric (optional)</em>  <br />Price for the upsell product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>shipping_price</td>\n<td><em>numeric (optional)</em>  <br />Shipping price for the upsell product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>tax_amount</td>\n<td><em>numeric (optional)</em>  <br />Pre-calculated sales tax for this upsell. Typically obtained from a prior call to <code>POST /checkout/tax</code> scoped to the upsell cart. Always honored when provided — the customer will be billed this amount regardless of the campaign's tax provider configuration. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>tax_rate</td>\n<td><em>numeric (optional)</em>  <br />Effective tax rate used when <code>tax_amount</code> was calculated (e.g. <code>0.0875</code> for 8.875%). Stored on the order for reporting; does not affect the charged amount. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>currency</td>\n<td><em>string (optional)</em>  <br />Three-letter currency code (ISO 4217). Must be exactly 3 characters</td>\n</tr>\n<tr>\n<td>payment</td>\n<td><em>object (optional)</em>  <br />Optional payment override. When omitted, the upsell is charged to the <strong>card on file</strong> from the original order. Applies to both the single and multiple-upsell formats.</td>\n</tr>\n<tr>\n<td>payment[method]</td>\n<td><strong>string (required if payment provided)</strong>  <br />Allowed values: <code>card</code> (charge a supplied card) or <code>onfile</code> (charge the original order's saved card).</td>\n</tr>\n<tr>\n<td>payment[card_number]</td>\n<td><strong>string (required when method=card)</strong>  <br />Credit/debit card number.</td>\n</tr>\n<tr>\n<td>payment[card_exp]</td>\n<td><strong>string (conditionally required when method=card)</strong>  <br />Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if card_exp_month and card_exp_year are not provided.</td>\n</tr>\n<tr>\n<td>payment[card_exp_month]</td>\n<td><strong>string (conditionally required when method=card)</strong>  <br />Two-digit expiration month (01-12). Required if card_exp is not provided.</td>\n</tr>\n<tr>\n<td>payment[card_exp_year]</td>\n<td><strong>string (conditionally required when method=card)</strong>  <br />Expiration year (2 or 4 digits). Required if card_exp is not provided.</td>\n</tr>\n<tr>\n<td>payment[card_cvv]</td>\n<td><strong>string (required when method=card; optional when method=onfile)</strong>  <br />Card verification value. Length: 3-4 characters. When only <code>card_cvv</code> is supplied with <code>method: onfile</code>, the card on file is charged and the CVV is passed to the gateway (the CVV is persisted only if the team has data capture enabled).</td>\n</tr>\n<tr>\n<td>payment[billing_address]</td>\n<td><em>object (optional)</em>  <br />Billing address for a supplied card.</td>\n</tr>\n<tr>\n<td>payment[billing_address][address1]</td>\n<td><strong>string (required if billing_address provided)</strong>  <br />Primary address line. Maximum length: 255 characters.</td>\n</tr>\n<tr>\n<td>payment[billing_address][address2]</td>\n<td><em>string (optional)</em>  <br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters.</td>\n</tr>\n<tr>\n<td>payment[billing_address][city]</td>\n<td><strong>string (required if billing_address provided)</strong>  <br />City name. Maximum length: 100 characters.</td>\n</tr>\n<tr>\n<td>payment[billing_address][state]</td>\n<td><strong>string (required if billing_address provided)</strong>  <br />State or province. Maximum length: 100 characters.</td>\n</tr>\n<tr>\n<td>payment[billing_address][postal_code]</td>\n<td><strong>string (required if billing_address provided)</strong>  <br />ZIP or postal code. Maximum length: 20 characters.</td>\n</tr>\n<tr>\n<td>payment[billing_address][country]</td>\n<td><strong>string (required if billing_address provided)</strong>  <br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"multiple-upsells-format\">Multiple Upsells Format</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong>  <br />The original order number to attach the upsells to</td>\n</tr>\n<tr>\n<td>upsells</td>\n<td><strong>array (required)</strong>  <br />Array of upsell objects to process in a single transaction</td>\n</tr>\n<tr>\n<td>upsells[].upsell_id</td>\n<td><strong>string (required)</strong>  <br />Internal ID for the campaign upsell</td>\n</tr>\n<tr>\n<td>upsells[].quantity</td>\n<td><strong>integer (required)</strong>  <br />Quantity of the upsell product. Minimum value: 1</td>\n</tr>\n<tr>\n<td>upsells[].price</td>\n<td><em>numeric (optional)</em>  <br />Price for the upsell product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>upsells[].shipping_price</td>\n<td><em>numeric (optional)</em>  <br />Shipping price for the upsell product. Minimum value: 0</td>\n</tr>\n<tr>\n<td>tax_amount</td>\n<td><em>numeric (optional)</em>  <br />Single pre-calculated sales tax total covering the whole upsell cart. Supply at the top level — not per-upsell. Matches how <code>POST /checkout/tax</code> returns a single total.</td>\n</tr>\n<tr>\n<td>tax_rate</td>\n<td><em>numeric (optional)</em>  <br />Effective tax rate applied to the upsell cart.</td>\n</tr>\n<tr>\n<td>currency</td>\n<td><em>string (optional)</em>  <br />Three-letter currency code (ISO 4217). Must be exactly 3 characters</td>\n</tr>\n<tr>\n<td>payment</td>\n<td><em>object (optional)</em>  <br />Same optional payment override described in <strong>Request Object</strong> above. Supplied at the top level and applied to the whole upsell cart.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"payment-method\">Payment Method</h2>\n<p>By default (no <code>payment</code> object) the upsell is charged to the <strong>card on file</strong> from the original order — no card data required.</p>\n<ul>\n<li><strong>Card on file + CVV</strong> — send <code>payment[method]=onfile</code> together with <code>payment[card_cvv]</code>. The saved card is charged and the supplied CVV is forwarded to the gateway. Useful for gateways that require a CVV on every charge.</li>\n<li><strong>New / replacement card</strong> — send <code>payment[method]=card</code> with the full card fields. A card on file matching the supplied number is reused (CVV/expiry refreshed); a different number is added as a new card. The supplied card is promoted to the customer's primary card <strong>only after the charge is approved</strong>, so a declined upsell never reroutes future subscription rebills onto an unvalidated card.</li>\n</ul>\n<p><strong>Guardrails (return <code>422</code>):</strong></p>\n<ul>\n<li>A new card cannot be pushed onto an order originally paid via PayPal or an external method — use the original payment flow instead.</li>\n<li>A test card number cannot be used on an order that was originally paid with a live card.</li>\n<li>A supplied card whose brand the resolved gateway cannot process is rejected before the charge.</li>\n</ul>\n<h2 id=\"tax-handling\">Tax Handling</h2>\n<p>Two ways to populate the upsell's tax:</p>\n<ul>\n<li><strong>Pass it in</strong> — supply <code>tax_amount</code> (and optionally <code>tax_rate</code>) in the request body. Typical flow: call <code>POST /checkout/tax</code> with the upsell's line items to get the calculated tax, then pass the returned value here. The customer is charged the <code>tax_amount</code> you supply.</li>\n<li><strong>Let the server compute it</strong> — omit both fields. The upsell's tax falls back to the <code>CampaignUpsell.tax_rate</code> configured on the offer.</li>\n</ul>\n<p><strong>Each upsell posts to TaxJar as its own record.</strong> When the upsell transaction completes, it's posted to TaxJar's <code>/v2/transactions/orders</code> endpoint keyed by the transaction's ID. Refunds of this upsell will reference that specific transaction — so tax reporting stays accurate even when items in the same order have different tax treatments (e.g., taxable base + tax-exempt clothing upsell).</p>\n<p><strong>Charge vs. report are separate decisions:</strong></p>\n<ul>\n<li><code>tax_amount</code> controls what the customer pays.</li>\n<li>Whether the upsell is forwarded to TaxJar depends on the campaign's <code>tax_enabled</code> flag + active provider. If the campaign has tax disabled, the customer is still charged the supplied <code>tax_amount</code>, but nothing is reported to TaxJar's books.</li>\n</ul>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the original order</td>\n</tr>\n<tr>\n<td>data.transaction_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the upsell transaction</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Status of the upsell transaction (\"completed\")</td>\n</tr>\n<tr>\n<td>data.subscription_created</td>\n<td><strong>boolean</strong>  <br />Indicates if a subscription was created with this upsell</td>\n</tr>\n<tr>\n<td>data.gateway_descriptor</td>\n<td><strong>string</strong>  <br />Statement descriptor from the payment gateway used for the transaction. Only included if the gateway has a descriptor configured</td>\n</tr>\n<tr>\n<td>data.upsell_depth</td>\n<td><strong>integer</strong>  <br />Depth level of the upsell in the sales funnel</td>\n</tr>\n<tr>\n<td>data.upsell_count</td>\n<td><strong>integer</strong>  <br />Count of upsells processed for the transaction</td>\n</tr>\n<tr>\n<td>data.total</td>\n<td><strong>number</strong>  <br />Total amount of the upsell (subtotal + shipping + tax)</td>\n</tr>\n<tr>\n<td>data.tax_amount</td>\n<td><strong>string</strong>  <br />Sales tax portion of the upsell total, formatted to 2 decimals. <code>0.00</code> when no tax was applied.</td>\n</tr>\n<tr>\n<td>data.tax_rate</td>\n<td><strong>number</strong>  <br />Effective tax rate recorded on the order (e.g. <code>0.0875</code> for 8.875%). <code>0</code> when no rate was set.</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code (ISO 4217) used for the transaction</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders","upsell"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"14ef65c2-5aec-47aa-94fa-5ed3a1812a50","name":"Process Upsell Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250321-00001","type":"text"},{"key":"upsell_id","value":"1","type":"text"},{"key":"quantity","value":"1","type":"text"},{"key":"price","value":"29.99","type":"text"},{"key":"shipping_price","value":"4.99","type":"text"},{"key":"currency","value":"USD","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/upsell"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:16:22 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Server","value":"cloudflare"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-Xss-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"Cf-Cache-Status","value":"DYNAMIC"},{"key":"Content-Encoding","value":"br"},{"key":"CF-RAY","value":"9239f25b8a5d13f7-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Upsell processed successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-250321-00001\",\n        \"transaction_number\": \"TXN-250321-000002\",\n        \"status\": \"completed\",\n        \"gateway_descriptor\": \"test descriptor\",\n        \"subscription_created\": false,\n        \"subscription_number\": \"SUB-250321-000002\",\n        \"upsell_depth\": 1,\n        \"upsell_count\": 2,\n        \"total\": 34.98,\n        \"currency\": \"USD\"\n    }\n}"},{"id":"8e2d3771-77e6-9791-6abe-2145d3ae344f","name":"402 — Upsell Decline Cap Reached","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"value":"ORD-250321-00001","key":"order_number","type":"text"},{"value":"1","key":"upsell_id","type":"text"},{"value":"1","key":"quantity","type":"text"},{"value":"29.99","key":"price","type":"text"},{"value":"4.99","key":"shipping_price","type":"text"},{"value":"2.62","key":"tax_amount","type":"text","disabled":true},{"value":"0.0875","key":"tax_rate","type":"text","disabled":true},{"value":"USD","key":"currency","type":"text"},{"value":"card","key":"payment[method]","type":"text","description":"card or onfile. Omit the whole payment object to charge the card on file.","disabled":true},{"value":"4111111111111111","key":"payment[card_number]","type":"text","disabled":true},{"value":"12","key":"payment[card_exp_month]","type":"text","disabled":true},{"value":"2027","key":"payment[card_exp_year]","type":"text","disabled":true},{"value":"123","key":"payment[card_cvv]","type":"text","description":"Required for method=card. With method=onfile, supply only this to charge the card on file with a CVV.","disabled":true},{"value":"123 Main St","key":"payment[billing_address][address1]","type":"text","disabled":true},{"value":"Apt 4B","key":"payment[billing_address][address2]","type":"text","disabled":true},{"value":"New York","key":"payment[billing_address][city]","type":"text","disabled":true},{"value":"NY","key":"payment[billing_address][state]","type":"text","disabled":true},{"value":"10001","key":"payment[billing_address][postal_code]","type":"text","disabled":true},{"value":"US","key":"payment[billing_address][country]","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/upsell","description":"# Process Upsell\n\nProcess a transaction as an upsell for an existing order from within the CRM\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| order_number | **string (required)**  <br>The original order number to attach the upsell to |\n| upsell_id | **string (required)**  <br>Internal ID for the campaign upsell |\n| quantity | **integer (required)**  <br>Quantity of the upsell product. Minimum value: 1 |\n| price | _numeric (optional)_  <br>Price for the upsell product. Minimum value: 0 |\n| shipping_price | _numeric (optional)_  <br>Shipping price for the upsell product. Minimum value: 0 |\n| tax_amount | _numeric (optional)_  <br>Pre-calculated sales tax for this upsell. Typically obtained from a prior call to `POST /checkout/tax` scoped to the upsell cart. Always honored when provided — the customer will be billed this amount regardless of the campaign's tax provider configuration. Minimum value: 0. |\n| tax_rate | _numeric (optional)_  <br>Effective tax rate used when `tax_amount` was calculated (e.g. `0.0875` for 8.875%). Stored on the order for reporting; does not affect the charged amount. Minimum value: 0. |\n| currency | _string (optional)_  <br>Three-letter currency code (ISO 4217). Must be exactly 3 characters |\n| payment | _object (optional)_  <br>Optional payment override. When omitted, the upsell is charged to the **card on file** from the original order. Applies to both the single and multiple-upsell formats. |\n| payment\\[method\\] | **string (required if payment provided)**  <br>Allowed values: `card` (charge a supplied card) or `onfile` (charge the original order's saved card). |\n| payment\\[card_number\\] | **string (required when method=card)**  <br>Credit/debit card number. |\n| payment\\[card_exp\\] | **string (conditionally required when method=card)**  <br>Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if card_exp_month and card_exp_year are not provided. |\n| payment\\[card_exp_month\\] | **string (conditionally required when method=card)**  <br>Two-digit expiration month (01-12). Required if card_exp is not provided. |\n| payment\\[card_exp_year\\] | **string (conditionally required when method=card)**  <br>Expiration year (2 or 4 digits). Required if card_exp is not provided. |\n| payment\\[card_cvv\\] | **string (required when method=card; optional when method=onfile)**  <br>Card verification value. Length: 3-4 characters. When only `card_cvv` is supplied with `method: onfile`, the card on file is charged and the CVV is passed to the gateway (the CVV is persisted only if the team has data capture enabled). |\n| payment\\[billing_address\\] | _object (optional)_  <br>Billing address for a supplied card. |\n| payment\\[billing_address\\]\\[address1\\] | **string (required if billing_address provided)**  <br>Primary address line. Maximum length: 255 characters. |\n| payment\\[billing_address\\]\\[address2\\] | _string (optional)_  <br>Secondary address line (apartment, suite, etc). Maximum length: 255 characters. |\n| payment\\[billing_address\\]\\[city\\] | **string (required if billing_address provided)**  <br>City name. Maximum length: 100 characters. |\n| payment\\[billing_address\\]\\[state\\] | **string (required if billing_address provided)**  <br>State or province. Maximum length: 100 characters. |\n| payment\\[billing_address\\]\\[postal_code\\] | **string (required if billing_address provided)**  <br>ZIP or postal code. Maximum length: 20 characters. |\n| payment\\[billing_address\\]\\[country\\] | **string (required if billing_address provided)**  <br>Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters. |\n\n## Multiple Upsells Format\n\n| Request Field | Description |\n| --- | --- |\n| order_number | **string (required)**  <br>The original order number to attach the upsells to |\n| upsells | **array (required)**  <br>Array of upsell objects to process in a single transaction |\n| upsells\\[\\].upsell_id | **string (required)**  <br>Internal ID for the campaign upsell |\n| upsells\\[\\].quantity | **integer (required)**  <br>Quantity of the upsell product. Minimum value: 1 |\n| upsells\\[\\].price | _numeric (optional)_  <br>Price for the upsell product. Minimum value: 0 |\n| upsells\\[\\].shipping_price | _numeric (optional)_  <br>Shipping price for the upsell product. Minimum value: 0 |\n| tax_amount | _numeric (optional)_  <br>Single pre-calculated sales tax total covering the whole upsell cart. Supply at the top level — not per-upsell. Matches how `POST /checkout/tax` returns a single total. |\n| tax_rate | _numeric (optional)_  <br>Effective tax rate applied to the upsell cart. |\n| currency | _string (optional)_  <br>Three-letter currency code (ISO 4217). Must be exactly 3 characters |\n| payment | _object (optional)_  <br>Same optional payment override described in **Request Object** above. Supplied at the top level and applied to the whole upsell cart. |\n\n## Payment Method\n\nBy default (no `payment` object) the upsell is charged to the **card on file** from the original order — no card data required.\n\n- **Card on file + CVV** — send `payment[method]=onfile` together with `payment[card_cvv]`. The saved card is charged and the supplied CVV is forwarded to the gateway. Useful for gateways that require a CVV on every charge.\n- **New / replacement card** — send `payment[method]=card` with the full card fields. A card on file matching the supplied number is reused (CVV/expiry refreshed); a different number is added as a new card. The supplied card is promoted to the customer's primary card **only after the charge is approved**, so a declined upsell never reroutes future subscription rebills onto an unvalidated card.\n\n**Guardrails (return `422`):**\n\n- A new card cannot be pushed onto an order originally paid via PayPal or an external method — use the original payment flow instead.\n- A test card number cannot be used on an order that was originally paid with a live card.\n- A supplied card whose brand the resolved gateway cannot process is rejected before the charge.\n\n## Tax Handling\n\nTwo ways to populate the upsell's tax:\n\n- **Pass it in** — supply `tax_amount` (and optionally `tax_rate`) in the request body. Typical flow: call `POST /checkout/tax` with the upsell's line items to get the calculated tax, then pass the returned value here. The customer is charged the `tax_amount` you supply.\n- **Let the server compute it** — omit both fields. The upsell's tax falls back to the `CampaignUpsell.tax_rate` configured on the offer.\n\n**Each upsell posts to TaxJar as its own record.** When the upsell transaction completes, it's posted to TaxJar's `/v2/transactions/orders` endpoint keyed by the transaction's ID. Refunds of this upsell will reference that specific transaction — so tax reporting stays accurate even when items in the same order have different tax treatments (e.g., taxable base + tax-exempt clothing upsell).\n\n**Charge vs. report are separate decisions:**\n- `tax_amount` controls what the customer pays.\n- Whether the upsell is forwarded to TaxJar depends on the campaign's `tax_enabled` flag + active provider. If the campaign has tax disabled, the customer is still charged the supplied `tax_amount`, but nothing is reported to TaxJar's books.\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| success | **boolean**  <br>Indicates if the API request was successful |\n| message | **string**  <br>Human-readable description of the result |\n| data | **object**  <br>Contains the detailed response data |\n| data.order_number | **string**  <br>Unique identifier for the original order |\n| data.transaction_number | **string**  <br>Unique identifier for the upsell transaction |\n| data.status | **string**  <br>Status of the upsell transaction (\"completed\") |\n| data.subscription_created | **boolean**  <br>Indicates if a subscription was created with this upsell |\n| data.gateway_descriptor | **string**  <br>Statement descriptor from the payment gateway used for the transaction. Only included if the gateway has a descriptor configured |\n| data.upsell_depth | **integer**  <br>Depth level of the upsell in the sales funnel |\n| data.upsell_count | **integer**  <br>Count of upsells processed for the transaction |\n| data.total | **number**  <br>Total amount of the upsell (subtotal + shipping + tax) |\n| data.tax_amount | **string**  <br>Sales tax portion of the upsell total, formatted to 2 decimals. `0.00` when no tax was applied. |\n| data.tax_rate | **number**  <br>Effective tax rate recorded on the order (e.g. `0.0875` for 8.875%). `0` when no rate was set. |\n| data.currency | **string**  <br>Three-letter currency code (ISO 4217) used for the transaction |\n"},"status":"Payment Required","code":402,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": false,\n    \"message\": \"Maximum upsell decline attempts reached for this order\",\n    \"data\": {\n        \"order_number\": \"ORD-12345\",\n        \"transaction_number\": \"TRX-67890\",\n        \"gateway_descriptor\": \"\",\n        \"status\": \"declined\",\n        \"upsell_depth\": 3,\n        \"total\": 49.99,\n        \"tax_amount\": \"0.00\",\n        \"tax_rate\": 0,\n        \"currency\": \"USD\",\n        \"subscription_created\": false,\n        \"subscription_number\": null\n    }\n}"}],"_postman_id":"c63a7325-1b93-4cb6-91e8-c4613444f65f"},{"name":"Complete Order","id":"598cbd5d-2463-4058-a26d-0a8ceb90c2cd","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250324-00001","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/complete","description":"<h1 id=\"complete-order\">Complete Order</h1>\n<p>Mark an order as completed within the CRM.</p>\n<p>Note: By default, this endpoint will be called 20 minutes after the customers last transaction which will close the order and send any applicable transactional emails</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong>  <br />The order number to mark as complete</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the order that was completed</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Updated status of the order (\"completed\")</td>\n</tr>\n<tr>\n<td>data.completed_at</td>\n<td><strong>string</strong>  <br />Date and time when the order was marked as completed (format: YYYY-MM-DD HH:MM:SS)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders","complete"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"e168e077-928f-4233-81db-da0496dcb65d","name":"Create Order Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250324-00001","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/complete"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Mon, 24 Mar 2025 13:47:44 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=hc%2BayptvH1XcWXqPdD4Ug0SsKnI%2FY9LLGvGr5WeCoVpS7zK%2BkgRWtRdt%2F7tGlxHYBN2id1plTJEI0y6fjIo5ddolT36BUCbuddne6%2FIMHyb3hG7udNXOLUAYLDkt637jciI%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"92569f42fd8d10c6-ORD"},{"key":"Content-Encoding","value":"br"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=17314&min_rtt=16117&rtt_var=6376&sent=33&recv=33&lost=0&retrans=0&sent_bytes=4466&recv_bytes=2311&delivery_rate=243766&cwnd=224&unsent_bytes=0&cid=289111252ed120f1&ts=28644&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Order marked as completed successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-250324-00001\",\n        \"status\": \"completed\",\n        \"completed_at\": \"2025-03-24 13:47:44\"\n    }\n}"}],"_postman_id":"598cbd5d-2463-4058-a26d-0a8ceb90c2cd"},{"name":"Reprocess Payment","id":"1d28aaca-ec25-4852-98b2-0e3962d04da0","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","type":"text","value":"ORD-260317-00004"},{"key":"amount","type":"text","value":"279.99"},{"type":"text","key":"gateway_id","value":"1"},{"type":"text","key":"affiliate","value":"none"},{"type":"text","key":"sub1","value":"sub-affiliate-1","disabled":true},{"type":"text","key":"sub2","value":"sub-affiliate-2","disabled":true},{"type":"text","key":"sub3","value":"sub-affiliate-3","disabled":true},{"type":"text","key":"sub4","value":"sub-affiliate-4","disabled":true},{"type":"text","key":"sub5","value":"sub-affiliate-5","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/reprocess_payment","description":"<h2 id=\"reprocess-payment\">Reprocess Payment</h2>\n<p>Retry a payment attempt on a previously declined order. This endpoint allows merchants to reprocess payment using the existing order configuration, or override specific parameters such as amount, gateway, payment method, billing address, affiliate, or sub affiliate IDs.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required Permission:</strong> <code>api:orders.payment.reprocess</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong><br />The order number to retry payment for</td>\n</tr>\n<tr>\n<td>amount</td>\n<td><em>numeric (optional)</em><br />Overrides the amount charged during the retry. Minimum value: 0.01. If not provided, the system uses the amount from the most recent payment attempt on the order</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em>integer (optional)</em><br />Forces the payment attempt through a specific gateway. If both <code>gateway_id</code> and <code>payment_orchestrator_id</code> are provided, <code>gateway_id</code> takes precedence and <code>payment_orchestrator_id</code> is ignored</td>\n</tr>\n<tr>\n<td>payment_orchestrator_id</td>\n<td><em>integer (optional)</em><br />Forces the retry through a specific payment orchestrator. Ignored if <code>gateway_id</code> is also provided</td>\n</tr>\n<tr>\n<td>affiliate</td>\n<td><em>string (optional)</em><br />Affiliate identifier to associate with the order. Pass <code>\"none\"</code> to remove the existing affiliate from the order. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>sub1</td>\n<td><em>string (optional, max 255)</em><br />Overrides <code>sub_affiliate_id</code> on the order. Pass an empty string to clear the existing value. Alias: <code>sub_affiliate_id</code></td>\n</tr>\n<tr>\n<td>sub2</td>\n<td><em>string (optional, max 255)</em><br />Overrides <code>sub_affiliate_id_2</code> on the order. Pass an empty string to clear the existing value. Alias: <code>sub_affiliate_id_2</code></td>\n</tr>\n<tr>\n<td>sub3</td>\n<td><em>string (optional, max 255)</em><br />Overrides <code>sub_affiliate_id_3</code> on the order. Pass an empty string to clear the existing value. Alias: <code>sub_affiliate_id_3</code></td>\n</tr>\n<tr>\n<td>sub4</td>\n<td><em>string (optional, max 255)</em><br />Overrides <code>sub_affiliate_id_4</code> on the order. Pass an empty string to clear the existing value. Alias: <code>sub_affiliate_id_4</code></td>\n</tr>\n<tr>\n<td>sub5</td>\n<td><em>string (optional, max 255)</em><br />Overrides <code>sub_affiliate_id_5</code> on the order. Pass an empty string to clear the existing value. Alias: <code>sub_affiliate_id_5</code></td>\n</tr>\n<tr>\n<td>payment[method]</td>\n<td><em>string (optional)</em><br />Payment method type. Allowed values: <code>card</code> (provide new card details), <code>onfile</code> (use customer's saved payment method). If not provided, the system reuses the order's existing payment method</td>\n</tr>\n<tr>\n<td>payment[card_number]</td>\n<td><strong>string (required if method is card)</strong><br />Credit/debit card number</td>\n</tr>\n<tr>\n<td>payment[card_exp]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if <code>card_exp_month</code> and <code>card_exp_year</code> are not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_month]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Two-digit expiration month (01-12). Must be exactly 2 characters. Required if <code>card_exp</code> is not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_year]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if <code>card_exp</code> is not provided</td>\n</tr>\n<tr>\n<td>payment[card_cvv]</td>\n<td><strong>string (required for card payments)</strong><br />Card verification value. Length: 3-4 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address]</td>\n<td><em>object (optional)</em><br />Billing address override for the retry attempt</td>\n</tr>\n<tr>\n<td>payment[billing_address][address1]</td>\n<td><em>string (optional)</em><br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][address2]</td>\n<td><em>string (optional)</em><br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][city]</td>\n<td><em>string (optional)</em><br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][state]</td>\n<td><em>string (optional)</em><br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][postal_code]</td>\n<td><em>string (optional)</em><br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][country]</td>\n<td><em>string (optional)</em><br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"behavior\">Behavior</h2>\n<ul>\n<li><strong>Completed orders</strong> — If the order has already been completed, the endpoint returns an error indicating a new order must be created for additional charges.</li>\n<li><strong>Retryable statuses</strong> — Only orders with a status of <code>declined</code>, <code>failed</code>, <code>error</code>, <code>pending</code>, <code>expired</code>, or <code>abandoned</code> can be retried. All other statuses return an error.</li>\n<li><strong>Gateway precedence</strong> — If both <code>gateway_id</code> and <code>payment_orchestrator_id</code> are provided, <code>gateway_id</code> takes precedence. A system note is logged on the order indicating the orchestrator was ignored.</li>\n<li><strong>Amount fallback</strong> — If <code>amount</code> is not provided, the system uses the amount from the most recent payment attempt. If no prior transaction exists, the cart total is used.</li>\n<li><strong>Payment method fallback</strong> — If <code>payment.method</code> is not provided, the system reuses the payment method from the most recent transaction on the order.</li>\n<li><strong>Affiliate handling</strong> — Pass <code>\"none\"</code> to remove the affiliate. Pass a valid affiliate identifier to change it. Invalid values are ignored and a system note is logged.</li>\n<li><strong>Sub affiliate ID handling</strong> — Each sub field (<code>sub1</code>–<code>sub5</code>) is optional and only updates the order when supplied. Pass an empty string to clear that sub affiliate ID. Omitted fields leave the existing value unchanged. The longer-form aliases <code>sub_affiliate_id</code>, <code>sub_affiliate_id_2</code>, <code>sub_affiliate_id_3</code>, <code>sub_affiliate_id_4</code>, and <code>sub_affiliate_id_5</code> are also accepted. When any sub IDs change, a system note is logged on the order listing the columns that were updated.</li>\n</ul>\n<h2 id=\"subscription-rebills\">Subscription Rebills</h2>\n<p>The endpoint accepts both initial orders and <strong>subscription rebill orders</strong> (each rebill is a separate order linked to its subscription). When the order being reprocessed is a rebill and the retry succeeds, the parent subscription is updated to match a first-try successful rebill:</p>\n<ul>\n<li>Status transitions from <code>past_due</code>, <code>salvaging</code>, or <code>declined_out</code> back to <code>active</code> (or <code>completed</code> if the subscription has reached <code>total_cycles</code>). Subscriptions already in <code>active</code> stay <code>active</code>.</li>\n<li><code>billing_cycle</code> and <code>successful_cycles</code> are incremented.</li>\n<li><code>last_billed_at</code> is set to now and <code>next_billing_at</code> is advanced by <code>billing_interval</code> days.</li>\n<li><code>total_billed</code> and <code>total_paid</code> are increased by <code>subscription.total</code>.</li>\n<li><code>retry_count</code> is reset to 0.</li>\n<li>The rebill order itself is marked <code>completed</code> (instead of stopping at <code>processing</code>).</li>\n<li>A <code>SubscriptionUpdatedEvent</code> is fired and a system note is added to the order.</li>\n</ul>\n<p>On a failed retry, the subscription is <strong>not</strong> touched by this endpoint — the existing subscription salvage / retry pipeline owns that state.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong><br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong><br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong><br />Unique identifier for the order that was reprocessed</td>\n</tr>\n<tr>\n<td>data.transaction_number</td>\n<td><strong>string</strong><br />Unique identifier for the new payment transaction</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong><br />Current status of the order after reprocessing</td>\n</tr>\n<tr>\n<td>data.gateway_descriptor</td>\n<td><strong>string</strong><br />Statement descriptor from the payment gateway. Only included if the gateway has a descriptor configured</td>\n</tr>\n<tr>\n<td>data.total</td>\n<td><strong>number</strong><br />Total amount charged for this retry attempt</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong><br />Three-letter currency code (ISO 4217) used for the transaction</td>\n</tr>\n<tr>\n<td>data.payment_status</td>\n<td><strong>string</strong><br />Status of the payment transaction. Values: <code>completed</code>, <code>declined</code></td>\n</tr>\n<tr>\n<td>data.retry_attempt</td>\n<td><strong>integer</strong><br />The retry attempt number for this order</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Scenario</th>\n<th>Status Code</th>\n<th>Message</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Order already completed</td>\n<td>422</td>\n<td>Configuration Error</td>\n</tr>\n<tr>\n<td>Order status not retryable</td>\n<td>422</td>\n<td>This order cannot be retried</td>\n</tr>\n<tr>\n<td>Validation failure</td>\n<td>422</td>\n<td>Validation errors returned per field</td>\n</tr>\n<tr>\n<td>Payment processing failure</td>\n<td>500</td>\n<td>Failed to reprocess payment</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders","reprocess_payment"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"2faf377c-13be-42cf-ac44-106a284a3546","name":"Reprocess Payment Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-260317-00004","type":"text"},{"key":"amount","value":"279.99","type":"text"},{"key":"gateway_id","value":"1","type":"text"},{"key":"affiliate","value":"none","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/reprocess_payment"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:13:55 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=wO7xtC5U8FgDQWDTrTPEKHwSKTpLPTzYxZc77sfAX678LxELygJpa7tG9DB7XQAnHUMw4DGaXSFdbkXp7IWnpq1r86RKDUyt%2FLz7Usxut%2BmJmJ4R35P%2B2esK5XTKxDYjIRc%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"9239eec33ecbd240-ORD"},{"key":"Content-Encoding","value":"br"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=14917&min_rtt=14417&rtt_var=6407&sent=4&recv=5&lost=0&retrans=0&sent_bytes=2809&recv_bytes=1094&delivery_rate=158506&cwnd=176&unsent_bytes=0&cid=81e16b49815f1fb3&ts=2202&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Payment processed successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-260317-00004\",\n        \"transaction_number\": \"TXN-260317-000007\",\n        \"status\": \"processing\",\n        \"gateway_descriptor\": \"\",\n        \"total\": 279.99,\n        \"currency\": \"USD\",\n        \"subscription_created\": false,\n        \"subscription_number\": null\n    }\n}"}],"_postman_id":"1d28aaca-ec25-4852-98b2-0e3962d04da0"},{"name":"Capture Paypal","id":"a97904df-7e9a-438c-bb85-54d0632a19bf","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250324-00001","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/capture","description":"<h1 id=\"capture-paypal-payment\">Capture PayPal Payment</h1>\n<p>Captures a PayPal Wallet payment after the customer has approved it on PayPal. This is the final step in the PayPal redirect flow.</p>\n<p><strong>This endpoint is idempotent</strong> — if the payment has already been captured, it will return the current state without charging again.</p>\n<h2 id=\"flow\">Flow</h2>\n<ol>\n<li>Create an order or process a payment with <code>payment.method</code> set to <code>\"paypal_wallet\"</code>. You receive a <code>redirect_url</code> in the response.</li>\n<li>Redirect the customer to the <code>redirect_url</code>. They approve the payment on PayPal and are redirected back to your <code>return_url</code>.</li>\n<li><strong>Call this endpoint</strong> with the <code>order_number</code> to finalize the charge. Money does not move until this step completes.</li>\n</ol>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong><br />The order number returned from the Create Order or Process Payment response</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br />Indicates if the capture was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong><br />Human-readable description of the result (e.g., \"Payment captured successfully\", \"Payment already captured\")</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong><br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong><br />Unique identifier for the order</td>\n</tr>\n<tr>\n<td>data.transaction_number</td>\n<td><strong>string</strong><br />Unique identifier for the payment transaction</td>\n</tr>\n<tr>\n<td>data.payment_status</td>\n<td><strong>string</strong><br />Status of the payment transaction after capture. Values: <code>completed</code>, <code>pending_redirect</code></td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong><br />Current status of the order after capture (e.g., \"processing\")</td>\n</tr>\n<tr>\n<td>data.total</td>\n<td><strong>number</strong><br />Total amount captured</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong><br />Three-letter currency code (ISO 4217) used for the transaction</td>\n</tr>\n<tr>\n<td>data.payer_email</td>\n<td><strong>string (optional)</strong><br />The PayPal payer's email address. Only included if provided by PayPal</td>\n</tr>\n<tr>\n<td>data.subscription_created</td>\n<td><strong>boolean</strong><br />Indicates if a subscription was created during capture</td>\n</tr>\n<tr>\n<td>data.subscription_number</td>\n<td><strong>string or null</strong><br />Unique identifier for the subscription, if one was created</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status Code</th>\n<th>Condition</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>404</td>\n<td>Order not found, or no capturable transaction exists for the order</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Payment capture failed at PayPal (e.g., buyer did not approve, PayPal rejected the capture)</td>\n</tr>\n<tr>\n<td>500</td>\n<td>Unexpected server error during capture</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders","capture"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"4bdacce8-6074-4908-b569-20bc1e81091b","name":"Capture Paypal Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"order_number","value":"ORD-250324-00001","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders/capture"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Mon, 24 Mar 2025 13:47:44 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=hc%2BayptvH1XcWXqPdD4Ug0SsKnI%2FY9LLGvGr5WeCoVpS7zK%2BkgRWtRdt%2F7tGlxHYBN2id1plTJEI0y6fjIo5ddolT36BUCbuddne6%2FIMHyb3hG7udNXOLUAYLDkt637jciI%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"92569f42fd8d10c6-ORD"},{"key":"Content-Encoding","value":"br"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=17314&min_rtt=16117&rtt_var=6376&sent=33&recv=33&lost=0&retrans=0&sent_bytes=4466&recv_bytes=2311&delivery_rate=243766&cwnd=224&unsent_bytes=0&cid=289111252ed120f1&ts=28644&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Payment captured successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-260218-00001\",\n        \"transaction_number\": \"TXN-260218-00001\",\n        \"payment_status\": \"completed\",\n        \"status\": \"processing\",\n        \"total\": 49.95,\n        \"currency\": \"USD\",\n        \"payer_email\": \"buyer@example.com\",\n        \"subscription_created\": false,\n        \"subscription_number\": null\n    }\n}\n"}],"_postman_id":"a97904df-7e9a-438c-bb85-54d0632a19bf"},{"name":"Search Orders","id":"29ea9eb6-7169-4d28-9360-87a1e8901f8f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"customer[email]","value":"test@example.com","type":"text"},{"key":"customer[first_name]","value":"John","type":"text"},{"key":"customer[last_name]","value":"Doe","type":"text"},{"key":"customer[phone]","value":"5551234567","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"New York","type":"text"},{"key":"shipping[state]","value":"NY","type":"text"},{"key":"shipping[postal_code]","value":"10001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"best deals","type":"text"},{"key":"utm_content","value":"banner1","type":"text"},{"key":"affiliate_id","value":"AFF123","type":"text"},{"key":"sub_affiliate_id","value":"SUB456","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[1][offer_id]","value":"2","type":"text"},{"key":"products[1][quantity]","value":"1","type":"text"},{"key":"ip_address","value":"192.168.1.1","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/orders?order_number=ORD-250321-00001&date_start=2023-01-01&date_end=2025-12-31&per_page=20","description":"<h1 id=\"search-orders\">Search Orders</h1>\n<p>Return information about orders that match the specified search criteria from within the CRM</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>transaction_number</td>\n<td><em>string (optional)</em>  <br />Filter by transaction number</td>\n</tr>\n<tr>\n<td>subscription_number</td>\n<td><em>string (optional)</em>  <br />Filter by subscription number</td>\n</tr>\n<tr>\n<td>external_transaction_id</td>\n<td><em>string (optional)</em>  <br />Filter by external transaction ID</td>\n</tr>\n<tr>\n<td>order_number</td>\n<td><em>string (optional)</em>  <br />Filter by order number</td>\n</tr>\n<tr>\n<td>customer_number</td>\n<td><em>string (optional)</em>  <br />Filter by customer number</td>\n</tr>\n<tr>\n<td>customer_email</td>\n<td><em>string (optional)</em>  <br />Filter by customer email address</td>\n</tr>\n<tr>\n<td>customer_phone</td>\n<td><em>string (optional)</em>  <br />Filter by customer phone number</td>\n</tr>\n<tr>\n<td>customer_name</td>\n<td><em>string (optional)</em>  <br />Filter by customer name</td>\n</tr>\n<tr>\n<td>status</td>\n<td><em>string (optional)</em>  <br />Filter by transaction status. Supported values: <code>pending</code>, <code>processing</code>, <code>completed</code>, <code>declined</code>, <code>refunded</code>, <code>partially_refunded</code>, <code>externally_refunded</code>, <code>disputed_alert</code>, <code>disputed_rdr</code>, <code>chargeback</code>, <code>voided</code>, <code>on_hold</code>, <code>failed</code>, <code>abandoned</code></td>\n</tr>\n<tr>\n<td>order_status</td>\n<td><em>string (optional)</em>  <br />Filter by order status</td>\n</tr>\n<tr>\n<td>card_first_six</td>\n<td><em>string (optional)</em>  <br />Filter by first 6 digits of card number (BIN). Must be exactly 6 digits.</td>\n</tr>\n<tr>\n<td>card_last_four</td>\n<td><em>string (optional)</em>  <br />Filter by last 4 digits of card number. Must be exactly 4 digits.</td>\n</tr>\n<tr>\n<td>amount</td>\n<td><em>numeric (optional)</em>  <br />Filter by transaction amount (e.g., 29.99, 100.00)</td>\n</tr>\n<tr>\n<td>payment_method</td>\n<td><em>string (optional)</em>  <br />Filter by payment method (e.g., \"card\")</td>\n</tr>\n<tr>\n<td>campaign_id</td>\n<td><em>string (optional)</em>  <br />Filter by campaign ID</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em>string (optional)</em>  <br />Filter by gateway ID</td>\n</tr>\n<tr>\n<td>affiliate_id</td>\n<td><em>string (optional)</em>  <br />Filter by affiliate ID</td>\n</tr>\n<tr>\n<td>affiliate</td>\n<td><em>string (optional)</em>  <br />Filter by affiliate ID (alias for affiliate_id)</td>\n</tr>\n<tr>\n<td>sub_affiliate_id</td>\n<td><em>string (optional)</em>  <br />Filter by sub-affiliate ID (alias for sub1)</td>\n</tr>\n<tr>\n<td>sub1</td>\n<td><em>string (optional)</em>  <br />Filter by sub-affiliate 1</td>\n</tr>\n<tr>\n<td>sub2</td>\n<td><em>string (optional)</em>  <br />Filter by sub-affiliate 2</td>\n</tr>\n<tr>\n<td>sub3</td>\n<td><em>string (optional)</em>  <br />Filter by sub-affiliate 3</td>\n</tr>\n<tr>\n<td>sub4</td>\n<td><em>string (optional)</em>  <br />Filter by sub-affiliate 4</td>\n</tr>\n<tr>\n<td>sub5</td>\n<td><em>string (optional)</em>  <br />Filter by sub-affiliate 5</td>\n</tr>\n<tr>\n<td>utm_source</td>\n<td><em>string (optional)</em>  <br />Filter by UTM source</td>\n</tr>\n<tr>\n<td>utm_medium</td>\n<td><em>string (optional)</em>  <br />Filter by UTM medium</td>\n</tr>\n<tr>\n<td>utm_campaign</td>\n<td><em>string (optional)</em>  <br />Filter by UTM campaign</td>\n</tr>\n<tr>\n<td>utm_term</td>\n<td><em>string (optional)</em>  <br />Filter by UTM term</td>\n</tr>\n<tr>\n<td>utm_content</td>\n<td><em>string (optional)</em>  <br />Filter by UTM content</td>\n</tr>\n<tr>\n<td>date_start</td>\n<td><em>date (optional)</em>  <br />Filter for orders placed on or after this date  <br /><strong>Format:</strong> YYYY-MM-DD (e.g., 2024-01-15)  <br /><strong>Note:</strong> Time is automatically set to 00:00:00 (start of day) and converted to UTC based on your team's timezone setting.</td>\n</tr>\n<tr>\n<td>date_end</td>\n<td><em>date (optional)</em>  <br />Filter for orders placed on or before this date  <br /><strong>Format:</strong> YYYY-MM-DD (e.g., 2024-12-31)  <br /><strong>Note:</strong> Time is automatically set to 23:59:59 (end of day) and converted to UTC based on your team's timezone setting.</td>\n</tr>\n<tr>\n<td>is_test</td>\n<td><em>boolean (optional)</em>  <br />Filter by test orders</td>\n</tr>\n<tr>\n<td>is_blacklisted</td>\n<td><em>boolean (optional)</em>  <br />Filter by blacklisted customers</td>\n</tr>\n<tr>\n<td>is_throttled</td>\n<td><em>boolean (optional)</em>  <br />Filter by throttled orders</td>\n</tr>\n<tr>\n<td>qa_required</td>\n<td><em>boolean (optional)</em>  <br />Filter by orders requiring QA review</td>\n</tr>\n<tr>\n<td>has_subscriptions</td>\n<td><em>boolean (optional)</em>  <br />Filter by orders that have associated subscriptions</td>\n</tr>\n<tr>\n<td>fulfillment_status</td>\n<td><em>string (optional)</em>  <br />Filter by fulfillment status</td>\n</tr>\n<tr>\n<td>per_page</td>\n<td><em>integer (optional)</em>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>array</strong>  <br />Array of customer objects matching the search criteria</td>\n</tr>\n<tr>\n<td>data[].customer_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the customer</td>\n</tr>\n<tr>\n<td>data[].first_name</td>\n<td><strong>string</strong>  <br />Customer's first name</td>\n</tr>\n<tr>\n<td>data[].last_name</td>\n<td><strong>string</strong>  <br />Customer's last name</td>\n</tr>\n<tr>\n<td>data[].full_name</td>\n<td><strong>string</strong>  <br />Customer's full name (first and last name combined)</td>\n</tr>\n<tr>\n<td>data[].email</td>\n<td><strong>string</strong>  <br />Customer's email address</td>\n</tr>\n<tr>\n<td>data[].phone</td>\n<td><strong>string</strong>  <br />Customer's phone number</td>\n</tr>\n<tr>\n<td>data[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the customer was created (format: YYYY-MM-DD HH:MM:SS)</td>\n</tr>\n<tr>\n<td>data[].orders</td>\n<td><strong>array</strong>  <br />List of orders associated with the customer</td>\n</tr>\n<tr>\n<td>data[].orders[].order_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the order</td>\n</tr>\n<tr>\n<td>data[].orders[].campaign_name</td>\n<td><strong>string</strong>  <br />Name of the campaign associated with the order</td>\n</tr>\n<tr>\n<td>data[].orders[].campaign_id</td>\n<td><strong>string</strong>  <br />Internal ID of the campaign associated with the order</td>\n</tr>\n<tr>\n<td>data[].orders[].affiliate_name</td>\n<td><strong>string</strong>  <br />Name of the affiliate associated with the order</td>\n</tr>\n<tr>\n<td>data[].orders[].affiliate_id</td>\n<td><strong>string</strong>  <br />Custom ID of the affiliate associated with the order</td>\n</tr>\n<tr>\n<td>data[].orders[].sub1</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 1</td>\n</tr>\n<tr>\n<td>data[].orders[].sub2</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 2</td>\n</tr>\n<tr>\n<td>data[].orders[].sub3</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 3</td>\n</tr>\n<tr>\n<td>data[].orders[].sub4</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 4</td>\n</tr>\n<tr>\n<td>data[].orders[].sub5</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 5</td>\n</tr>\n<tr>\n<td>data[].orders[].utm_source</td>\n<td><strong>string</strong>  <br />UTM source parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].utm_medium</td>\n<td><strong>string</strong>  <br />UTM medium parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].utm_campaign</td>\n<td><strong>string</strong>  <br />UTM campaign parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].utm_term</td>\n<td><strong>string</strong>  <br />UTM term parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].utm_content</td>\n<td><strong>string</strong>  <br />UTM content parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].custom_fields</td>\n<td><strong>object</strong>  <br />Arbitrary key/value tracking data stored on the order. Empty object when none set.</td>\n</tr>\n<tr>\n<td>data[].orders[].status</td>\n<td><strong>string</strong>  <br />Current status of the order</td>\n</tr>\n<tr>\n<td>data[].orders[].currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code (ISO 4217) used for the order</td>\n</tr>\n<tr>\n<td>data[].orders[].is_throttled</td>\n<td><strong>boolean</strong>  <br />Indicates if the order was throttled</td>\n</tr>\n<tr>\n<td>data[].orders[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the order was created</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions</td>\n<td><strong>array</strong>  <br />List of transactions associated with this order</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].transaction_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].campaign_name</td>\n<td><strong>string</strong>  <br />Name of the campaign associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].campaign_id</td>\n<td><strong>string</strong>  <br />Internal ID of the campaign associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].gateway_name</td>\n<td><strong>string</strong>  <br />Name of the payment gateway used for the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].gateway_id</td>\n<td><strong>string</strong>  <br />Internal ID of the payment gateway used for the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].external_transaction_id</td>\n<td><strong>string</strong>  <br />Identifier provided by the payment gateway</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].status</td>\n<td><strong>string</strong>  <br />Status of the transaction (e.g., \"completed\", \"refunded\")</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].amount</td>\n<td><strong>string</strong>  <br />Transaction amount (negative for refunds)</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code for the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].payment_method</td>\n<td><strong>string</strong>  <br />Method used for payment (e.g., \"card\")</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].affiliate_name</td>\n<td><strong>string</strong>  <br />Name of the affiliate associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].affiliate_id</td>\n<td><strong>string</strong>  <br />Custom ID of the affiliate associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].sub1</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 1</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].sub2</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 2</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].sub3</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 3</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].sub4</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 4</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].sub5</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 5</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].utm_source</td>\n<td><strong>string</strong>  <br />UTM source parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].utm_medium</td>\n<td><strong>string</strong>  <br />UTM medium parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].utm_campaign</td>\n<td><strong>string</strong>  <br />UTM campaign parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].utm_term</td>\n<td><strong>string</strong>  <br />UTM term parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].utm_content</td>\n<td><strong>string</strong>  <br />UTM content parameter</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].card_brand</td>\n<td><strong>string</strong>  <br />Card brand/network (e.g., \"Visa\", \"Mastercard\", \"Amex\", \"Discover\")</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].card_first_six</td>\n<td><strong>string</strong>  <br />First 6 digits of the card number (BIN) used for the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].card_last_four</td>\n<td><strong>string</strong>  <br />Last 4 digits of the card number used for the transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].is_upsell</td>\n<td><strong>boolean</strong>  <br />Indicates if this transaction was for an upsell product</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].upsell_depth</td>\n<td><strong>integer</strong>  <br />Depth level of the upsell in the sales funnel</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].gateway_response</td>\n<td><strong>string</strong>  <br />Response code or message from the payment gateway</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].decline_code</td>\n<td><strong>string or null</strong>  <br />Team-mapped decline code for failed/declined transactions, resolved from the team's Decline Reason Mappings. <code>null</code> for approved transactions or when no mapping matches</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].is_reprocessable</td>\n<td><strong>boolean</strong>  <br /><code>true</code> when this is a declined/failed <strong>upsell</strong> transaction eligible for retry via <code>POST /checkout/orders/upsell/reprocess</code>. <code>false</code> for approved transactions and for declined non-upsell (main) transactions</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was created</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was last updated</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].products</td>\n<td><strong>array</strong>  <br />Array of products included in this transaction</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].products[].id</td>\n<td><strong>integer</strong>  <br />Unique identifier for the product</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].products[].name</td>\n<td><strong>string</strong>  <br />Name of the product</td>\n</tr>\n<tr>\n<td>data[].orders[].transactions[].products[].type</td>\n<td><strong>string</strong>  <br />Type of the product (e.g., \"offer\")</td>\n</tr>\n<tr>\n<td>data[].orders[].cart</td>\n<td><strong>object</strong>  <br />Contains information about the order's cart</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.tax</td>\n<td><strong>string</strong>  <br />Total tax amount for the order</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items</td>\n<td><strong>array</strong>  <br />List of items in the cart</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].quantity</td>\n<td><strong>integer</strong>  <br />Quantity of this product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].name</td>\n<td><strong>string</strong>  <br />Name of the product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].unit_price</td>\n<td><strong>number</strong>  <br />Price per unit of the product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].shipping_price</td>\n<td><strong>number</strong>  <br />Shipping cost for this product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].subtotal</td>\n<td><strong>number</strong>  <br />Product subtotal (unit_price x quantity)</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].tax</td>\n<td><strong>number</strong>  <br />Tax amount for this product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].is_upsell</td>\n<td><strong>boolean</strong>  <br />Indicates if this item is an upsell product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].id</td>\n<td><strong>integer</strong>  <br />Unique identifier for the product</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.items[].type</td>\n<td><strong>string</strong>  <br />Type of the product (e.g., \"offer\")</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.total</td>\n<td><strong>string</strong>  <br />Total amount of the order (subtotal + shipping + tax)</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.shipping</td>\n<td><strong>string</strong>  <br />Total shipping cost for the order</td>\n</tr>\n<tr>\n<td>data[].orders[].cart.subtotal</td>\n<td><strong>string</strong>  <br />Subtotal of all items before shipping and tax</td>\n</tr>\n<tr>\n<td>data[].addresses</td>\n<td><strong>array</strong>  <br />List of addresses associated with the customer</td>\n</tr>\n<tr>\n<td>data[].addresses[].name</td>\n<td><strong>string</strong>  <br />Full name associated with this address</td>\n</tr>\n<tr>\n<td>data[].addresses[].street_1</td>\n<td><strong>string</strong>  <br />Primary address line</td>\n</tr>\n<tr>\n<td>data[].addresses[].street_2</td>\n<td><strong>string</strong>  <br />Secondary address line (apartment, suite, etc.)</td>\n</tr>\n<tr>\n<td>data[].addresses[].city</td>\n<td><strong>string</strong>  <br />City name</td>\n</tr>\n<tr>\n<td>data[].addresses[].state_province</td>\n<td><strong>string</strong>  <br />State or province</td>\n</tr>\n<tr>\n<td>data[].addresses[].postal_code</td>\n<td><strong>string</strong>  <br />ZIP or postal code</td>\n</tr>\n<tr>\n<td>data[].addresses[].country_code</td>\n<td><strong>string</strong>  <br />Two-letter country code (ISO 3166-1 alpha-2)</td>\n</tr>\n<tr>\n<td>data[].addresses[].phone</td>\n<td><strong>string</strong>  <br />Phone number associated with this address</td>\n</tr>\n<tr>\n<td>data[].addresses[].email</td>\n<td><strong>string</strong>  <br />Email address associated with this address</td>\n</tr>\n<tr>\n<td>data[].addresses[].type</td>\n<td><strong>string</strong>  <br />Type of address (e.g., \"home\", \"work\")</td>\n</tr>\n<tr>\n<td>data[].addresses[].is_primary</td>\n<td><strong>boolean</strong>  <br />Indicates if this is the customer's primary address</td>\n</tr>\n<tr>\n<td>data[].addresses[].is_billing</td>\n<td><strong>boolean</strong>  <br />Indicates if this address is used for billing</td>\n</tr>\n<tr>\n<td>data[].addresses[].is_shipping</td>\n<td><strong>boolean</strong>  <br />Indicates if this address is used for shipping</td>\n</tr>\n<tr>\n<td>pagination</td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td>pagination.total</td>\n<td><strong>integer</strong>  <br />Total number of records matching the search criteria</td>\n</tr>\n<tr>\n<td>pagination.per_page</td>\n<td><strong>integer</strong>  <br />Number of records displayed per page</td>\n</tr>\n<tr>\n<td>pagination.current_page</td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td>pagination.last_page</td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders"],"host":["api","sparkcrm","io"],"query":[{"key":"order_number","value":"ORD-250321-00001"},{"disabled":true,"key":"customer_number","value":"CUST-230315-00001"},{"disabled":true,"key":"customer_email","value":"john.doe@example.com"},{"disabled":true,"key":"customer_phone","value":"5551234567"},{"disabled":true,"key":"customer_name","value":"John Doe"},{"disabled":true,"key":"status","value":"processing"},{"key":"date_start","value":"2023-01-01"},{"key":"date_end","value":"2025-12-31"},{"key":"per_page","value":"20"},{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"b2399e2d-2973-47b7-a7ca-9dd7f2cfdd70","name":"Search Orders Success","originalRequest":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"customer[email]","value":"test@example.com","type":"text"},{"key":"customer[first_name]","value":"John","type":"text"},{"key":"customer[last_name]","value":"Doe","type":"text"},{"key":"customer[phone]","value":"5551234567","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"New York","type":"text"},{"key":"shipping[state]","value":"NY","type":"text"},{"key":"shipping[postal_code]","value":"10001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"best deals","type":"text"},{"key":"utm_content","value":"banner1","type":"text"},{"key":"affiliate_id","value":"AFF123","type":"text"},{"key":"sub_affiliate_id","value":"SUB456","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[1][offer_id]","value":"2","type":"text"},{"key":"products[1][quantity]","value":"1","type":"text"},{"key":"ip_address","value":"192.168.1.1","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"}]},"url":{"raw":"https://api.sparkcrm.io/checkout/orders?order_number=ORD-250321-00001&date_start=2023-01-01&date_end=2025-12-31&per_page=20","protocol":"https","host":["api","sparkcrm","io"],"path":["checkout","orders"],"query":[{"key":"order_number","value":"ORD-250321-00001"},{"key":"customer_number","value":"CUST-230315-00001","type":"text","disabled":true},{"key":"customer_email","value":"john.doe@example.com","type":"text","disabled":true},{"key":"customer_phone","value":"5551234567","type":"text","disabled":true},{"key":"customer_name","value":"John Doe","type":"text","disabled":true},{"key":"status","value":"processing","type":"text","disabled":true},{"key":"date_start","value":"2023-01-01"},{"key":"date_end","value":"2025-12-31"},{"key":"per_page","value":"20"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:21:35 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Server","value":"cloudflare"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-Xss-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"Cf-Cache-Status","value":"DYNAMIC"},{"key":"Content-Encoding","value":"br"},{"key":"CF-RAY","value":"9239fa083e7c72eb-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"customer_number\": \"CUST-250529-00001\",\n            \"first_name\": \"Test\",\n            \"last_name\": \"Test\",\n            \"full_name\": \"Test Test\",\n            \"email\": \"johndoe@gmail.com\",\n            \"phone\": \"4444444444\",\n            \"created_at\": \"2025-05-29 14:56:53\",\n            \"orders\": [\n                {\n                    \"order_number\": \"ORD-250529-00001\",\n                    \"campaign_name\": \"Summer Health Promo\",\n                    \"campaign_id\": \"3\",\n                    \"affiliate_name\": \"HealthAds Network\",\n                    \"affiliate_id\": \"AFF-001\",\n                    \"sub1\": \"landing_v2\",\n                    \"sub2\": \"banner_top\",\n                    \"sub3\": null,\n                    \"sub4\": null,\n                    \"sub5\": null,\n                    \"utm_source\": \"google\",\n                    \"utm_medium\": \"cpc\",\n                    \"utm_campaign\": \"summer_sale\",\n                    \"utm_term\": \"best deals\",\n                    \"utm_content\": \"banner1\",\n                    \"custom_fields\": {\n                        \"partner_ref\": \"ACME-2024-Q4\",\n                        \"landing_variant\": \"hero-v3\"\n                    },\n                    \"status\": \"completed\",\n                    \"currency\": \"USD\",\n                    \"is_throttled\": false,\n                    \"created_at\": \"2025-05-29 14:56:53\",\n                    \"transactions\": [\n                        {\n                            \"transaction_number\": \"TXN-250529-000001\",\n                            \"campaign_name\": \"Summer Health Promo\",\n                            \"campaign_id\": \"3\",\n                            \"gateway_name\": \"NMI Production\",\n                            \"gateway_id\": \"5\",\n                            \"external_transaction_id\": \"SANDBOX-8E02E190-55B4-45FC-BAEB-05D141613532\",\n                            \"status\": \"completed\",\n                            \"amount\": \"270.00\",\n                            \"currency\": \"USD\",\n                            \"payment_method\": \"card\",\n                            \"affiliate_name\": \"HealthAds Network\",\n                            \"affiliate_id\": \"AFF-001\",\n                            \"sub1\": \"landing_v2\",\n                            \"sub2\": \"banner_top\",\n                            \"sub3\": null,\n                            \"sub4\": null,\n                            \"sub5\": null,\n                            \"utm_source\": \"google\",\n                            \"utm_medium\": \"cpc\",\n                            \"utm_campaign\": \"summer_sale\",\n                            \"utm_term\": \"best deals\",\n                            \"utm_content\": \"banner1\",\n                            \"card_brand\": \"Visa\",\n                            \"card_first_six\": \"411111\",\n                            \"card_last_four\": \"1111\",\n                            \"is_upsell\": false,\n                            \"upsell_depth\": 0,\n                            \"gateway_response\": \"Sandbox: Transaction approved\",\n                            \"decline_code\": null,\n                            \"is_reprocessable\": false,\n                            \"created_at\": \"2025-05-29 14:56:53\",\n                            \"updated_at\": \"2025-05-29 14:56:53\",\n                            \"products\": [\n                                {\n                                    \"id\": 9,\n                                    \"name\": \"Restore - 6 Bottles\",\n                                    \"type\": \"offer\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"cart\": {\n                        \"tax\": \"0.00\",\n                        \"items\": [\n                            {\n                                \"quantity\": 1,\n                                \"name\": \"Restore - 6 Bottles\",\n                                \"unit_price\": 270,\n                                \"shipping_price\": 0,\n                                \"subtotal\": 270,\n                                \"tax\": 0,\n                                \"is_upsell\": false,\n                                \"id\": 9,\n                                \"type\": \"offer\"\n                            }\n                        ],\n                        \"total\": \"270.00\",\n                        \"shipping\": \"0.00\",\n                        \"subtotal\": \"270.00\"\n                    }\n                }\n            ],\n            \"addresses\": [\n                {\n                    \"name\": \"Test Test\",\n                    \"street_1\": \"123 testing\",\n                    \"street_2\": \"\",\n                    \"city\": \"test\",\n                    \"state_province\": \"AL\",\n                    \"postal_code\": \"55555\",\n                    \"country_code\": \"US\",\n                    \"phone\": \"\",\n                    \"email\": \"johndoe@gmail.com\",\n                    \"type\": \"home\",\n                    \"is_primary\": true,\n                    \"is_billing\": true,\n                    \"is_shipping\": true\n                }\n            ]\n        }\n    ],\n    \"pagination\": {\n        \"total\": 1,\n        \"per_page\": 20,\n        \"current_page\": 1,\n        \"last_page\": 1\n    }\n}"}],"_postman_id":"29ea9eb6-7169-4d28-9360-87a1e8901f8f"},{"name":"Calculate Tax","id":"4c9e9410-6d0c-4f56-3e62-5937e40538ec","request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"type":"text","key":"campaign_id","value":"1"},{"type":"text","key":"shipping","value":"4.70"},{"type":"text","key":"to_address[country]","value":"US"},{"type":"text","key":"to_address[zip]","value":"90001"},{"type":"text","key":"to_address[state]","value":"CA"},{"type":"text","key":"to_address[city]","value":"Los Angeles"},{"type":"text","key":"to_address[street]","value":"123 Main St"},{"type":"text","key":"line_items[0][sku]","value":"SKU-001"},{"type":"text","key":"line_items[0][quantity]","value":"1"},{"type":"text","key":"line_items[0][unit_price]","value":"49.98"},{"type":"text","key":"line_items[0][tax_code]","value":"20010","disabled":true},{"type":"text","key":"line_items[1][sku]","value":"SKU-002","disabled":true},{"type":"text","key":"line_items[1][quantity]","value":"2","disabled":true},{"type":"text","key":"line_items[1][unit_price]","value":"29.99","disabled":true},{"type":"text","key":"line_items[1][tax_code]","value":"40030","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/tax","description":"<h1 id=\"calculate-tax\">Calculate Tax</h1>\n<p>Calculates sales tax for a cart in real time via the campaign's configured tax provider (TaxJar). Intended to be called during checkout whenever the cart or shipping address changes, so the tax amount displayed to the customer stays in sync with the line items and destination.</p>\n<p>If the campaign has no tax provider configured, is disabled, or the provider is inactive, the endpoint returns <code>tax_amount: 0</code>, <code>tax_rate: 0</code>, empty <code>breakdown</code>, and <code>tax_enabled: false</code>. Callers should treat that as a successful \"no tax required\" response rather than an error.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM. The API key must have the <code>api:tax.calculate</code> permission.</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>campaign_id</td>\n<td><strong>string (required)</strong><br />Internal ID for the campaign. Must belong to the authenticated user.</td>\n</tr>\n<tr>\n<td>shipping</td>\n<td><em>numeric (optional)</em><br />Total shipping amount for the cart. Minimum value: 0. Defaults to 0.</td>\n</tr>\n<tr>\n<td>to_address[country]</td>\n<td><strong>string (required)</strong><br />Destination country. Two-letter ISO 3166-1 alpha-2 code. Must be exactly 2 characters.</td>\n</tr>\n<tr>\n<td>to_address[zip]</td>\n<td><strong>string (required)</strong><br />Destination ZIP or postal code. Maximum length: 20 characters.</td>\n</tr>\n<tr>\n<td>to_address[state]</td>\n<td><strong>string (required)</strong><br />Destination state or province code (e.g. <code>CA</code>). Maximum length: 100 characters.</td>\n</tr>\n<tr>\n<td>to_address[city]</td>\n<td><em>string (optional)</em><br />Destination city. Maximum length: 100 characters.</td>\n</tr>\n<tr>\n<td>to_address[street]</td>\n<td><em>string (optional)</em><br />Destination street address line. Maximum length: 255 characters.</td>\n</tr>\n<tr>\n<td>line_items</td>\n<td><strong>array (required)</strong><br />Array of cart line items. Must contain at least one item.</td>\n</tr>\n<tr>\n<td>line_items[].sku</td>\n<td><em>string (optional)</em><br />SKU / product identifier for the line item. Maximum length: 100 characters.</td>\n</tr>\n<tr>\n<td>line_items[].quantity</td>\n<td><strong>integer (required)</strong><br />Quantity for the line item. Minimum value: 1.</td>\n</tr>\n<tr>\n<td>line_items[].unit_price</td>\n<td><strong>numeric (required)</strong><br />Unit price (pre-tax) for the line item. Minimum value: 0.</td>\n</tr>\n<tr>\n<td>line_items[].tax_code</td>\n<td><em>string (optional)</em><br />TaxJar product tax code for items taxed at reduced or exempt rates (e.g. <code>20010</code> for Clothing, <code>40030</code> for Food &amp; Groceries, <code>51020</code> for Prescription Drugs). Omit to treat the item as fully taxable. Invalid codes are rejected by TaxJar. Maximum length: 100 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br />Indicates whether the API request was successful.</td>\n</tr>\n<tr>\n<td>data.tax_amount</td>\n<td><strong>number</strong><br />Total sales tax to collect from the customer, in the campaign's currency.</td>\n</tr>\n<tr>\n<td>data.tax_rate</td>\n<td><strong>number</strong><br />Effective tax rate applied to the cart (e.g. <code>0.0875</code> for 8.75%).</td>\n</tr>\n<tr>\n<td>data.breakdown</td>\n<td><strong>object</strong><br />Per-jurisdiction breakdown of the tax amount. Keys: <code>state</code>, <code>county</code>, <code>city</code>, <code>special</code>.</td>\n</tr>\n<tr>\n<td>data.tax_enabled</td>\n<td><strong>boolean</strong><br /><code>true</code> when a tax provider ran the calculation. <code>false</code> when the campaign is not configured for tax — all other fields will be zero/empty.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"sample-success-response-tax-enabled\">Sample Success Response (tax enabled)</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"tax_amount\": 4.37,\n    \"tax_rate\": 0.0875,\n    \"breakdown\": {\n      \"state\": 3.00,\n      \"county\": 0.50,\n      \"city\": 0.50,\n      \"special\": 0.37\n    },\n    \"tax_enabled\": true\n  }\n}\n</code></pre>\n<h2 id=\"sample-success-response-tax-disabled\">Sample Success Response (tax disabled)</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"tax_amount\": 0,\n    \"tax_rate\": 0,\n    \"breakdown\": [],\n    \"tax_enabled\": false\n  }\n}\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Scenario</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>401</td>\n<td>API key missing or lacks the <code>api:tax.calculate</code> permission.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation failed. Response body includes a per-field <code>errors</code> object.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"product-tax-codes\">Product Tax Codes</h2>\n<p>TaxJar exposes a taxonomy of product categories that alter per-jurisdiction taxability (clothing is exempt in PA but taxable in CA, groceries are reduced-rate in many states, prescriptions are exempt nearly everywhere, etc.).</p>\n<ul>\n<li><strong>Omit <code>tax_code</code></strong> to treat the item as fully taxable — TaxJar's default.</li>\n<li><strong>Provide <code>tax_code</code></strong> to let TaxJar consult ship-from / ship-to / local rules for that category.</li>\n<li>Tax codes set on the Product in the CRM flow through automatically via the cart, so this field is mainly for callers that construct line items outside the normal product catalog.</li>\n<li>The full category list (~860 codes) is available at <code>GET /v2/categories</code> in the TaxJar API.</li>\n</ul>\n<h2 id=\"usage-notes\">Usage Notes</h2>\n<ul>\n<li>Call this endpoint during checkout whenever the shipping address or cart contents change.</li>\n<li>The returned <code>tax_amount</code> can be passed back to <code>POST /checkout/orders</code> as <code>tax_amount</code> (and optionally <code>tax_rate</code>) to lock in the calculated value. The Order endpoints will otherwise recompute tax server-side when the campaign has tax enabled.</li>\n<li>Tax is not persisted by this endpoint; nothing is sent to TaxJar's Transactions API until an order is actually created and completed.</li>\n</ul>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","tax"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"4c9e9410-6d0c-4f56-3e62-5937e40538ec"},{"name":"Reprocess Upsell","id":"bb0ff0f6-8bc4-9be2-a545-861453115857","request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"type":"text","key":"order_number","value":"ORD-260317-00004"},{"type":"text","key":"transaction_number","value":"TXN-260317-000005"},{"type":"text","key":"gateway_id","value":"1"},{"type":"text","key":"payment_orchestrator_id","value":"2","disabled":true},{"type":"text","key":"amount","value":"49.99","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/upsell/reprocess","description":"<h2 id=\"reprocess-upsell\">Reprocess Upsell</h2>\n<p>Retry a previously <strong>declined, failed, or errored upsell</strong> transaction. The endpoint re-charges the same upsell product on the existing order — optionally through a different gateway or with a fresh payment method.</p>\n<p>Target the attempt to retry with the <code>transaction_number</code> of a declined upsell, as surfaced by <strong>Search Orders</strong> / <strong>Search Transactions</strong> (where <code>is_reprocessable</code> is <code>true</code>).</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required Permission:</strong> <code>api:orders.upsell.reprocess</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_number</td>\n<td><strong>string (required)</strong><br />The order the declined upsell belongs to</td>\n</tr>\n<tr>\n<td>transaction_number</td>\n<td><strong>string (required)</strong><br />The declined/failed upsell transaction to reprocess. Format: <code>TXN-XXXXXX-XXXXXX</code>. Must be an upsell transaction on the given order whose status is declined, failed, or errored</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em>integer (optional)</em><br />Forces the retry through a specific gateway, overriding the upsell's stored gateway configuration. If both <code>gateway_id</code> and <code>payment_orchestrator_id</code> are provided, <code>gateway_id</code> takes precedence and <code>payment_orchestrator_id</code> is ignored</td>\n</tr>\n<tr>\n<td>payment_orchestrator_id</td>\n<td><em>integer (optional)</em><br />Forces the retry through a specific payment orchestrator, overriding the upsell's stored configuration. Ignored if <code>gateway_id</code> is also provided</td>\n</tr>\n<tr>\n<td>amount</td>\n<td><em>numeric (optional)</em><br />Overrides the total amount charged for the retry. Minimum value: 0.01. Treated as the final total — the upsell subtotal/unit price are scaled proportionally while shipping and tax stay anchored. If omitted, the original upsell amount is used</td>\n</tr>\n<tr>\n<td>payment[method]</td>\n<td><em>string (optional)</em><br />Payment method type. Allowed values: <code>card</code> (provide new card details), <code>onfile</code> (use a saved payment method). If omitted, the payment method stored on the declined upsell transaction is reused</td>\n</tr>\n<tr>\n<td>payment[card_number]</td>\n<td><strong>string (required if method is card)</strong><br />Credit/debit card number</td>\n</tr>\n<tr>\n<td>payment[card_exp]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if <code>card_exp_month</code> and <code>card_exp_year</code> are not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_month]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Two-digit expiration month (01-12). Must be exactly 2 characters. Required if <code>card_exp</code> is not provided</td>\n</tr>\n<tr>\n<td>payment[card_exp_year]</td>\n<td><strong>string (conditionally required for card payments)</strong><br />Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if <code>card_exp</code> is not provided</td>\n</tr>\n<tr>\n<td>payment[card_cvv]</td>\n<td><strong>string (required for card payments)</strong><br />Card verification value. Length: 3-4 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address]</td>\n<td><em>object (optional)</em><br />Billing address override for the retry attempt</td>\n</tr>\n<tr>\n<td>payment[billing_address][address1]</td>\n<td><em>string (optional)</em><br />Primary address line. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][address2]</td>\n<td><em>string (optional)</em><br />Secondary address line (apartment, suite, etc). Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][city]</td>\n<td><em>string (optional)</em><br />City name. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][state]</td>\n<td><em>string (optional)</em><br />State or province. Maximum length: 100 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][postal_code]</td>\n<td><em>string (optional)</em><br />ZIP or postal code. Maximum length: 20 characters</td>\n</tr>\n<tr>\n<td>payment[billing_address][country]</td>\n<td><em>string (optional)</em><br />Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"behavior\">Behavior</h2>\n<ul>\n<li><strong>Eligibility</strong> — Only <strong>upsell</strong> transactions with a status of <code>declined</code>, <code>failed</code>, or <code>error</code> can be reprocessed. Non-upsell (main) transactions and already-approved transactions are rejected.</li>\n<li><strong>Gateway override</strong> — Provide <code>gateway_id</code> (or <code>payment_orchestrator_id</code>) to force the retry through a specific gateway, overriding the upsell's stored gateway. If neither is provided, the upsell's configured gateway (offer gateway / upsell gateway / campaign default) is used. When both are provided, <code>gateway_id</code> wins.</li>\n<li><strong>Payment method</strong> — Provide a <code>payment</code> block to charge a new card or a saved (<code>onfile</code>) method. If omitted, the payment method from the declined upsell is reused.</li>\n<li><strong>Retry chaining</strong> — Each retry creates a new transaction linked to the original declined attempt; the retry attempt counter increments on each retry.</li>\n<li><strong>Idempotency</strong> — If an earlier attempt in the same decline lineage already succeeded, the prior successful result is returned without charging again.</li>\n<li><strong>Concurrency lock</strong> — Concurrent reprocesses of the same declined upsell are serialized; a second in-flight request returns <code>409</code>.</li>\n<li><strong>Refund / dispute guard</strong> — If the parent order has been refunded, partially refunded, or disputed/charged back, the declined upsell can no longer be reprocessed.</li>\n<li><strong>Attempt cap</strong> — When the campaign sets <code>max_reprocess_attempts_per_decline</code>, reprocessing is blocked once that many retries exist for the decline lineage.</li>\n</ul>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br />Indicates if the upsell was processed successfully. <code>false</code> when the retry is declined</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong><br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong><br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong><br />Unique identifier for the order</td>\n</tr>\n<tr>\n<td>data.transaction_number</td>\n<td><strong>string</strong><br />Unique identifier for the new upsell transaction created by this retry</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong><br />Status of the new upsell transaction (e.g. <code>completed</code>, <code>declined</code>)</td>\n</tr>\n<tr>\n<td>data.gateway_descriptor</td>\n<td><strong>string</strong><br />Statement descriptor from the gateway used. Only included if the gateway has a descriptor configured</td>\n</tr>\n<tr>\n<td>data.upsell_depth</td>\n<td><strong>integer</strong><br />Depth level of the upsell in the sales funnel</td>\n</tr>\n<tr>\n<td>data.total</td>\n<td><strong>number</strong><br />Total amount charged for this retry attempt</td>\n</tr>\n<tr>\n<td>data.tax_amount</td>\n<td><strong>string</strong><br />Sales tax portion of the upsell total, formatted to 2 decimals. <code>0.00</code> when no tax was applied</td>\n</tr>\n<tr>\n<td>data.tax_rate</td>\n<td><strong>number</strong><br />Effective tax rate recorded on the order. <code>0</code> when no rate was set</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong><br />Three-letter currency code (ISO 4217) used for the transaction</td>\n</tr>\n<tr>\n<td>data.subscription_created</td>\n<td><strong>boolean</strong><br />Indicates if a subscription was created with this upsell</td>\n</tr>\n<tr>\n<td>data.subscription_number</td>\n<td><strong>string</strong><br />Subscription number when a subscription was created, otherwise <code>null</code></td>\n</tr>\n<tr>\n<td>data.decline_code</td>\n<td><strong>string</strong><br />Team-mapped decline code. Included only when the retry is declined and a matching decline reason mapping exists</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Scenario</th>\n<th>Status Code</th>\n<th>Message</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Retry declined by gateway</td>\n<td>402</td>\n<td>Gateway decline message (response <code>data</code> includes <code>decline_code</code> when mapped)</td>\n</tr>\n<tr>\n<td>Order not found</td>\n<td>404</td>\n<td>Order not found</td>\n</tr>\n<tr>\n<td>Transaction not found on order</td>\n<td>404</td>\n<td>Transaction not found on this order</td>\n</tr>\n<tr>\n<td>Transaction is not an upsell</td>\n<td>422</td>\n<td>Transaction is not an upsell</td>\n</tr>\n<tr>\n<td>Transaction not declined/failed/errored</td>\n<td>422</td>\n<td>Transaction is not eligible for reprocess (must be declined, failed, or errored)</td>\n</tr>\n<tr>\n<td>Order refunded or disputed</td>\n<td>422</td>\n<td>Order has been refunded or disputed — declined upsells cannot be reprocessed</td>\n</tr>\n<tr>\n<td>Max reprocess attempts reached</td>\n<td>422</td>\n<td>Maximum reprocess attempts (N) reached for this declined upsell</td>\n</tr>\n<tr>\n<td>Cannot resolve campaign upsell</td>\n<td>422</td>\n<td>Cannot resolve campaign upsell linked to this transaction</td>\n</tr>\n<tr>\n<td>Validation failure</td>\n<td>422</td>\n<td>Validation errors returned per field</td>\n</tr>\n<tr>\n<td>Another reprocess already in progress</td>\n<td>409</td>\n<td>Another reprocess for this transaction is already in progress</td>\n</tr>\n<tr>\n<td>Upsell processing failure</td>\n<td>500</td>\n<td>Failed to reprocess upsell</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","orders","upsell","reprocess"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"36ee5cac-8085-684f-eda4-df560c1caf39","name":"Reprocess Upsell Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"type":"text","key":"order_number","value":"ORD-260317-00004"},{"type":"text","key":"transaction_number","value":"TXN-260317-000005"},{"type":"text","key":"gateway_id","value":"1"},{"type":"text","key":"payment_orchestrator_id","value":"2","disabled":true},{"type":"text","key":"amount","value":"49.99","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/upsell/reprocess","description":"## Reprocess Upsell\n\nRetry a previously **declined, failed, or errored upsell** transaction. The endpoint re-charges the same upsell product on the existing order — optionally through a different gateway or with a fresh payment method.\n\nTarget the attempt to retry with the `transaction_number` of a declined upsell, as surfaced by **Search Orders** / **Search Transactions** (where `is_reprocessable` is `true`).\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required Permission:** `api:orders.upsell.reprocess`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| order_number | **string (required)**<br>The order the declined upsell belongs to |\n| transaction_number | **string (required)**<br>The declined/failed upsell transaction to reprocess. Format: `TXN-XXXXXX-XXXXXX`. Must be an upsell transaction on the given order whose status is declined, failed, or errored |\n| gateway_id | _integer (optional)_<br>Forces the retry through a specific gateway, overriding the upsell's stored gateway configuration. If both `gateway_id` and `payment_orchestrator_id` are provided, `gateway_id` takes precedence and `payment_orchestrator_id` is ignored |\n| payment_orchestrator_id | _integer (optional)_<br>Forces the retry through a specific payment orchestrator, overriding the upsell's stored configuration. Ignored if `gateway_id` is also provided |\n| amount | _numeric (optional)_<br>Overrides the total amount charged for the retry. Minimum value: 0.01. Treated as the final total — the upsell subtotal/unit price are scaled proportionally while shipping and tax stay anchored. If omitted, the original upsell amount is used |\n| payment\\[method\\] | _string (optional)_<br>Payment method type. Allowed values: `card` (provide new card details), `onfile` (use a saved payment method). If omitted, the payment method stored on the declined upsell transaction is reused |\n| payment\\[card_number\\] | **string (required if method is card)**<br>Credit/debit card number |\n| payment\\[card_exp\\] | **string (conditionally required for card payments)**<br>Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if `card_exp_month` and `card_exp_year` are not provided |\n| payment\\[card_exp_month\\] | **string (conditionally required for card payments)**<br>Two-digit expiration month (01-12). Must be exactly 2 characters. Required if `card_exp` is not provided |\n| payment\\[card_exp_year\\] | **string (conditionally required for card payments)**<br>Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if `card_exp` is not provided |\n| payment\\[card_cvv\\] | **string (required for card payments)**<br>Card verification value. Length: 3-4 characters |\n| payment\\[billing_address\\] | _object (optional)_<br>Billing address override for the retry attempt |\n| payment\\[billing_address\\]\\[address1\\] | _string (optional)_<br>Primary address line. Maximum length: 255 characters |\n| payment\\[billing_address\\]\\[address2\\] | _string (optional)_<br>Secondary address line (apartment, suite, etc). Maximum length: 255 characters |\n| payment\\[billing_address\\]\\[city\\] | _string (optional)_<br>City name. Maximum length: 100 characters |\n| payment\\[billing_address\\]\\[state\\] | _string (optional)_<br>State or province. Maximum length: 100 characters |\n| payment\\[billing_address\\]\\[postal_code\\] | _string (optional)_<br>ZIP or postal code. Maximum length: 20 characters |\n| payment\\[billing_address\\]\\[country\\] | _string (optional)_<br>Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters |\n\n## Behavior\n\n- **Eligibility** — Only **upsell** transactions with a status of `declined`, `failed`, or `error` can be reprocessed. Non-upsell (main) transactions and already-approved transactions are rejected.\n- **Gateway override** — Provide `gateway_id` (or `payment_orchestrator_id`) to force the retry through a specific gateway, overriding the upsell's stored gateway. If neither is provided, the upsell's configured gateway (offer gateway / upsell gateway / campaign default) is used. When both are provided, `gateway_id` wins.\n- **Payment method** — Provide a `payment` block to charge a new card or a saved (`onfile`) method. If omitted, the payment method from the declined upsell is reused.\n- **Retry chaining** — Each retry creates a new transaction linked to the original declined attempt; the retry attempt counter increments on each retry.\n- **Idempotency** — If an earlier attempt in the same decline lineage already succeeded, the prior successful result is returned without charging again.\n- **Concurrency lock** — Concurrent reprocesses of the same declined upsell are serialized; a second in-flight request returns `409`.\n- **Refund / dispute guard** — If the parent order has been refunded, partially refunded, or disputed/charged back, the declined upsell can no longer be reprocessed.\n- **Attempt cap** — When the campaign sets `max_reprocess_attempts_per_decline`, reprocessing is blocked once that many retries exist for the decline lineage.\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| success | **boolean**<br>Indicates if the upsell was processed successfully. `false` when the retry is declined |\n| message | **string**<br>Human-readable description of the result |\n| data | **object**<br>Contains the detailed response data |\n| data.order_number | **string**<br>Unique identifier for the order |\n| data.transaction_number | **string**<br>Unique identifier for the new upsell transaction created by this retry |\n| data.status | **string**<br>Status of the new upsell transaction (e.g. `completed`, `declined`) |\n| data.gateway_descriptor | **string**<br>Statement descriptor from the gateway used. Only included if the gateway has a descriptor configured |\n| data.upsell_depth | **integer**<br>Depth level of the upsell in the sales funnel |\n| data.total | **number**<br>Total amount charged for this retry attempt |\n| data.tax_amount | **string**<br>Sales tax portion of the upsell total, formatted to 2 decimals. `0.00` when no tax was applied |\n| data.tax_rate | **number**<br>Effective tax rate recorded on the order. `0` when no rate was set |\n| data.currency | **string**<br>Three-letter currency code (ISO 4217) used for the transaction |\n| data.subscription_created | **boolean**<br>Indicates if a subscription was created with this upsell |\n| data.subscription_number | **string**<br>Subscription number when a subscription was created, otherwise `null` |\n| data.decline_code | **string**<br>Team-mapped decline code. Included only when the retry is declined and a matching decline reason mapping exists |\n\n## Error Responses\n\n| Scenario | Status Code | Message |\n| --- | --- | --- |\n| Retry declined by gateway | 402 | Gateway decline message (response `data` includes `decline_code` when mapped) |\n| Order not found | 404 | Order not found |\n| Transaction not found on order | 404 | Transaction not found on this order |\n| Transaction is not an upsell | 422 | Transaction is not an upsell |\n| Transaction not declined/failed/errored | 422 | Transaction is not eligible for reprocess (must be declined, failed, or errored) |\n| Order refunded or disputed | 422 | Order has been refunded or disputed — declined upsells cannot be reprocessed |\n| Max reprocess attempts reached | 422 | Maximum reprocess attempts (N) reached for this declined upsell |\n| Cannot resolve campaign upsell | 422 | Cannot resolve campaign upsell linked to this transaction |\n| Validation failure | 422 | Validation errors returned per field |\n| Another reprocess already in progress | 409 | Another reprocess for this transaction is already in progress |\n| Upsell processing failure | 500 | Failed to reprocess upsell |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Upsell processed successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-260317-00004\",\n        \"transaction_number\": \"TXN-260317-000008\",\n        \"gateway_descriptor\": \"test descriptor\",\n        \"status\": \"completed\",\n        \"upsell_depth\": 1,\n        \"total\": 49.99,\n        \"tax_amount\": \"0.00\",\n        \"tax_rate\": 0,\n        \"currency\": \"USD\",\n        \"subscription_created\": false,\n        \"subscription_number\": null\n    }\n}"},{"id":"d3faa269-fa4c-63c8-e8d4-c1483c6994f7","name":"402 — Upsell Reprocess Declined","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"type":"text","key":"order_number","value":"ORD-260317-00004"},{"type":"text","key":"transaction_number","value":"TXN-260317-000005"},{"type":"text","key":"gateway_id","value":"1"},{"type":"text","key":"payment_orchestrator_id","value":"2","disabled":true},{"type":"text","key":"amount","value":"49.99","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/orders/upsell/reprocess","description":"## Reprocess Upsell\n\nRetry a previously **declined, failed, or errored upsell** transaction. The endpoint re-charges the same upsell product on the existing order — optionally through a different gateway or with a fresh payment method.\n\nTarget the attempt to retry with the `transaction_number` of a declined upsell, as surfaced by **Search Orders** / **Search Transactions** (where `is_reprocessable` is `true`).\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required Permission:** `api:orders.upsell.reprocess`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| order_number | **string (required)**<br>The order the declined upsell belongs to |\n| transaction_number | **string (required)**<br>The declined/failed upsell transaction to reprocess. Format: `TXN-XXXXXX-XXXXXX`. Must be an upsell transaction on the given order whose status is declined, failed, or errored |\n| gateway_id | _integer (optional)_<br>Forces the retry through a specific gateway, overriding the upsell's stored gateway configuration. If both `gateway_id` and `payment_orchestrator_id` are provided, `gateway_id` takes precedence and `payment_orchestrator_id` is ignored |\n| payment_orchestrator_id | _integer (optional)_<br>Forces the retry through a specific payment orchestrator, overriding the upsell's stored configuration. Ignored if `gateway_id` is also provided |\n| amount | _numeric (optional)_<br>Overrides the total amount charged for the retry. Minimum value: 0.01. Treated as the final total — the upsell subtotal/unit price are scaled proportionally while shipping and tax stay anchored. If omitted, the original upsell amount is used |\n| payment\\[method\\] | _string (optional)_<br>Payment method type. Allowed values: `card` (provide new card details), `onfile` (use a saved payment method). If omitted, the payment method stored on the declined upsell transaction is reused |\n| payment\\[card_number\\] | **string (required if method is card)**<br>Credit/debit card number |\n| payment\\[card_exp\\] | **string (conditionally required for card payments)**<br>Combined expiration date. Accepted formats: \"MM/YY\", \"MMYY\", \"MM/YYYY\", \"MMYYYY\". Required if `card_exp_month` and `card_exp_year` are not provided |\n| payment\\[card_exp_month\\] | **string (conditionally required for card payments)**<br>Two-digit expiration month (01-12). Must be exactly 2 characters. Required if `card_exp` is not provided |\n| payment\\[card_exp_year\\] | **string (conditionally required for card payments)**<br>Expiration year. Can be 2 digits (YY) or 4 digits (YYYY). Required if `card_exp` is not provided |\n| payment\\[card_cvv\\] | **string (required for card payments)**<br>Card verification value. Length: 3-4 characters |\n| payment\\[billing_address\\] | _object (optional)_<br>Billing address override for the retry attempt |\n| payment\\[billing_address\\]\\[address1\\] | _string (optional)_<br>Primary address line. Maximum length: 255 characters |\n| payment\\[billing_address\\]\\[address2\\] | _string (optional)_<br>Secondary address line (apartment, suite, etc). Maximum length: 255 characters |\n| payment\\[billing_address\\]\\[city\\] | _string (optional)_<br>City name. Maximum length: 100 characters |\n| payment\\[billing_address\\]\\[state\\] | _string (optional)_<br>State or province. Maximum length: 100 characters |\n| payment\\[billing_address\\]\\[postal_code\\] | _string (optional)_<br>ZIP or postal code. Maximum length: 20 characters |\n| payment\\[billing_address\\]\\[country\\] | _string (optional)_<br>Two-letter country code (ISO 3166-1 alpha-2). Maximum length: 2 characters |\n\n## Behavior\n\n- **Eligibility** — Only **upsell** transactions with a status of `declined`, `failed`, or `error` can be reprocessed. Non-upsell (main) transactions and already-approved transactions are rejected.\n- **Gateway override** — Provide `gateway_id` (or `payment_orchestrator_id`) to force the retry through a specific gateway, overriding the upsell's stored gateway. If neither is provided, the upsell's configured gateway (offer gateway / upsell gateway / campaign default) is used. When both are provided, `gateway_id` wins.\n- **Payment method** — Provide a `payment` block to charge a new card or a saved (`onfile`) method. If omitted, the payment method from the declined upsell is reused.\n- **Retry chaining** — Each retry creates a new transaction linked to the original declined attempt; the retry attempt counter increments on each retry.\n- **Idempotency** — If an earlier attempt in the same decline lineage already succeeded, the prior successful result is returned without charging again.\n- **Concurrency lock** — Concurrent reprocesses of the same declined upsell are serialized; a second in-flight request returns `409`.\n- **Refund / dispute guard** — If the parent order has been refunded, partially refunded, or disputed/charged back, the declined upsell can no longer be reprocessed.\n- **Attempt cap** — When the campaign sets `max_reprocess_attempts_per_decline`, reprocessing is blocked once that many retries exist for the decline lineage.\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| success | **boolean**<br>Indicates if the upsell was processed successfully. `false` when the retry is declined |\n| message | **string**<br>Human-readable description of the result |\n| data | **object**<br>Contains the detailed response data |\n| data.order_number | **string**<br>Unique identifier for the order |\n| data.transaction_number | **string**<br>Unique identifier for the new upsell transaction created by this retry |\n| data.status | **string**<br>Status of the new upsell transaction (e.g. `completed`, `declined`) |\n| data.gateway_descriptor | **string**<br>Statement descriptor from the gateway used. Only included if the gateway has a descriptor configured |\n| data.upsell_depth | **integer**<br>Depth level of the upsell in the sales funnel |\n| data.total | **number**<br>Total amount charged for this retry attempt |\n| data.tax_amount | **string**<br>Sales tax portion of the upsell total, formatted to 2 decimals. `0.00` when no tax was applied |\n| data.tax_rate | **number**<br>Effective tax rate recorded on the order. `0` when no rate was set |\n| data.currency | **string**<br>Three-letter currency code (ISO 4217) used for the transaction |\n| data.subscription_created | **boolean**<br>Indicates if a subscription was created with this upsell |\n| data.subscription_number | **string**<br>Subscription number when a subscription was created, otherwise `null` |\n| data.decline_code | **string**<br>Team-mapped decline code. Included only when the retry is declined and a matching decline reason mapping exists |\n\n## Error Responses\n\n| Scenario | Status Code | Message |\n| --- | --- | --- |\n| Retry declined by gateway | 402 | Gateway decline message (response `data` includes `decline_code` when mapped) |\n| Order not found | 404 | Order not found |\n| Transaction not found on order | 404 | Transaction not found on this order |\n| Transaction is not an upsell | 422 | Transaction is not an upsell |\n| Transaction not declined/failed/errored | 422 | Transaction is not eligible for reprocess (must be declined, failed, or errored) |\n| Order refunded or disputed | 422 | Order has been refunded or disputed — declined upsells cannot be reprocessed |\n| Max reprocess attempts reached | 422 | Maximum reprocess attempts (N) reached for this declined upsell |\n| Cannot resolve campaign upsell | 422 | Cannot resolve campaign upsell linked to this transaction |\n| Validation failure | 422 | Validation errors returned per field |\n| Another reprocess already in progress | 409 | Another reprocess for this transaction is already in progress |\n| Upsell processing failure | 500 | Failed to reprocess upsell |"},"status":"Payment Required","code":402,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": false,\n    \"message\": \"Insufficient funds — please use another card.\",\n    \"data\": {\n        \"order_number\": \"ORD-260317-00004\",\n        \"transaction_number\": \"TXN-260317-000008\",\n        \"gateway_descriptor\": \"\",\n        \"status\": \"declined\",\n        \"upsell_depth\": 1,\n        \"total\": 49.99,\n        \"tax_amount\": \"0.00\",\n        \"tax_rate\": 0,\n        \"currency\": \"USD\",\n        \"subscription_created\": false,\n        \"subscription_number\": null,\n        \"decline_code\": \"INSUFFICIENT_FUNDS\"\n    }\n}"}],"_postman_id":"bb0ff0f6-8bc4-9be2-a545-861453115857"}],"id":"3031bf97-75df-4790-9403-006e027b03b9","description":"<h4 id=\"the-orders-api-allows-you-to-manage-customer-orders-process-payments-and-handle-upsells-within-the-spark-crm-system\">The Orders API allows you to manage customer orders, process payments, and handle upsells within the Spark CRM system</h4>\n<p>Here are example offers and how you would interract with the endpoints:</p>\n<ul>\n<li><p>Multiple Step Form with Upsells (Capture lead and then capture card information):<br />  Create Lead -&gt; Process Payment -&gt; Process Upsell #1 -&gt; Process Upsell #2 -&gt; Complete Order (optional)</p>\n</li>\n<li><p>Single Checkout Form with Upsells (Capture lead and card information in one form):<br />  Create Order -&gt; Process Upsell #1 -&gt; Process Upsell #2 -&gt; Complete Order (optional)</p>\n</li>\n</ul>\n<p>Note: The Create Order endpoint is a stand-alone order creation for 1-step checkouts.<br />Where as the Create Lead and Process Payment endpoint are paired together for 2-step checkouts</p>\n","_postman_id":"3031bf97-75df-4790-9403-006e027b03b9","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Transactions","item":[{"name":"Search Transactions","id":"5a42b160-6ff8-4d55-94f3-d84c32b50d2d","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"customer[email]","value":"test@example.com","type":"text"},{"key":"customer[first_name]","value":"John","type":"text"},{"key":"customer[last_name]","value":"Doe","type":"text"},{"key":"customer[phone]","value":"5551234567","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"New York","type":"text"},{"key":"shipping[state]","value":"NY","type":"text"},{"key":"shipping[postal_code]","value":"10001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"best deals","type":"text"},{"key":"utm_content","value":"banner1","type":"text"},{"key":"affiliate_id","value":"AFF123","type":"text"},{"key":"sub_affiliate_id","value":"SUB456","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[1][offer_id]","value":"2","type":"text"},{"key":"products[1][quantity]","value":"1","type":"text"},{"key":"ip_address","value":"192.168.1.1","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/transactions?transaction_number=TXN-250321-000002&date_start=2025-01-01&date_end=2025-03-22&per_page=10","description":"<h1 id=\"search-transactions\">Search Transactions</h1>\n<p>Return payment transactions that match the specified search criteria from within the CRM</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>transaction_number</td>\n<td><em>string (optional)</em>  <br />Filter by transaction number</td>\n</tr>\n<tr>\n<td>external_transaction_id</td>\n<td><em>string (optional)</em>  <br />Filter by external transaction ID (e.g. gateway reference)</td>\n</tr>\n<tr>\n<td>order_number</td>\n<td><em>string (optional)</em>  <br />Filter by associated order number</td>\n</tr>\n<tr>\n<td>customer_number</td>\n<td><em>string (optional)</em>  <br />Filter by customer number</td>\n</tr>\n<tr>\n<td>customer_email</td>\n<td><em>string (optional)</em>  <br />Filter by customer email address</td>\n</tr>\n<tr>\n<td>status</td>\n<td><em>string (optional)</em>  <br />Filter by transaction status. Possible values: \"pending\", \"processing\", \"authorized\", \"completed\", \"failed\", \"declined\", \"refunded\", \"partially_refunded\", \"alert_refunded\", \"rdr_refunded\", \"voided\", \"canceled\", \"expired\", \"chargeback\", \"error\"</td>\n</tr>\n<tr>\n<td>date_start</td>\n<td><em>date (optional)</em>  <br />Filter for transactions processed on or after this date (format: YYYY-MM-DD)</td>\n</tr>\n<tr>\n<td>date_end</td>\n<td><em>date (optional)</em>  <br />Filter for transactions processed on or before this date (format: YYYY-MM-DD)</td>\n</tr>\n<tr>\n<td>card_first_six</td>\n<td><em>string (optional)</em>  <br />Filter by first six digits of the card number (must be exactly 6 digits)</td>\n</tr>\n<tr>\n<td>card_last_four</td>\n<td><em>string (optional)</em>  <br />Filter by last four digits of the card number (must be exactly 4 digits)</td>\n</tr>\n<tr>\n<td>amount</td>\n<td><em>numeric (optional)</em>  <br />Filter by exact transaction amount</td>\n</tr>\n<tr>\n<td>per_page</td>\n<td><em>integer (optional)</em>  <br />Number of results per page. Minimum: 1, Maximum: 100</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>array</strong>  <br />Array of transaction objects matching the search criteria</td>\n</tr>\n<tr>\n<td>data[].customer_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the customer</td>\n</tr>\n<tr>\n<td>data[].order_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the order</td>\n</tr>\n<tr>\n<td>data[].card_first_six</td>\n<td><strong>string</strong>  <br />First six digits of the card number used for the transaction</td>\n</tr>\n<tr>\n<td>data[].card_last_four</td>\n<td><strong>string</strong>  <br />Last four digits of the card number used for the transaction</td>\n</tr>\n<tr>\n<td>data[].transaction_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the transaction</td>\n</tr>\n<tr>\n<td>data[].campaign_name</td>\n<td><strong>string</strong>  <br />Name of the campaign associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].campaign_id</td>\n<td><strong>string</strong>  <br />Internal ID of the campaign associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].gateway_name</td>\n<td><strong>string</strong>  <br />Name of the payment gateway used for the transaction</td>\n</tr>\n<tr>\n<td>data[].gateway_id</td>\n<td><strong>string</strong>  <br />Internal ID of the payment gateway used for the transaction</td>\n</tr>\n<tr>\n<td>data[].external_transaction_id</td>\n<td><strong>string</strong>  <br />Identifier provided by the payment gateway</td>\n</tr>\n<tr>\n<td>data[].status</td>\n<td><strong>string</strong>  <br />Status of the transaction. Possible values: \"pending\", \"processing\", \"authorized\", \"completed\", \"failed\", \"declined\", \"refunded\", \"partially_refunded\", \"alert_refunded\", \"rdr_refunded\", \"voided\", \"canceled\", \"expired\", \"chargeback\", \"error\"</td>\n</tr>\n<tr>\n<td>data[].amount</td>\n<td><strong>string</strong>  <br />Transaction amount</td>\n</tr>\n<tr>\n<td>data[].currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code (ISO 4217) used for the transaction</td>\n</tr>\n<tr>\n<td>data[].payment_method</td>\n<td><strong>string</strong>  <br />Method used for payment (e.g., \"card\")</td>\n</tr>\n<tr>\n<td>data[].affiliate_name</td>\n<td><strong>string</strong>  <br />Name of the affiliate associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].affiliate_id</td>\n<td><strong>string</strong>  <br />Custom ID of the affiliate associated with the transaction</td>\n</tr>\n<tr>\n<td>data[].sub1</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 1</td>\n</tr>\n<tr>\n<td>data[].sub2</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 2</td>\n</tr>\n<tr>\n<td>data[].sub3</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 3</td>\n</tr>\n<tr>\n<td>data[].sub4</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 4</td>\n</tr>\n<tr>\n<td>data[].sub5</td>\n<td><strong>string</strong>  <br />Sub-affiliate ID 5</td>\n</tr>\n<tr>\n<td>data[].utm_source</td>\n<td><strong>string</strong>  <br />UTM source parameter</td>\n</tr>\n<tr>\n<td>data[].utm_medium</td>\n<td><strong>string</strong>  <br />UTM medium parameter</td>\n</tr>\n<tr>\n<td>data[].utm_campaign</td>\n<td><strong>string</strong>  <br />UTM campaign parameter</td>\n</tr>\n<tr>\n<td>data[].utm_term</td>\n<td><strong>string</strong>  <br />UTM term parameter</td>\n</tr>\n<tr>\n<td>data[].utm_content</td>\n<td><strong>string</strong>  <br />UTM content parameter</td>\n</tr>\n<tr>\n<td>data[].card_brand</td>\n<td><strong>string</strong>  <br />Card brand/network (e.g., \"Visa\", \"Mastercard\", \"Amex\", \"Discover\")</td>\n</tr>\n<tr>\n<td>data[].is_upsell</td>\n<td><strong>boolean</strong>  <br />Indicates if this transaction was for an upsell product</td>\n</tr>\n<tr>\n<td>data[].upsell_depth</td>\n<td><strong>integer</strong>  <br />Depth level of the upsell in the sales funnel</td>\n</tr>\n<tr>\n<td>data[].gateway_response</td>\n<td><strong>string</strong>  <br />Response code or message from the payment gateway</td>\n</tr>\n<tr>\n<td>data[].decline_code</td>\n<td><strong>string or null</strong>  <br />Team-mapped decline code for failed/declined transactions, resolved from the team's Decline Reason Mappings. <code>null</code> for approved transactions or when no mapping matches</td>\n</tr>\n<tr>\n<td>data[].is_reprocessable</td>\n<td><strong>boolean</strong>  <br /><code>true</code> when this is a declined/failed <strong>upsell</strong> transaction eligible for retry via <code>POST /checkout/orders/upsell/reprocess</code>. <code>false</code> for approved transactions and for declined non-upsell (main) transactions</td>\n</tr>\n<tr>\n<td>data[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was created (format: YYYY-MM-DD HH:MM:SS)</td>\n</tr>\n<tr>\n<td>data[].updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was last updated (format: YYYY-MM-DD HH:MM:SS)</td>\n</tr>\n<tr>\n<td>data[].products</td>\n<td><strong>array</strong>  <br />Array of products included in this transaction</td>\n</tr>\n<tr>\n<td>data[].products[].id</td>\n<td><strong>integer</strong>  <br />Unique identifier for the product</td>\n</tr>\n<tr>\n<td>data[].products[].name</td>\n<td><strong>string</strong>  <br />Name of the product</td>\n</tr>\n<tr>\n<td>data[].products[].type</td>\n<td><strong>string</strong>  <br />Type of the product (e.g., \"offer\")</td>\n</tr>\n<tr>\n<td>pagination</td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td>pagination.total</td>\n<td><strong>integer</strong>  <br />Total number of records matching the search criteria</td>\n</tr>\n<tr>\n<td>pagination.per_page</td>\n<td><strong>integer</strong>  <br />Number of records displayed per page</td>\n</tr>\n<tr>\n<td>pagination.current_page</td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td>pagination.last_page</td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","transactions"],"host":["api","sparkcrm","io"],"query":[{"key":"transaction_number","value":"TXN-250321-000002"},{"disabled":true,"key":"external_transaction_id","value":"12345ABC"},{"disabled":true,"key":"order_number","value":"ORD-250315-00010"},{"disabled":true,"key":"customer_number","value":"CUST-250315-00005"},{"disabled":true,"key":"customer_email","value":"test@example.com"},{"disabled":true,"key":"status","value":"completed"},{"key":"date_start","value":"2025-01-01"},{"key":"date_end","value":"2025-03-22"},{"key":"per_page","value":"10"},{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"e820ad3d-f953-4068-8498-c7854a52007e","name":"Search Transactions Success","originalRequest":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"customer[email]","value":"test@example.com","type":"text"},{"key":"customer[first_name]","value":"John","type":"text"},{"key":"customer[last_name]","value":"Doe","type":"text"},{"key":"customer[phone]","value":"5551234567","type":"text"},{"key":"shipping[address1]","value":"123 Main St","type":"text"},{"key":"shipping[address2]","value":"Apt 4B","type":"text"},{"key":"shipping[city]","value":"New York","type":"text"},{"key":"shipping[state]","value":"NY","type":"text"},{"key":"shipping[postal_code]","value":"10001","type":"text"},{"key":"shipping[country]","value":"US","type":"text"},{"key":"campaign_id","value":"1","type":"text"},{"key":"currency","value":"USD","type":"text"},{"key":"utm_source","value":"google","type":"text"},{"key":"utm_medium","value":"cpc","type":"text"},{"key":"utm_campaign","value":"summer_sale","type":"text"},{"key":"utm_term","value":"best deals","type":"text"},{"key":"utm_content","value":"banner1","type":"text"},{"key":"affiliate_id","value":"AFF123","type":"text"},{"key":"sub_affiliate_id","value":"SUB456","type":"text"},{"key":"products[0][offer_id]","value":"1","type":"text"},{"key":"products[0][quantity]","value":"1","type":"text"},{"key":"products[1][offer_id]","value":"2","type":"text"},{"key":"products[1][quantity]","value":"1","type":"text"},{"key":"ip_address","value":"192.168.1.1","type":"text"},{"key":"user_agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","type":"text"}]},"url":{"raw":"https://api.sparkcrm.io/checkout/transactions?transaction_number=TXN-250321-000002&date_start=2025-01-01&date_end=2025-03-22&per_page=10","protocol":"https","host":["api","sparkcrm","io"],"path":["checkout","transactions"],"query":[{"key":"transaction_number","value":"TXN-250321-000002"},{"key":"external_transaction_id","value":"12345ABC","type":"text","disabled":true},{"key":"order_number","value":"ORD-250315-00010","type":"text","disabled":true},{"key":"customer_number","value":"CUST-250315-00005","type":"text","disabled":true},{"key":"customer_email","value":"test@example.com","disabled":true},{"key":"status","value":"completed","type":"text","disabled":true},{"key":"date_start","value":"2025-01-01"},{"key":"date_end","value":"2025-03-22"},{"key":"per_page","value":"10"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:20:41 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Server","value":"cloudflare"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-Xss-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"Cf-Cache-Status","value":"DYNAMIC"},{"key":"Content-Encoding","value":"br"},{"key":"CF-RAY","value":"9239f8b72c7f72eb-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"customer_number\": \"CUST-250529-00001\",\n            \"order_number\": \"ORD-250529-00001\",\n            \"transaction_number\": \"TXN-250529-000001\",\n            \"campaign_name\": \"Summer Health Promo\",\n            \"campaign_id\": \"3\",\n            \"gateway_name\": \"NMI Production\",\n            \"gateway_id\": \"5\",\n            \"external_transaction_id\": \"SANDBOX-8E02E190-55B4-45FC-BAEB-05D141613532\",\n            \"status\": \"completed\",\n            \"amount\": \"270.00\",\n            \"currency\": \"USD\",\n            \"payment_method\": \"card\",\n            \"affiliate_name\": \"HealthAds Network\",\n            \"affiliate_id\": \"AFF-001\",\n            \"sub1\": \"landing_v2\",\n            \"sub2\": \"banner_top\",\n            \"sub3\": null,\n            \"sub4\": null,\n            \"sub5\": null,\n            \"utm_source\": \"google\",\n            \"utm_medium\": \"cpc\",\n            \"utm_campaign\": \"summer_sale\",\n            \"utm_term\": \"best deals\",\n            \"utm_content\": \"banner1\",\n            \"card_brand\": \"Visa\",\n            \"card_first_six\": \"411111\",\n            \"card_last_four\": \"1111\",\n            \"is_upsell\": false,\n            \"upsell_depth\": 0,\n            \"gateway_response\": \"Sandbox: Transaction approved\",\n            \"decline_code\": null,\n            \"is_reprocessable\": false,\n            \"created_at\": \"2025-05-29 14:56:53\",\n            \"updated_at\": \"2025-05-29 14:56:53\",\n            \"products\": [\n                {\n                    \"id\": 9,\n                    \"name\": \"Restore - 6 Bottles\",\n                    \"type\": \"offer\"\n                }\n            ]\n        }\n    ],\n    \"pagination\": {\n        \"total\": 1,\n        \"per_page\": 10,\n        \"current_page\": 1,\n        \"last_page\": 1\n    }\n}"}],"_postman_id":"5a42b160-6ff8-4d55-94f3-d84c32b50d2d"},{"name":"Refund Transaction","id":"681718e6-d47d-4005-9495-d3b209b4cbfb","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"transaction_number","value":"TXN-250321-000002","type":"text"},{"key":"amount","value":"25.00","type":"text","disabled":true},{"key":"is_external","value":"false","type":"text"},{"key":"refund_reason","value":"Customer dissatisfied with product","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/transactions/refund","description":"<h1 id=\"refund-transaction\">Refund Transaction</h1>\n<p>Process a refund for a specific transaction from within the CRM</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>transaction_number</td>\n<td><strong>string (required)</strong>  <br />The transaction number to refund</td>\n</tr>\n<tr>\n<td>amount</td>\n<td><em>numeric (optional)</em>  <br />Amount to refund. Minimum value: 0.01. If not provided, the full transaction amount will be refunded</td>\n</tr>\n<tr>\n<td>is_external</td>\n<td><em>boolean (optional)</em>  <br />Indicates if the refund was processed outside the system. Accepted values: true, false, 1, 0, yes, no</td>\n</tr>\n<tr>\n<td>refund_reason</td>\n<td><em>string (optional)</em>  <br />Reason for the refund. Maximum length: 255 characters</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Contains the detailed response data</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong>  <br />The unique identifier for the order</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Current status of the order (e.g., \"refunded\")</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code (ISO 4217) used for the order</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date and time when the order was created (format: YYYY-MM-DD HH:MM:SS)</td>\n</tr>\n<tr>\n<td>data.transactions</td>\n<td><strong>array</strong>  <br />List of transactions associated with this order</td>\n</tr>\n<tr>\n<td>data.transactions[].transaction_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the transaction</td>\n</tr>\n<tr>\n<td>data.transactions[].external_transaction_id</td>\n<td><strong>string</strong>  <br />Identifier provided by the payment gateway</td>\n</tr>\n<tr>\n<td>data.transactions[].status</td>\n<td><strong>string</strong>  <br />Status of the transaction (e.g., \"completed\", \"refunded\")</td>\n</tr>\n<tr>\n<td>data.transactions[].amount</td>\n<td><strong>string</strong>  <br />Transaction amount (negative for refunds)</td>\n</tr>\n<tr>\n<td>data.transactions[].currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code for the transaction</td>\n</tr>\n<tr>\n<td>data.transactions[].payment_method</td>\n<td><strong>string</strong>  <br />Method used for payment (e.g., \"card\")</td>\n</tr>\n<tr>\n<td>data.transactions[].is_upsell</td>\n<td><strong>boolean</strong>  <br />Indicates if this transaction was for an upsell product</td>\n</tr>\n<tr>\n<td>data.transactions[].upsell_depth</td>\n<td><strong>integer</strong>  <br />Depth level of the upsell in the sales funnel</td>\n</tr>\n<tr>\n<td>data.transactions[].gateway_response</td>\n<td><strong>string</strong>  <br />Response code or message from the payment gateway</td>\n</tr>\n<tr>\n<td>data.transactions[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was created</td>\n</tr>\n<tr>\n<td>data.transactions[].updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was last updated</td>\n</tr>\n<tr>\n<td>data.cart</td>\n<td><strong>object</strong>  <br />Contains information about the order's cart</td>\n</tr>\n<tr>\n<td>data.cart.tax</td>\n<td><strong>string</strong>  <br />Total tax amount for the order</td>\n</tr>\n<tr>\n<td>data.cart.items</td>\n<td><strong>array</strong>  <br />List of items in the cart</td>\n</tr>\n<tr>\n<td>data.cart.items[].quantity</td>\n<td><strong>string</strong>  <br />Quantity of this product</td>\n</tr>\n<tr>\n<td>data.cart.items[].unit_price</td>\n<td><strong>string</strong>  <br />Price per unit of the product</td>\n</tr>\n<tr>\n<td>data.cart.items[].shipping_price</td>\n<td><strong>string</strong>  <br />Shipping cost for this product</td>\n</tr>\n<tr>\n<td>data.cart.items[].subtotal</td>\n<td><strong>number</strong>  <br />Product subtotal (unit_price × quantity)</td>\n</tr>\n<tr>\n<td>data.cart.items[].tax</td>\n<td><strong>number</strong>  <br />Tax amount for this product</td>\n</tr>\n<tr>\n<td>data.cart.items[].is_upsell</td>\n<td><strong>boolean</strong>  <br />Indicates if this item is an upsell product</td>\n</tr>\n<tr>\n<td>data.cart.items[].offer_id</td>\n<td><strong>integer</strong>  <br />ID of the offer associated with this product (if applicable)</td>\n</tr>\n<tr>\n<td>data.cart.total</td>\n<td><strong>string</strong>  <br />Total amount of the order (subtotal + shipping + tax)</td>\n</tr>\n<tr>\n<td>data.cart.shipping</td>\n<td><strong>string</strong>  <br />Total shipping cost for the order</td>\n</tr>\n<tr>\n<td>data.cart.subtotal</td>\n<td><strong>string</strong>  <br />Subtotal of all items before shipping and tax</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"taxjar-integration\">TaxJar Integration</h2>\n<p>When a refund is processed on an order whose campaign has TaxJar enabled and whose original order was posted to TaxJar, a matching refund transaction is automatically posted to TaxJar's <code>/v2/transactions/refunds</code> endpoint. No additional request fields are required — tax handling is driven by the campaign's tax provider configuration and the order's original TaxJar transaction.</p>\n<p><strong>Proration:</strong> The refund's tax and shipping portions are prorated by <code>refund_amount / order_total</code> against the original order's tax and shipping. Example — refunding $59.38 of a $118.75 order (50%) posts <code>sales_tax: -4.38</code> against the original <code>sales_tax: 8.75</code>.</p>\n<p><strong>Coverage:</strong></p>\n<ul>\n<li>Full refunds, partial refunds, and multiple refunds against the same order.</li>\n<li>Post-capture voids (<code>OrderVoidedEvent</code>) on TaxJar-posted orders — sent as a full-amount negative refund.</li>\n<li>External / RDR refunds (<code>is_external: true</code>) — still posted since TaxJar tracks tax liability regardless of money movement.</li>\n<li>Dispute-alert refunds (via Dispute.com) processed by <code>ProcessAlertRefundAction</code>.</li>\n</ul>\n<p><strong>Idempotency:</strong> Each refund is posted with a stable <code>transaction_id</code> of <code>\"{order_id}-refund-{transaction_id}\"</code> and a <code>transaction_reference_id</code> linking to the original order. Duplicate posts (422) are treated as success. The <code>transactions.tax_posted_at</code> timestamp marks which refund rows have been posted.</p>\n<p><strong>Skipped cases:</strong> Orders without a TaxJar provider, with <code>tax_enabled: false</code>, or that were never posted to TaxJar (<code>orders.tax_posted_at</code> null) — nothing is sent in these cases.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","transactions","refund"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"fa956c37-e293-4913-b779-5bf700a26a0d","name":"Refund Transaction Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"transaction_number","value":"TXN-250321-000002","type":"text"},{"key":"amount","value":"25.00","type":"text","disabled":true},{"key":"is_external","value":"false","type":"text"},{"key":"refund_reason","value":"Customer dissatisfied with product","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/transactions/refund"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:18:17 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-XSS-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"cf-cache-status","value":"DYNAMIC"},{"key":"Report-To","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=AvMgevgPbZjCScyNbta1s%2FoZ6a0aTUPoUb%2B7P4w1nQtOy1Tj9hp8eLpZzMpR%2BW6lQVjiIGbRw%2FlvyTSTOGVT8dfJHUME%2Fssq2yYVGHxih8G3BuiO%2FNHeWX%2F6siS1jYbWUZI%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"key":"NEL","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"key":"Server","value":"cloudflare"},{"key":"CF-RAY","value":"9239f52ac835e821-ORD"},{"key":"Content-Encoding","value":"br"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"},{"key":"server-timing","value":"cfL4;desc=\"?proto=TCP&rtt=13874&min_rtt=13033&rtt_var=5488&sent=4&recv=5&lost=0&retrans=0&sent_bytes=2809&recv_bytes=848&delivery_rate=224046&cwnd=250&unsent_bytes=0&cid=f867c0497da7b3f5&ts=1425&x=0\""}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Transaction refunded successfully\",\n    \"data\": {\n        \"order_number\": \"ORD-250321-00001\",\n        \"status\": \"refunded\",\n        \"currency\": \"USD\",\n        \"created_at\": \"2025-03-21 01:59:46\",\n        \"transactions\": [\n            {\n                \"transaction_number\": \"TXN-250321-000001\",\n                \"external_transaction_id\": \"10528333031\",\n                \"status\": \"completed\",\n                \"amount\": \"689.97\",\n                \"currency\": \"USD\",\n                \"payment_method\": \"card\",\n                \"is_upsell\": false,\n                \"upsell_depth\": 1,\n                \"gateway_response\": \"SUCCESS\",\n                \"created_at\": \"2025-03-21 02:13:55\",\n                \"updated_at\": \"2025-03-21 02:13:55\"\n            },\n            {\n                \"transaction_number\": \"TXN-250321-000002\",\n                \"external_transaction_id\": \"10528336842\",\n                \"status\": \"completed\",\n                \"amount\": \"34.98\",\n                \"currency\": \"USD\",\n                \"payment_method\": \"card\",\n                \"is_upsell\": true,\n                \"upsell_depth\": 1,\n                \"gateway_response\": \"SUCCESS\",\n                \"created_at\": \"2025-03-21 02:16:22\",\n                \"updated_at\": \"2025-03-21 02:16:22\"\n            },\n            {\n                \"transaction_number\": \"TXN-250321-000003\",\n                \"external_transaction_id\": \"10528339625\",\n                \"status\": \"refunded\",\n                \"amount\": \"-34.98\",\n                \"currency\": \"USD\",\n                \"payment_method\": \"card\",\n                \"is_upsell\": false,\n                \"upsell_depth\": 1,\n                \"gateway_response\": \"SUCCESS\",\n                \"created_at\": \"2025-03-21 02:18:17\",\n                \"updated_at\": \"2025-03-21 02:18:17\"\n            }\n        ],\n        \"cart\": {\n            \"tax\": \"0.00\",\n            \"items\": [\n                {\n                    \"quantity\": \"1\",\n                    \"unit_price\": \"279.99\",\n                    \"shipping_price\": \"9.99\",\n                    \"subtotal\": 279.99,\n                    \"tax\": 0,\n                    \"is_upsell\": false,\n                    \"offer_id\": 1\n                },\n                {\n                    \"quantity\": \"1\",\n                    \"unit_price\": \"399.99\",\n                    \"shipping_price\": \"0.00\",\n                    \"subtotal\": 399.99,\n                    \"tax\": 0,\n                    \"is_upsell\": false,\n                    \"offer_id\": 2\n                },\n                {\n                    \"quantity\": \"1\",\n                    \"unit_price\": \"29.99\",\n                    \"shipping_price\": \"4.99\",\n                    \"subtotal\": 29.99,\n                    \"tax\": 0,\n                    \"is_upsell\": true\n                }\n            ],\n            \"total\": \"724.95\",\n            \"shipping\": \"14.98\",\n            \"subtotal\": \"709.97\"\n        }\n    }\n}"}],"_postman_id":"681718e6-d47d-4005-9495-d3b209b4cbfb"},{"name":"Chargeback Transaction","id":"9dd36b1a-890f-5808-58e0-02bb31fe3da5","request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"transaction_number","value":"TXN-250321-000002","type":"text"},{"key":"reason_code","value":"4853","type":"text"},{"key":"reason","value":"Customer reported an unauthorized charge","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/transactions/chargeback","description":"<h1 id=\"chargeback-transaction\">Chargeback Transaction</h1>\n<p>Mark an existing transaction as a chargeback from within the CRM.</p>\n<p>This endpoint records a chargeback against the <strong>original</strong> transaction — it creates a new negative-amount transaction linked to the original and sets the order status to <code>chargeback</code>. <strong>It does not issue a refund.</strong> The original transaction is left intact for record keeping. Use this when a chargeback has occurred outside the system (for example, reported by your processor) and you need to reflect it in the CRM.</p>\n<p>As part of marking the chargeback, the customer's active subscriptions are cancelled and the customer is added to the blacklist.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p>Requires the <code>api:transactions.chargeback</code> token permission.</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>transaction_number</td>\n<td><strong>string (required)</strong>  <br />The transaction number to mark as a chargeback. Must belong to your team and be a successful (completed/authorized) sale.</td>\n</tr>\n<tr>\n<td>reason_code</td>\n<td><em>string (optional)</em>  <br />The chargeback reason code (for example, <code>4853</code>). Maximum length: 50 characters.</td>\n</tr>\n<tr>\n<td>reason</td>\n<td><em>string (optional)</em>  <br />Free-text chargeback reason recorded on the order and transaction notes. Maximum length: 1000 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />The order, including its transactions. The newly recorded chargeback appears as a transaction with a negative <code>amount</code> and status <code>chargeback</code>.</td>\n</tr>\n<tr>\n<td>data.order_number</td>\n<td><strong>string</strong>  <br />The unique identifier for the order</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Current status of the order (<code>chargeback</code> after this call)</td>\n</tr>\n<tr>\n<td>data.currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code (ISO 4217) used for the order</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date and time when the order was created (format: YYYY-MM-DD HH:MM:SS)</td>\n</tr>\n<tr>\n<td>data.transactions</td>\n<td><strong>array</strong>  <br />List of transactions associated with this order</td>\n</tr>\n<tr>\n<td>data.transactions[].transaction_number</td>\n<td><strong>string</strong>  <br />Unique identifier for the transaction</td>\n</tr>\n<tr>\n<td>data.transactions[].external_transaction_id</td>\n<td><strong>string</strong>  <br />Identifier provided by the payment gateway</td>\n</tr>\n<tr>\n<td>data.transactions[].status</td>\n<td><strong>string</strong>  <br />Status of the transaction (e.g., <code>completed</code>, <code>chargeback</code>)</td>\n</tr>\n<tr>\n<td>data.transactions[].amount</td>\n<td><strong>string</strong>  <br />Transaction amount (negative for the chargeback record)</td>\n</tr>\n<tr>\n<td>data.transactions[].currency</td>\n<td><strong>string</strong>  <br />Three-letter currency code for the transaction</td>\n</tr>\n<tr>\n<td>data.transactions[].payment_method</td>\n<td><strong>string</strong>  <br />Method used for payment (e.g., <code>card</code>)</td>\n</tr>\n<tr>\n<td>data.transactions[].gateway_response</td>\n<td><strong>string</strong>  <br />Response code or message from the payment gateway</td>\n</tr>\n<tr>\n<td>data.transactions[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was created</td>\n</tr>\n<tr>\n<td>data.transactions[].updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the transaction was last updated</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"side-effects\">Side Effects</h2>\n<ul>\n<li><strong>No refund is issued.</strong> The original transaction keeps its <code>completed</code> status; a new linked transaction with status <code>chargeback</code> and a negative amount is created for record keeping.</li>\n<li><strong>Order status</strong> is recomputed to <code>chargeback</code>.</li>\n<li><strong>Subscriptions:</strong> the customer's active subscriptions are cancelled.</li>\n<li><strong>Blacklist:</strong> the customer's email, phone, IP, and shipping address are added to the team blacklist.</li>\n<li>An order note and transaction note are recorded, including the reason code and reason when supplied.</li>\n</ul>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Condition</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:transactions.chargeback</code> permission</td>\n</tr>\n<tr>\n<td>404</td>\n<td>No transaction with that number exists for your team</td>\n</tr>\n<tr>\n<td>409</td>\n<td>The transaction is already marked as a chargeback</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation failed, or the transaction is not a successful sale</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","transactions","chargeback"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"993c4bba-4dfa-c20f-a836-c4e996350426","name":"Chargeback Transaction Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"transaction_number","value":"TXN-250321-000002","type":"text"},{"key":"reason_code","value":"4853","type":"text"},{"key":"reason","value":"Customer reported an unauthorized charge","type":"text"}]},"url":"https://api.sparkcrm.io/checkout/transactions/chargeback"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Transaction marked as chargeback\",\n    \"data\": {\n        \"order_number\": \"ORD-250321-00001\",\n        \"status\": \"chargeback\",\n        \"currency\": \"USD\",\n        \"created_at\": \"2025-03-21 01:59:46\",\n        \"transactions\": [\n            {\n                \"transaction_number\": \"TXN-250321-000002\",\n                \"external_transaction_id\": \"10528336842\",\n                \"status\": \"completed\",\n                \"amount\": \"118.75\",\n                \"currency\": \"USD\",\n                \"payment_method\": \"card\",\n                \"is_upsell\": false,\n                \"upsell_depth\": 1,\n                \"gateway_response\": \"SUCCESS\",\n                \"created_at\": \"2025-03-21 02:16:22\",\n                \"updated_at\": \"2025-03-21 02:16:22\"\n            },\n            {\n                \"transaction_number\": \"TXN-250321-000004\",\n                \"external_transaction_id\": null,\n                \"status\": \"chargeback\",\n                \"amount\": \"-118.75\",\n                \"currency\": \"USD\",\n                \"payment_method\": \"card\",\n                \"is_upsell\": false,\n                \"upsell_depth\": 1,\n                \"gateway_response\": \"Chargeback recorded — Dispute Chargeback ID: 4853\",\n                \"created_at\": \"2025-03-21 02:20:11\",\n                \"updated_at\": \"2025-03-21 02:20:11\"\n            }\n        ],\n        \"cart\": {\n            \"tax\": \"8.75\",\n            \"items\": [\n                {\n                    \"quantity\": \"1\",\n                    \"unit_price\": \"100.00\",\n                    \"shipping_price\": \"10.00\",\n                    \"subtotal\": 100.00,\n                    \"tax\": 8.75,\n                    \"is_upsell\": false,\n                    \"offer_id\": 1\n                }\n            ],\n            \"total\": \"118.75\",\n            \"shipping\": \"10.00\",\n            \"subtotal\": \"100.00\"\n        }\n    }\n}"}],"_postman_id":"9dd36b1a-890f-5808-58e0-02bb31fe3da5"}],"id":"553499a3-c903-41c1-885a-e97b92630ddf","description":"<h4 id=\"transactions-api-allows-you-to-search-for-transactions-process-refunds-and-mark-transactions-as-chargebacks-within-the-crm\">Transactions API allows you to search for transactions, process refunds, and mark transactions as chargebacks within the CRM</h4>\n","_postman_id":"553499a3-c903-41c1-885a-e97b92630ddf","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Subscriptions","item":[{"name":"Check Subscription Status","id":"4be79cf8-b036-544a-656d-80339cda6205","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/checkout/subscriptions/check-status?order_id=ORD-251104-0001","description":"<h1 id=\"check-subscription-status\">Check Subscription Status</h1>\n<p>Sanity check whether a customer currently has an active subscription. Designed for 3rd-party subscription managers to confirm presence before attempting to bill or before submitting a new external subscription order.</p>\n<p>Accepts either an <code>order_id</code> (resolved up to the customer) or a <code>customer_id</code> directly. Exactly one of the two must be provided.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:subscriptions.check_status</code> (or the legacy <code>api:view_any</code> ability)</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>order_id</td>\n<td><em>string (required without customer_id)</em><br />The customer's order number (e.g. <code>ORD-251104-0001</code>). The endpoint resolves the order to its customer and then checks for active subscriptions on that customer.</td>\n</tr>\n<tr>\n<td>customer_id</td>\n<td><em>string (required without order_id)</em><br />The customer number (e.g. <code>CUST-251104-0001</code>).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>A customer can have multiple active subscriptions. The response always returns the full list, plus a <code>subscription_number</code> convenience field for callers that only care about the most recent one.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>active</td>\n<td><strong>boolean</strong><br />True when the customer has at least one subscription in an active status (active, trial, etc). False if the customer or order does not exist, or no active subscription is found.</td>\n</tr>\n<tr>\n<td>active_count</td>\n<td><strong>integer</strong><br />Total number of active subscriptions for this customer. <code>0</code> when none exist.</td>\n</tr>\n<tr>\n<td>customer_number</td>\n<td><strong>string|null</strong><br />Public-facing customer number (e.g. <code>CUST-251104-0001</code>) resolved from the order or customer lookup. Null when the lookup found no matching customer/order.</td>\n</tr>\n<tr>\n<td>subscription_numbers</td>\n<td><strong>string[]</strong><br />Public-facing subscription numbers (e.g. <code>[\"SUB-251104-0001\", \"SUB-251104-0007\"]</code>) for <strong>every</strong> active subscription on the customer, ordered most-recent first. Empty array when none exist.</td>\n</tr>\n<tr>\n<td>subscription_number</td>\n<td><strong>string|null</strong><br />Convenience pointer to the most recent active subscription number. Equivalent to <code>subscription_numbers[0]</code>. Null when none exist. Use <code>subscription_numbers</code> when you need to reason about all active subscriptions.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example-responses\">Example Responses</h2>\n<p><strong>Single active subscription</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"active\": true,\n    \"active_count\": 1,\n    \"customer_number\": \"CUST-251104-0001\",\n    \"subscription_numbers\": [\"SUB-251104-0001\"],\n    \"subscription_number\": \"SUB-251104-0001\"\n}\n</code></pre>\n<p><strong>Multiple active subscriptions</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"active\": true,\n    \"active_count\": 2,\n    \"customer_number\": \"CUST-251104-0001\",\n    \"subscription_numbers\": [\"SUB-251104-0007\", \"SUB-251104-0001\"],\n    \"subscription_number\": \"SUB-251104-0007\"\n}\n</code></pre>\n<p><strong>Customer or order not found / no active subscription</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"active\": false,\n    \"active_count\": 0,\n    \"customer_number\": null,\n    \"subscription_numbers\": [],\n    \"subscription_number\": null\n}\n</code></pre>\n<h2 id=\"notes\">Notes</h2>\n<ul>\n<li>Subscriptions are filtered by the team's active-status set, so paused/canceled/failed subscriptions never count as \"active\".</li>\n<li>When an order is provided, the endpoint resolves to the customer and returns <strong>all</strong> of that customer's active subscriptions — not just the one tied to the order. Use <code>subscription_numbers</code> if you need to disambiguate.</li>\n<li>Returns <code>200 OK</code> even when nothing is found; a 4xx is only returned for auth/validation failures.</li>\n<li>Response identifiers are public-facing numbers, not internal database IDs.</li>\n</ul>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","subscriptions","check-status"],"host":["api","sparkcrm","io"],"query":[{"description":{"content":"<p>Order number to resolve up to the customer. Use either order_id or customer_id (one is required).</p>\n","type":"text/plain"},"key":"order_id","value":"ORD-251104-0001"},{"disabled":true,"description":{"content":"<p>Customer number to look up directly. Use either order_id or customer_id (one is required).</p>\n","type":"text/plain"},"key":"customer_id","value":"CUST-251104-0001"}],"variable":[]}},"response":[],"_postman_id":"4be79cf8-b036-544a-656d-80339cda6205"},{"name":"Process Subscription","id":"1bf6ff3f-bd37-c9c6-5b24-736a89857215","request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"type":"text","key":"subscription_id","value":"SUB-251104-0001","description":"<p>Subscription number or UUID to bill now</p>\n"},{"key":"gateway_id","type":"text","value":"12","description":"<p>Override the configured gateway</p>\n","disabled":true},{"key":"payment_orchestrator_id","type":"text","value":"3","description":"<p>Override the configured payment orchestrator</p>\n","disabled":true},{"key":"price","type":"text","value":"29.99","description":"<p>Override the recurring price for this billing only</p>\n","disabled":true},{"key":"payment[card][number]","type":"text","value":"4111111111111111","description":"<p>Override the on-file card with a new card for this billing</p>\n","disabled":true},{"key":"payment[card][exp_month]","type":"text","value":"12","description":"<p>Required when payment[card][number] is provided</p>\n","disabled":true},{"key":"payment[card][exp_year]","type":"text","value":"2030","description":"<p>Required when payment[card][number] is provided</p>\n","disabled":true},{"key":"payment[card][cvv]","type":"text","value":"123","description":"<p>Optional CVV for the override card</p>\n","disabled":true},{"type":"text","key":"billing_address[first_name]","value":"George","disabled":true},{"type":"text","key":"billing_address[last_name]","value":"Foreman","disabled":true},{"type":"text","key":"billing_address[address1]","value":"123 Main St","disabled":true},{"type":"text","key":"billing_address[city]","value":"Los Angeles","disabled":true},{"type":"text","key":"billing_address[state]","value":"CA","disabled":true},{"type":"text","key":"billing_address[zip]","value":"90001","disabled":true},{"type":"text","key":"billing_address[country]","value":"US","disabled":true}]},"url":"https://api.sparkcrm.io/checkout/subscriptions/process","description":"<h1 id=\"process-subscription\">Process Subscription</h1>\n<p>Trigger an immediate billing run on an existing subscription, optionally overriding the gateway, payment orchestrator, price, payment card, or billing address for this billing only. Lets a 3rd-party subscription manager bill on their own schedule, overriding the platform's scheduling for that subscription.</p>\n<p>The subscription must be in an <code>active</code> or <code>trial</code> status; canceled/paused/failed subscriptions are rejected.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token with permission: <code>api:subscriptions.process</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>subscription_id</td>\n<td><strong>string (required)</strong><br />Subscription number (e.g. <code>SUB-251104-0001</code>) or UUID identifying the subscription to bill.</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em>integer (optional)</em><br />Override the gateway configured on the subscription. Must be a gateway owned by the requesting team.</td>\n</tr>\n<tr>\n<td>payment_orchestrator_id</td>\n<td><em>integer (optional)</em><br />Override the payment orchestrator configured on the subscription. Must belong to the requesting team.</td>\n</tr>\n<tr>\n<td>price</td>\n<td><em>numeric (optional)</em><br />Override the price charged for this billing only. Minimum: 0.01. The subscription's recurring price is <strong>not</strong> changed for future cycles.</td>\n</tr>\n<tr>\n<td>payment[card][number]</td>\n<td><em>string (optional)</em><br />Override the customer's on-file card with a new card for this billing. Length: 13–19 digits.</td>\n</tr>\n<tr>\n<td>payment[card][exp_month]</td>\n<td><strong>integer (required with card.number)</strong><br />Card expiration month, 1–12.</td>\n</tr>\n<tr>\n<td>payment[card][exp_year]</td>\n<td><strong>integer (required with card.number)</strong><br />Card expiration year (4-digit), must be ≥ current year.</td>\n</tr>\n<tr>\n<td>payment[card][cvv]</td>\n<td><em>string (optional)</em><br />Card CVV. Length: 3–4 characters.</td>\n</tr>\n<tr>\n<td>billing_address[first_name]</td>\n<td><em>string (optional)</em><br />Billing first name override.</td>\n</tr>\n<tr>\n<td>billing_address[last_name]</td>\n<td><em>string (optional)</em><br />Billing last name override.</td>\n</tr>\n<tr>\n<td>billing_address[address1]</td>\n<td><em>string (optional)</em><br />Billing street address.</td>\n</tr>\n<tr>\n<td>billing_address[city]</td>\n<td><em>string (optional)</em><br />Billing city.</td>\n</tr>\n<tr>\n<td>billing_address[state]</td>\n<td><em>string (optional)</em><br />Billing state/province.</td>\n</tr>\n<tr>\n<td>billing_address[zip]</td>\n<td><em>string (optional)</em><br />Billing postal code.</td>\n</tr>\n<tr>\n<td>billing_address[country]</td>\n<td><em>string (optional)</em><br />Two-letter ISO 3166-1 country code.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p><strong>On success (<code>200 OK</code>)</strong></p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br /><code>true</code> when the subscription billing produced a transaction.</td>\n</tr>\n<tr>\n<td>transaction_number</td>\n<td><strong>string</strong><br />Public-facing transaction number (e.g. <code>TXN-251104-0001</code>) of the transaction that was created.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>On non-billable result (<code>422 Unprocessable Entity</code>)</strong></p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong><br /><code>false</code></td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong><br />Reason no transaction was produced (e.g. order flagged for QA).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Error Code</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>401 / 403</td>\n<td>Missing or insufficient API permissions.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Subscription not found, not owned by the team, or not in an <code>active</code>/<code>trial</code> status.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation failure on the request, or processor returned no transaction (e.g. QA hold).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"notes\">Notes</h2>\n<ul>\n<li>Overrides apply to <strong>this billing only</strong>. The subscription record itself is not modified — its stored gateway, orchestrator, price, and payment method remain unchanged for the next scheduled cycle.</li>\n<li>When <code>payment[card][number]</code> is provided, it is used in place of the customer's on-file payment method for this charge.</li>\n<li>Useful for the 3rd-party subscription manager flow: external systems call this endpoint to bill on their own schedule rather than waiting for the platform's scheduler.</li>\n<li>Response identifiers are public-facing numbers, not internal database IDs.</li>\n</ul>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["checkout","subscriptions","process"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"1bf6ff3f-bd37-c9c6-5b24-736a89857215"}],"id":"404e1fdc-57bc-72a8-6abf-5399fddb2422","_postman_id":"404e1fdc-57bc-72a8-6abf-5399fddb2422","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}}],"id":"48dab617-bbea-4d67-bd3d-d944ccde99c8","description":"<p>This simplified API streamlines the checkout process for developers. Designed with ease of use in mind, Spark CRM API reduces complexity and allows you to implement checkout functionality with minimal code requirements. The streamlined interface focuses on essential operations, making integration straightforward while maintaining robust functionality.</p>\n<p><a href=\"https://app.sparkcrm.io/onboarding\">Register for a Spark CRM account to get started</a></p>\n<h2 id=\"api-authentication\">API Authentication</h2>\n<h3 id=\"getting-your-api-key\">Getting Your API Key</h3>\n<ol>\n<li><p>Login to your Spark Account</p>\n</li>\n<li><p>Navigate to Settings &gt; API Keys</p>\n</li>\n<li><p>Click \"Generate API Key\"</p>\n</li>\n<li><p>Copy your newly generated API key</p>\n</li>\n<li><p>Store this key securely - it will only be shown once</p>\n</li>\n</ol>\n<h3 id=\"using-your-api-key\">Using Your API Key</h3>\n<p>Include your API key in all requests as a Bearer token in the Authorization header:</p>\n<p><code>Authorization: Bearer YOUR_API_KEY_HERE</code></p>\n<p>All authenticated endpoints require this header to be present with a valid API key.</p>\n<h3 id=\"content-type-and-accept-headers\">Content-Type And Accept Headers</h3>\n<p>This is a JSON API and requires proper headers for all requests:</p>\n<ul>\n<li><p>All requests must include <code>Content-Type: application/json</code></p>\n</li>\n<li><p>All requests must include <code>Accept: application/json</code></p>\n</li>\n</ul>\n<p>If these headers are not included, the API will return a 400 Bad Request response with an error message indicating which header is missing or incorrect, such as \"Content-Type must be application/json\" or \"Accept must be application/json\".</p>\n<h3 id=\"rate-and-usage-limits\">Rate and Usage Limits</h3>\n<p>To ensure system stability and fair usage, API requests are subject to the below rate limiting per account:</p>\n<ul>\n<li><p>100 requests per minute is default</p>\n</li>\n<li><p>Enterprise accounts can be set to custom rate limits (e.g. 1,000 requests per minute and beyond). To increase rate limits please email <a href=\"https://mailto:hello@sparkcrm.io\">hello@sparkcrm.io</a>.</p>\n</li>\n</ul>\n<p>When a rate limit is exceeded, the API will return a 429 Too Many Requests response with the following headers:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Header</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>X-RateLimit-Limit</td>\n<td>The maximum number of requests that the consumer is permitted to make per minute. Default to 100 requests per minute. Please contact support if you need a higher quota.</td>\n</tr>\n<tr>\n<td>X-RateLimit-Remaining</td>\n<td>The number of requests remaining in the current rate limit window.</td>\n</tr>\n<tr>\n<td>X-RateLimit-Reset</td>\n<td>The time in milliseconds until the current window resets.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<p>Spark CRM uses conventional HTTP response codes to indicate the success or failure of an API request. In general:</p>\n<ul>\n<li><p>Codes in the <code>2xx</code> range indicate success</p>\n</li>\n<li><p>Codes in the <code>4xx</code> range indicate an error that failed given the information provided (e.g., a required parameter was omitted, invalid object passed, etc.)</p>\n</li>\n<li><p>Codes in the <code>5xx</code> range indicate an error with Spark CRM's servers (these are rare)</p>\n</li>\n</ul>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>HTTP STATUS CODE</th>\n<th>SUMMARY</th>\n<th>DESCRIPTION</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>OK</td>\n<td>Everything worked as expected.</td>\n</tr>\n<tr>\n<td>201</td>\n<td>Created</td>\n<td>Resource was successfully created.</td>\n</tr>\n<tr>\n<td>400</td>\n<td>Bad Request</td>\n<td>The request was unacceptable, often due to missing a required parameter.</td>\n</tr>\n<tr>\n<td>401</td>\n<td>Unauthorized</td>\n<td>No valid API key provided.</td>\n</tr>\n<tr>\n<td>403</td>\n<td>Forbidden</td>\n<td>The API key doesn't have permissions to perform the request.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Not Found</td>\n<td>The requested resource doesn't exist.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation Error</td>\n<td>The request was well-formed but was unable to be followed due to validation errors.</td>\n</tr>\n<tr>\n<td>429</td>\n<td>Too Many Requests</td>\n<td>Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.</td>\n</tr>\n<tr>\n<td>500, 502, 503, 504</td>\n<td>Server Errors</td>\n<td>Something went wrong on Spark CRM's end. (These are rare.)</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"example-error-response\">Example Error Response</h3>\n<p>All <code>4xx</code> and <code>5xx</code> errors return an error message via the \"errors\" field.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{\n  \"success\": false,\n  \"message\": \"Validation error\",\n  \"errors\": {\n    \"customer.email\": [\n      \"The email field is required.\"\n    ],\n    \"shipping.address1\": [\n      \"The address1 field is required.\"\n    ]\n  }\n}\n\n</code></pre><h3 id=\"null-values\">Null Values</h3>\n<p>If there is no data for a response field, the API will use <code>null</code> for that field's value.</p>\n","_postman_id":"48dab617-bbea-4d67-bd3d-d944ccde99c8","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"REST API","item":[{"name":"Campaign","item":[{"name":"Offers","item":[{"name":"List Campaign Offers","id":"bd3276cb-2f1b-294f-9ca8-60752facd33b","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/offers","description":"<h1 id=\"list-campaign-offers\">List Campaign Offers</h1>\n<p><strong>Retrieve every offer attached to a campaign, ordered by display position.</strong></p>\n<p>Returns the full list of offers configured for a single campaign. Offers are the primary purchasable items of a campaign (the \"core\" products) and are always returned sorted by their <code>position</code> (ascending). This endpoint returns the summary shape of each offer; the <code>bundle_products</code> array is only included on the create and update endpoints (the detailed shape).</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.offers.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> Path parameter. The campaign's <code>internal_id</code> (the public id of the campaign, e.g. <code>123</code>). Must belong to the authenticated team or a <code>404 Campaign not found</code> is returned. Matches the pattern <code>[a-zA-Z0-9\\-_]+</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no query parameters or request body. Results are not paginated and are always ordered by <code>position</code> ascending.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> array. Each element is a campaign offer:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>The offer's <code>internal_id</code> (use this value as <code>{offer_id}</code> for update/delete).</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>The offer name.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td>Boolean. Whether the offer is active.</td>\n</tr>\n<tr>\n<td><code>position</code></td>\n<td>Integer display/sort order.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td>Decimal string with 2 places, e.g. <code>\"49.95\"</code>.</td>\n</tr>\n<tr>\n<td><code>shipping_price</code></td>\n<td>Decimal string with 2 places.</td>\n</tr>\n<tr>\n<td><code>tax_rate</code></td>\n<td>Decimal string with 2 places (percentage).</td>\n</tr>\n<tr>\n<td><code>is_tax_included</code></td>\n<td>Boolean. When <code>true</code>, <code>tax_rate</code> is treated as already baked into <code>price</code>.</td>\n</tr>\n<tr>\n<td><code>dynamic_descriptor</code></td>\n<td>The billing descriptor shown on the customer's statement, or <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>sale_type</code></td>\n<td>One of <code>none</code>, <code>standard</code>, <code>trial</code>, <code>installment</code>, <code>custom</code>, <code>third_party</code>, or <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>subscription_config</code></td>\n<td>Object/array of subscription settings, or <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>product_id</code></td>\n<td>The primary product's <code>internal_id</code> (the product charged as the single line item).</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td>ISO-8601 timestamp.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td>ISO-8601 timestamp.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:campaigns.offers.view</code> (or legacy <code>api:view_any</code>) permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>Campaign not found for this team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET /v1/campaigns/123/offers</code></p>\n<p>Returns the campaign's offers ordered by position.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","offers"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"15fe1305-5593-bafc-7c03-25515d819c90","name":"List Campaign Offers","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/offers","description":"# List Campaign Offers\n\n**Retrieve every offer attached to a campaign, ordered by display position.**\n\nReturns the full list of offers configured for a single campaign. Offers are the primary purchasable items of a campaign (the \"core\" products) and are always returned sorted by their `position` (ascending). This endpoint returns the summary shape of each offer; the `bundle_products` array is only included on the create and update endpoints (the detailed shape).\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.offers.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ Path parameter. The campaign's `internal_id` (the public id of the campaign, e.g. `123`). Must belong to the authenticated team or a `404 Campaign not found` is returned. Matches the pattern `[a-zA-Z0-9\\-_]+`. |\n\nThis endpoint takes no query parameters or request body. Results are not paginated and are always ordered by `position` ascending.\n\n## Response Object\n\nReturns `success: true` and a `data` array. Each element is a campaign offer:\n\n| Field | Description |\n| --- | --- |\n| `id` | The offer's `internal_id` (use this value as `{offer_id}` for update/delete). |\n| `name` | The offer name. |\n| `is_active` | Boolean. Whether the offer is active. |\n| `position` | Integer display/sort order. |\n| `price` | Decimal string with 2 places, e.g. `\"49.95\"`. |\n| `shipping_price` | Decimal string with 2 places. |\n| `tax_rate` | Decimal string with 2 places (percentage). |\n| `is_tax_included` | Boolean. When `true`, `tax_rate` is treated as already baked into `price`. |\n| `dynamic_descriptor` | The billing descriptor shown on the customer's statement, or `null`. |\n| `sale_type` | One of `none`, `standard`, `trial`, `installment`, `custom`, `third_party`, or `null`. |\n| `subscription_config` | Object/array of subscription settings, or `null`. |\n| `product_id` | The primary product's `internal_id` (the product charged as the single line item). |\n| `created_at` | ISO-8601 timestamp. |\n| `updated_at` | ISO-8601 timestamp. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:campaigns.offers.view` (or legacy `api:view_any`) permission. |\n| `404` | Campaign not found for this team. |\n\n## Example\n\n`GET /v1/campaigns/123/offers`\n\nReturns the campaign's offers ordered by position."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 4501,\n      \"name\": \"Premium Skin Cream - Buy 1\",\n      \"is_active\": true,\n      \"position\": 0,\n      \"price\": \"49.95\",\n      \"shipping_price\": \"5.99\",\n      \"tax_rate\": \"0.00\",\n      \"is_tax_included\": false,\n      \"dynamic_descriptor\": \"SPARK*SKINCARE\",\n      \"sale_type\": \"standard\",\n      \"subscription_config\": {\n        \"interval\": \"month\",\n        \"interval_count\": 1\n      },\n      \"product_id\": 781,\n      \"created_at\": \"2026-05-02T14:21:08.000000Z\",\n      \"updated_at\": \"2026-06-10T09:03:55.000000Z\"\n    },\n    {\n      \"id\": 4502,\n      \"name\": \"Premium Skin Cream - Buy 3 Bundle\",\n      \"is_active\": true,\n      \"position\": 1,\n      \"price\": \"119.95\",\n      \"shipping_price\": \"0.00\",\n      \"tax_rate\": \"7.50\",\n      \"is_tax_included\": false,\n      \"dynamic_descriptor\": \"SPARK*SKINCARE\",\n      \"sale_type\": \"none\",\n      \"subscription_config\": null,\n      \"product_id\": 781,\n      \"created_at\": \"2026-05-02T14:25:40.000000Z\",\n      \"updated_at\": \"2026-05-02T14:25:40.000000Z\"\n    }\n  ]\n}"}],"_postman_id":"bd3276cb-2f1b-294f-9ca8-60752facd33b"},{"name":"Create Campaign Offer","id":"5c72471c-6949-8345-49c0-d5e5cf221fe5","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"product_id\": 781,\n  \"name\": \"Premium Skin Cream - Buy 3 Bundle\",\n  \"is_active\": true,\n  \"position\": 1,\n  \"price\": 119.95,\n  \"shipping_price\": 0,\n  \"tax_rate\": 7.5,\n  \"is_tax_included\": false,\n  \"dynamic_descriptor\": \"SPARK*SKINCARE\",\n  \"sale_type\": \"standard\",\n  \"subscription_config\": {\n    \"interval\": \"month\",\n    \"interval_count\": 1\n  },\n  \"bundle_products\": [\n    {\n      \"product_id\": 781,\n      \"quantity\": 2,\n      \"position\": 0\n    },\n    {\n      \"product_id\": 802,\n      \"quantity\": 1,\n      \"position\": 1\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/offers","description":"<h1 id=\"create-campaign-offer\">Create Campaign Offer</h1>\n<p><strong>Add a new purchasable offer to a campaign, optionally as a multi-product bundle.</strong></p>\n<p>Creates an offer within the given campaign. An offer is charged as a single line item against its primary <code>product_id</code>, but you may optionally attach <code>bundle_products</code> - the set of underlying products that are actually shipped to fulfillment when the offer is purchased. Supplying more than one bundle product makes the offer a bundle. The response uses the detailed shape, so the persisted <code>bundle_products</code> are echoed back.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.offers.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>product_id</code></td>\n<td><em><strong>integer (required)</strong></em> The primary product's <code>internal_id</code>. Must reference a product owned by the authenticated team or a <code>422</code> is returned. This is the product charged as the single line item.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (required)</strong></em> Offer name. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the offer is active. Defaults to model default when omitted.</td>\n</tr>\n<tr>\n<td><code>position</code></td>\n<td><em><strong>integer (optional)</strong></em> Display/sort order. Minimum <code>0</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td><em><strong>numeric (required)</strong></em> Offer price. Minimum <code>0</code>. Stored with 2 decimal places.</td>\n</tr>\n<tr>\n<td><code>shipping_price</code></td>\n<td><em><strong>numeric (optional)</strong></em> Shipping charge. Minimum <code>0</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>tax_rate</code></td>\n<td><em><strong>numeric (optional)</strong></em> Tax rate as a percentage. Minimum <code>0</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>is_tax_included</code></td>\n<td><em><strong>boolean (optional)</strong></em> When <code>true</code>, tax is treated as already included in <code>price</code>.</td>\n</tr>\n<tr>\n<td><code>dynamic_descriptor</code></td>\n<td><em><strong>string (optional)</strong></em> Billing statement descriptor. Max 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><code>sale_type</code></td>\n<td><em><strong>string (optional)</strong></em> One of <code>none</code>, <code>standard</code>, <code>trial</code>, <code>installment</code>, <code>custom</code>, <code>third_party</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>subscription_config</code></td>\n<td><em><strong>array/object (optional)</strong></em> Free-form subscription configuration (stored as JSON). Nullable.</td>\n</tr>\n<tr>\n<td><code>bundle_products</code></td>\n<td><em><strong>array (optional)</strong></em> The products shipped for this offer. When provided, the set is synced to the offer. More than one entry marks the offer as a bundle. Nullable.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].product_id</code></td>\n<td><em><strong>integer (required with bundle_products)</strong></em> A product <code>internal_id</code> owned by the team. If any entry does not exist for the account, a <code>422</code> is returned.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].quantity</code></td>\n<td><em><strong>integer (optional)</strong></em> Quantity of this product in the bundle. Minimum <code>1</code>. Defaults to <code>1</code>.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].position</code></td>\n<td><em><strong>integer (optional)</strong></em> Sort order within the bundle. Minimum <code>0</code>. Defaults to <code>0</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code>, a <code>message</code> of <code>Offer created successfully</code>, and a <code>data</code> object using the detailed offer shape. In addition to the standard offer fields (see List Campaign Offers), the detailed shape includes a <code>bundle_products</code> array, each element containing <code>product_id</code> (the product's <code>internal_id</code>), <code>name</code>, <code>quantity</code>, and <code>position</code>.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:campaigns.offers.create</code> (or legacy <code>api:create</code>) permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>Campaign not found for this team.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error. Includes the case where <code>product_id</code> does not exist for the account (<code>The selected product does not exist for this account.</code>) or a <code>bundle_products</code> entry is invalid (<code>One or more bundle products do not exist for this account.</code>).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>POST /v1/campaigns/123/offers</code> with the request body above creates a bundle offer and returns the <code>201</code> payload shown in the response.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","offers"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"3e26cc43-1961-27a4-1bf7-e895033bbc3f","name":"Create Campaign Offer","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"product_id\": 781,\n  \"name\": \"Premium Skin Cream - Buy 3 Bundle\",\n  \"is_active\": true,\n  \"position\": 1,\n  \"price\": 119.95,\n  \"shipping_price\": 0,\n  \"tax_rate\": 7.5,\n  \"is_tax_included\": false,\n  \"dynamic_descriptor\": \"SPARK*SKINCARE\",\n  \"sale_type\": \"standard\",\n  \"subscription_config\": {\n    \"interval\": \"month\",\n    \"interval_count\": 1\n  },\n  \"bundle_products\": [\n    {\n      \"product_id\": 781,\n      \"quantity\": 2,\n      \"position\": 0\n    },\n    {\n      \"product_id\": 802,\n      \"quantity\": 1,\n      \"position\": 1\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/offers","description":"# Create Campaign Offer\n\n**Add a new purchasable offer to a campaign, optionally as a multi-product bundle.**\n\nCreates an offer within the given campaign. An offer is charged as a single line item against its primary `product_id`, but you may optionally attach `bundle_products` - the set of underlying products that are actually shipped to fulfillment when the offer is purchased. Supplying more than one bundle product makes the offer a bundle. The response uses the detailed shape, so the persisted `bundle_products` are echoed back.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.offers.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| `product_id` | _**integer (required)**_ The primary product's `internal_id`. Must reference a product owned by the authenticated team or a `422` is returned. This is the product charged as the single line item. |\n| `name` | _**string (required)**_ Offer name. Max 255 characters. |\n| `is_active` | _**boolean (optional)**_ Whether the offer is active. Defaults to model default when omitted. |\n| `position` | _**integer (optional)**_ Display/sort order. Minimum `0`. Nullable. |\n| `price` | _**numeric (required)**_ Offer price. Minimum `0`. Stored with 2 decimal places. |\n| `shipping_price` | _**numeric (optional)**_ Shipping charge. Minimum `0`. Nullable. |\n| `tax_rate` | _**numeric (optional)**_ Tax rate as a percentage. Minimum `0`. Nullable. |\n| `is_tax_included` | _**boolean (optional)**_ When `true`, tax is treated as already included in `price`. |\n| `dynamic_descriptor` | _**string (optional)**_ Billing statement descriptor. Max 255 characters. Nullable. |\n| `sale_type` | _**string (optional)**_ One of `none`, `standard`, `trial`, `installment`, `custom`, `third_party`. Nullable. |\n| `subscription_config` | _**array/object (optional)**_ Free-form subscription configuration (stored as JSON). Nullable. |\n| `bundle_products` | _**array (optional)**_ The products shipped for this offer. When provided, the set is synced to the offer. More than one entry marks the offer as a bundle. Nullable. |\n| `bundle_products[].product_id` | _**integer (required with bundle_products)**_ A product `internal_id` owned by the team. If any entry does not exist for the account, a `422` is returned. |\n| `bundle_products[].quantity` | _**integer (optional)**_ Quantity of this product in the bundle. Minimum `1`. Defaults to `1`. |\n| `bundle_products[].position` | _**integer (optional)**_ Sort order within the bundle. Minimum `0`. Defaults to `0`. |\n\n## Response Object\n\nReturns `success: true`, a `message` of `Offer created successfully`, and a `data` object using the detailed offer shape. In addition to the standard offer fields (see List Campaign Offers), the detailed shape includes a `bundle_products` array, each element containing `product_id` (the product's `internal_id`), `name`, `quantity`, and `position`.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:campaigns.offers.create` (or legacy `api:create`) permission. |\n| `404` | Campaign not found for this team. |\n| `422` | Validation error. Includes the case where `product_id` does not exist for the account (`The selected product does not exist for this account.`) or a `bundle_products` entry is invalid (`One or more bundle products do not exist for this account.`). |\n\n## Example\n\n`POST /v1/campaigns/123/offers` with the request body above creates a bundle offer and returns the `201` payload shown in the response."},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Offer created successfully\",\n  \"data\": {\n    \"id\": 4502,\n    \"name\": \"Premium Skin Cream - Buy 3 Bundle\",\n    \"is_active\": true,\n    \"position\": 1,\n    \"price\": \"119.95\",\n    \"shipping_price\": \"0.00\",\n    \"tax_rate\": \"7.50\",\n    \"is_tax_included\": false,\n    \"dynamic_descriptor\": \"SPARK*SKINCARE\",\n    \"sale_type\": \"standard\",\n    \"subscription_config\": {\n      \"interval\": \"month\",\n      \"interval_count\": 1\n    },\n    \"product_id\": 781,\n    \"created_at\": \"2026-06-16T16:42:11.000000Z\",\n    \"updated_at\": \"2026-06-16T16:42:11.000000Z\",\n    \"bundle_products\": [\n      {\n        \"product_id\": 781,\n        \"name\": \"Premium Skin Cream 1oz\",\n        \"quantity\": 2,\n        \"position\": 0\n      },\n      {\n        \"product_id\": 802,\n        \"name\": \"Travel Pouch\",\n        \"quantity\": 1,\n        \"position\": 1\n      }\n    ]\n  }\n}"}],"_postman_id":"5c72471c-6949-8345-49c0-d5e5cf221fe5"},{"name":"Update Campaign Offer","id":"149745a6-b8dc-69e0-5689-89ec46ca00f7","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Premium Skin Cream - Buy 3 Bundle (Updated)\",\n  \"price\": 109.95,\n  \"is_active\": false,\n  \"bundle_products\": [\n    {\n      \"product_id\": 781,\n      \"quantity\": 3,\n      \"position\": 0\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/offers/4502","description":"<h1 id=\"update-campaign-offer\">Update Campaign Offer</h1>\n<p><strong>Update an existing campaign offer; all fields are optional (partial update).</strong></p>\n<p>Updates a single offer within a campaign, identified by its <code>internal_id</code> in the path. This is a PATCH, so every field is optional - only the fields you send are validated and changed. If <code>bundle_products</code> is included it fully replaces (syncs) the offer's existing bundle set; omit it to leave the current bundle untouched.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.offers.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional. A field is only validated when present (<code>sometimes</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>product_id</code></td>\n<td><em><strong>integer (optional)</strong></em> The primary product's <code>internal_id</code>. When sent it must reference a product owned by the team or a <code>422</code> is returned.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (optional)</strong></em> Offer name. Max 255 characters. Required if the key is present.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the offer is active.</td>\n</tr>\n<tr>\n<td><code>position</code></td>\n<td><em><strong>integer (optional)</strong></em> Display/sort order. Minimum <code>0</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td><em><strong>numeric (optional)</strong></em> Offer price. Minimum <code>0</code>. Required if the key is present.</td>\n</tr>\n<tr>\n<td><code>shipping_price</code></td>\n<td><em><strong>numeric (optional)</strong></em> Shipping charge. Minimum <code>0</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>tax_rate</code></td>\n<td><em><strong>numeric (optional)</strong></em> Tax rate percentage. Minimum <code>0</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>is_tax_included</code></td>\n<td><em><strong>boolean (optional)</strong></em> When <code>true</code>, tax is treated as included in <code>price</code>.</td>\n</tr>\n<tr>\n<td><code>dynamic_descriptor</code></td>\n<td><em><strong>string (optional)</strong></em> Billing statement descriptor. Max 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><code>sale_type</code></td>\n<td><em><strong>string (optional)</strong></em> One of <code>none</code>, <code>standard</code>, <code>trial</code>, <code>installment</code>, <code>custom</code>, <code>third_party</code>.</td>\n</tr>\n<tr>\n<td><code>subscription_config</code></td>\n<td><em><strong>array/object (optional)</strong></em> Subscription configuration JSON. Nullable.</td>\n</tr>\n<tr>\n<td><code>bundle_products</code></td>\n<td><em><strong>array (optional)</strong></em> When present, fully replaces (syncs) the offer's shipped-product set. Omit to leave the existing bundle unchanged. Nullable.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].product_id</code></td>\n<td><em><strong>integer (required with bundle_products)</strong></em> A product <code>internal_id</code> owned by the team.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].quantity</code></td>\n<td><em><strong>integer (optional)</strong></em> Quantity in the bundle. Minimum <code>1</code>. Defaults to <code>1</code>.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].position</code></td>\n<td><em><strong>integer (optional)</strong></em> Sort order within the bundle. Minimum <code>0</code>. Defaults to <code>0</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Path Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> The campaign's <code>internal_id</code>.</td>\n</tr>\n<tr>\n<td><code>offer_id</code></td>\n<td><em><strong>integer (required)</strong></em> The offer's <code>internal_id</code> (numeric, the <code>id</code> returned by the list endpoint).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code>, a <code>message</code> of <code>Offer updated successfully</code>, and a <code>data</code> object in the detailed offer shape, including the <code>bundle_products</code> array (each entry with <code>product_id</code>, <code>name</code>, <code>quantity</code>, <code>position</code>).</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:campaigns.offers.update</code> (or legacy <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>Campaign not found, or offer not found within the campaign.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error, including an unknown <code>product_id</code> or invalid <code>bundle_products</code> entry for the account.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>PATCH /v1/campaigns/123/offers/4502</code> with a partial body updates only the supplied fields and re-syncs the bundle when <code>bundle_products</code> is present.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","offers","4502"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"28ff417e-0f07-5306-457b-1c1c7c337281","name":"Update Campaign Offer","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Premium Skin Cream - Buy 3 Bundle (Updated)\",\n  \"price\": 109.95,\n  \"is_active\": false,\n  \"bundle_products\": [\n    {\n      \"product_id\": 781,\n      \"quantity\": 3,\n      \"position\": 0\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/offers/4502","description":"# Update Campaign Offer\n\n**Update an existing campaign offer; all fields are optional (partial update).**\n\nUpdates a single offer within a campaign, identified by its `internal_id` in the path. This is a PATCH, so every field is optional - only the fields you send are validated and changed. If `bundle_products` is included it fully replaces (syncs) the offer's existing bundle set; omit it to leave the current bundle untouched.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.offers.update`\n\n## Request Body\n\nAll fields are optional. A field is only validated when present (`sometimes`).\n\n| Request Field | Description |\n| --- | --- |\n| `product_id` | _**integer (optional)**_ The primary product's `internal_id`. When sent it must reference a product owned by the team or a `422` is returned. |\n| `name` | _**string (optional)**_ Offer name. Max 255 characters. Required if the key is present. |\n| `is_active` | _**boolean (optional)**_ Whether the offer is active. |\n| `position` | _**integer (optional)**_ Display/sort order. Minimum `0`. Nullable. |\n| `price` | _**numeric (optional)**_ Offer price. Minimum `0`. Required if the key is present. |\n| `shipping_price` | _**numeric (optional)**_ Shipping charge. Minimum `0`. Nullable. |\n| `tax_rate` | _**numeric (optional)**_ Tax rate percentage. Minimum `0`. Nullable. |\n| `is_tax_included` | _**boolean (optional)**_ When `true`, tax is treated as included in `price`. |\n| `dynamic_descriptor` | _**string (optional)**_ Billing statement descriptor. Max 255 characters. Nullable. |\n| `sale_type` | _**string (optional)**_ One of `none`, `standard`, `trial`, `installment`, `custom`, `third_party`. |\n| `subscription_config` | _**array/object (optional)**_ Subscription configuration JSON. Nullable. |\n| `bundle_products` | _**array (optional)**_ When present, fully replaces (syncs) the offer's shipped-product set. Omit to leave the existing bundle unchanged. Nullable. |\n| `bundle_products[].product_id` | _**integer (required with bundle_products)**_ A product `internal_id` owned by the team. |\n| `bundle_products[].quantity` | _**integer (optional)**_ Quantity in the bundle. Minimum `1`. Defaults to `1`. |\n| `bundle_products[].position` | _**integer (optional)**_ Sort order within the bundle. Minimum `0`. Defaults to `0`. |\n\n## Request Object\n\n| Path Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ The campaign's `internal_id`. |\n| `offer_id` | _**integer (required)**_ The offer's `internal_id` (numeric, the `id` returned by the list endpoint). |\n\n## Response Object\n\nReturns `success: true`, a `message` of `Offer updated successfully`, and a `data` object in the detailed offer shape, including the `bundle_products` array (each entry with `product_id`, `name`, `quantity`, `position`).\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:campaigns.offers.update` (or legacy `api:update`) permission. |\n| `404` | Campaign not found, or offer not found within the campaign. |\n| `422` | Validation error, including an unknown `product_id` or invalid `bundle_products` entry for the account. |\n\n## Example\n\n`PATCH /v1/campaigns/123/offers/4502` with a partial body updates only the supplied fields and re-syncs the bundle when `bundle_products` is present."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Offer updated successfully\",\n  \"data\": {\n    \"id\": 4502,\n    \"name\": \"Premium Skin Cream - Buy 3 Bundle (Updated)\",\n    \"is_active\": false,\n    \"position\": 1,\n    \"price\": \"109.95\",\n    \"shipping_price\": \"0.00\",\n    \"tax_rate\": \"7.50\",\n    \"is_tax_included\": false,\n    \"dynamic_descriptor\": \"SPARK*SKINCARE\",\n    \"sale_type\": \"standard\",\n    \"subscription_config\": {\n      \"interval\": \"month\",\n      \"interval_count\": 1\n    },\n    \"product_id\": 781,\n    \"created_at\": \"2026-05-02T14:25:40.000000Z\",\n    \"updated_at\": \"2026-06-16T16:55:02.000000Z\",\n    \"bundle_products\": [\n      {\n        \"product_id\": 781,\n        \"name\": \"Premium Skin Cream 1oz\",\n        \"quantity\": 3,\n        \"position\": 0\n      }\n    ]\n  }\n}"}],"_postman_id":"149745a6-b8dc-69e0-5689-89ec46ca00f7"},{"name":"Delete Campaign Offer","id":"4191089a-4cec-2287-b0a3-ac8f9a1918b5","request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/offers/4502","description":"<h1 id=\"delete-campaign-offer\">Delete Campaign Offer</h1>\n<p><strong>Soft-delete an offer from a campaign.</strong></p>\n<p>Removes an offer from the given campaign. The offer is soft-deleted (the underlying model uses soft deletes), so it is hidden from listings but retained in the database. The campaign and offer must both belong to the authenticated team.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.offers.delete</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Path Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> The campaign's <code>internal_id</code> (e.g. <code>123</code>).</td>\n</tr>\n<tr>\n<td><code>offer_id</code></td>\n<td><em><strong>integer (required)</strong></em> The offer's <code>internal_id</code> (numeric, the <code>id</code> returned by the list endpoint).</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no request body.</p>\n<h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code> with a <code>message</code> of <code>Offer deleted successfully</code>.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:campaigns.offers.delete</code> (or legacy <code>api:delete</code>) permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>Campaign not found, or offer not found within the campaign.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>DELETE /v1/campaigns/123/offers/4502</code> soft-deletes the offer and returns the success message.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","offers","4502"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"89248aa9-a438-d639-8b02-890ff7e2ad19","name":"Delete Campaign Offer","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/offers/4502","description":"# Delete Campaign Offer\n\n**Soft-delete an offer from a campaign.**\n\nRemoves an offer from the given campaign. The offer is soft-deleted (the underlying model uses soft deletes), so it is hidden from listings but retained in the database. The campaign and offer must both belong to the authenticated team.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.offers.delete`\n\n## Request Object\n\n| Path Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ The campaign's `internal_id` (e.g. `123`). |\n| `offer_id` | _**integer (required)**_ The offer's `internal_id` (numeric, the `id` returned by the list endpoint). |\n\nThis endpoint takes no request body.\n\n## Response\n\nReturns `success: true` with a `message` of `Offer deleted successfully`.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:campaigns.offers.delete` (or legacy `api:delete`) permission. |\n| `404` | Campaign not found, or offer not found within the campaign. |\n\n## Example\n\n`DELETE /v1/campaigns/123/offers/4502` soft-deletes the offer and returns the success message."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Offer deleted successfully\"\n}"}],"_postman_id":"4191089a-4cec-2287-b0a3-ac8f9a1918b5"}],"id":"f43e0146-b39d-bc73-230d-cb43e3c7d83a","_postman_id":"f43e0146-b39d-bc73-230d-cb43e3c7d83a","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Upsells","item":[{"name":"List Campaign Upsells","id":"0e92583f-65f7-e59c-9e76-50bfad4ba367","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/upsells","description":"<h1 id=\"list-campaign-upsells\">List Campaign Upsells</h1>\n<p><strong>Returns every upsell assigned to a campaign, ordered by display position.</strong></p>\n<p>Retrieves the full list of upsells configured on a single campaign. Upsells are post-purchase offers presented after the core sale; each one references a primary product and may bundle multiple shippable products. Results are scoped to your team and sorted ascending by <code>position</code>.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.upsells.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> Path parameter. The campaign's <code>internal_id</code> (the public id returned by the campaigns endpoints, e.g. <code>123</code>). Matched against <code>[a-zA-Z0-9\\-_]+</code>. The campaign must belong to your team.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no query parameters. It always returns the complete, unpaginated set of upsells for the campaign.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> array. Each element is the <strong>base</strong> upsell representation:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>Integer. The upsell <code>internal_id</code> (use this value as <code>{upsell_id}</code> for update/delete).</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>String. Upsell display name.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td>Boolean. Whether the upsell is enabled.</td>\n</tr>\n<tr>\n<td><code>position</code></td>\n<td>Integer. Sort order within the campaign.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td>String (decimal, 2 dp). The price charged for the upsell.</td>\n</tr>\n<tr>\n<td><code>shipping_price</code></td>\n<td>String (decimal, 2 dp). Shipping charged on the upsell.</td>\n</tr>\n<tr>\n<td><code>tax_rate</code></td>\n<td>String (decimal, 2 dp). Tax rate percentage.</td>\n</tr>\n<tr>\n<td><code>is_tax_included</code></td>\n<td>Boolean. Whether tax is already included in <code>price</code>.</td>\n</tr>\n<tr>\n<td><code>allow_duplicates</code></td>\n<td>Boolean. Whether the same upsell may be taken more than once.</td>\n</tr>\n<tr>\n<td><code>dynamic_descriptor</code></td>\n<td>String or null. Optional billing descriptor override.</td>\n</tr>\n<tr>\n<td><code>sale_type</code></td>\n<td>String or null. One of <code>none</code>, <code>standard</code>, <code>trial</code>, <code>installment</code>, <code>custom</code>, <code>third_party</code>.</td>\n</tr>\n<tr>\n<td><code>subscription_config</code></td>\n<td>Object or null. Subscription configuration payload.</td>\n</tr>\n<tr>\n<td><code>product_id</code></td>\n<td>Integer. The primary product's <code>internal_id</code>.</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td>ISO-8601 timestamp.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td>ISO-8601 timestamp.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Note: gateway / payment router / bundle fields are only returned by the create and update endpoints (the detailed representation), not by this list.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:campaigns.upsells.view</code> permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found for this team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET /v1/campaigns/123/upsells</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","upsells"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"b578b2d0-2e64-2505-9ed4-bfe6e4749223","name":"List Campaign Upsells","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/upsells","description":"# List Campaign Upsells\n\n**Returns every upsell assigned to a campaign, ordered by display position.**\n\nRetrieves the full list of upsells configured on a single campaign. Upsells are post-purchase offers presented after the core sale; each one references a primary product and may bundle multiple shippable products. Results are scoped to your team and sorted ascending by `position`.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.upsells.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ Path parameter. The campaign's `internal_id` (the public id returned by the campaigns endpoints, e.g. `123`). Matched against `[a-zA-Z0-9\\-_]+`. The campaign must belong to your team. |\n\nThis endpoint takes no query parameters. It always returns the complete, unpaginated set of upsells for the campaign.\n\n## Response Object\n\nReturns `success: true` and a `data` array. Each element is the **base** upsell representation:\n\n| Field | Description |\n| --- | --- |\n| `id` | Integer. The upsell `internal_id` (use this value as `{upsell_id}` for update/delete). |\n| `name` | String. Upsell display name. |\n| `is_active` | Boolean. Whether the upsell is enabled. |\n| `position` | Integer. Sort order within the campaign. |\n| `price` | String (decimal, 2 dp). The price charged for the upsell. |\n| `shipping_price` | String (decimal, 2 dp). Shipping charged on the upsell. |\n| `tax_rate` | String (decimal, 2 dp). Tax rate percentage. |\n| `is_tax_included` | Boolean. Whether tax is already included in `price`. |\n| `allow_duplicates` | Boolean. Whether the same upsell may be taken more than once. |\n| `dynamic_descriptor` | String or null. Optional billing descriptor override. |\n| `sale_type` | String or null. One of `none`, `standard`, `trial`, `installment`, `custom`, `third_party`. |\n| `subscription_config` | Object or null. Subscription configuration payload. |\n| `product_id` | Integer. The primary product's `internal_id`. |\n| `created_at` | ISO-8601 timestamp. |\n| `updated_at` | ISO-8601 timestamp. |\n\nNote: gateway / payment router / bundle fields are only returned by the create and update endpoints (the detailed representation), not by this list.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:campaigns.upsells.view` permission. |\n| 404 | Campaign not found for this team. |\n\n## Example\n\n`GET /v1/campaigns/123/upsells`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 45,\n      \"name\": \"Premium Sleep Bundle\",\n      \"is_active\": true,\n      \"position\": 0,\n      \"price\": \"49.00\",\n      \"shipping_price\": \"5.95\",\n      \"tax_rate\": \"0.00\",\n      \"is_tax_included\": false,\n      \"allow_duplicates\": false,\n      \"dynamic_descriptor\": \"SLEEP UPSELL\",\n      \"sale_type\": \"standard\",\n      \"subscription_config\": {\n        \"interval\": \"month\",\n        \"interval_count\": 1\n      },\n      \"product_id\": 88,\n      \"created_at\": \"2026-06-10T14:22:05.000000Z\",\n      \"updated_at\": \"2026-06-12T09:01:44.000000Z\"\n    },\n    {\n      \"id\": 46,\n      \"name\": \"One-Time Add-On\",\n      \"is_active\": true,\n      \"position\": 1,\n      \"price\": \"19.99\",\n      \"shipping_price\": \"0.00\",\n      \"tax_rate\": \"0.00\",\n      \"is_tax_included\": true,\n      \"allow_duplicates\": true,\n      \"dynamic_descriptor\": null,\n      \"sale_type\": \"none\",\n      \"subscription_config\": null,\n      \"product_id\": 91,\n      \"created_at\": \"2026-06-11T17:40:12.000000Z\",\n      \"updated_at\": \"2026-06-11T17:40:12.000000Z\"\n    }\n  ]\n}"}],"_postman_id":"0e92583f-65f7-e59c-9e76-50bfad4ba367"},{"name":"Create Campaign Upsell","id":"49d017ed-bef2-d897-654f-d48639737038","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"product_id\": 88,\n  \"name\": \"Premium Sleep Bundle\",\n  \"is_active\": true,\n  \"position\": 0,\n  \"price\": 49.00,\n  \"shipping_price\": 5.95,\n  \"tax_rate\": 0,\n  \"is_tax_included\": false,\n  \"allow_duplicates\": false,\n  \"dynamic_descriptor\": \"SLEEP UPSELL\",\n  \"sale_type\": \"standard\",\n  \"subscription_config\": {\n    \"interval\": \"month\",\n    \"interval_count\": 1\n  },\n  \"use_offer_gateway\": false,\n  \"gateway_id\": 7,\n  \"payment_orchestrator_id\": 3,\n  \"bundle_products\": [\n    { \"product_id\": 88, \"quantity\": 1, \"position\": 0 },\n    { \"product_id\": 92, \"quantity\": 2, \"position\": 1 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/upsells","description":"<h1 id=\"create-campaign-upsell\">Create Campaign Upsell</h1>\n<p><strong>Adds a new post-purchase upsell to a campaign.</strong></p>\n<p>Creates an upsell on the given campaign. The upsell references a primary <code>product_id</code> (the single line that is charged) and may optionally define <code>bundle_products</code> (the underlying products sent to fulfillment when the upsell is taken). All product, gateway and payment-router ids are supplied as <strong>internal ids</strong> and are resolved to your team's records server-side.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.upsells.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>product_id</code></td>\n<td><em><strong>integer (required)</strong></em> The primary product's <code>internal_id</code>. Must exist for your team or a 422 is returned. This is the product that is charged as the upsell line.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (required)</strong></em> Upsell display name. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td><em><strong>numeric (required)</strong></em> Upsell price. Min 0.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the upsell is enabled. Defaults to nullable/unset on create.</td>\n</tr>\n<tr>\n<td><code>position</code></td>\n<td><em><strong>integer (optional)</strong></em> Sort order within the campaign. Min 0. Nullable.</td>\n</tr>\n<tr>\n<td><code>shipping_price</code></td>\n<td><em><strong>numeric (optional)</strong></em> Shipping charged on the upsell. Min 0. Nullable.</td>\n</tr>\n<tr>\n<td><code>tax_rate</code></td>\n<td><em><strong>numeric (optional)</strong></em> Tax rate percentage. Min 0. Nullable.</td>\n</tr>\n<tr>\n<td><code>is_tax_included</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether tax is already included in <code>price</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>allow_duplicates</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the customer may take this upsell more than once. Nullable.</td>\n</tr>\n<tr>\n<td><code>dynamic_descriptor</code></td>\n<td><em><strong>string (optional)</strong></em> Billing descriptor override. Max 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><code>sale_type</code></td>\n<td><em><strong>string (optional)</strong></em> Subscription/sale type. One of <code>none</code>, <code>standard</code>, <code>trial</code>, <code>installment</code>, <code>custom</code>, <code>third_party</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>subscription_config</code></td>\n<td><em><strong>array/object (optional)</strong></em> Subscription configuration payload (stored as JSON). Nullable.</td>\n</tr>\n<tr>\n<td><code>use_offer_gateway</code></td>\n<td><em><strong>boolean (optional)</strong></em> When true, the upsell is charged on the parent offer's gateway instead of its own <code>gateway_id</code>. Nullable.</td>\n</tr>\n<tr>\n<td><code>gateway_id</code></td>\n<td><em><strong>integer (optional)</strong></em> A gateway <code>internal_id</code> belonging to your team. Resolved server-side to the real gateway; if it does not exist for your account a 422 is returned. Nullable.</td>\n</tr>\n<tr>\n<td><code>payment_orchestrator_id</code></td>\n<td><em><strong>integer (optional)</strong></em> A payment router (orchestrator) <code>internal_id</code> belonging to your team. Resolved server-side; if it does not exist for your account a 422 is returned. Nullable.</td>\n</tr>\n<tr>\n<td><code>bundle_products</code></td>\n<td><em><strong>array (optional)</strong></em> The set of products shipped for this upsell. Provide more than one entry to make the upsell a bundle. Each <code>product_id</code> is an <code>internal_id</code> for your team. Nullable.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].product_id</code></td>\n<td><em><strong>integer (required with <code>bundle_products</code>)</strong></em> Product <code>internal_id</code> to include in the bundle. Must exist for your team or a 422 is returned.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].quantity</code></td>\n<td><em><strong>integer (optional)</strong></em> Quantity to ship. Min 1. Defaults to 1.</td>\n</tr>\n<tr>\n<td><code>bundle_products[].position</code></td>\n<td><em><strong>integer (optional)</strong></em> Sort order within the bundle. Min 0. Defaults to 0.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>201</code> with <code>success: true</code>, a <code>message</code>, and a <code>data</code> object using the <strong>detailed</strong> representation. In addition to the base fields it includes <code>use_offer_gateway</code>, <code>gateway_id</code> (resolved back to the gateway internal id), <code>payment_orchestrator_id</code> (resolved back to the router internal id), and a <code>bundle_products</code> array (<code>product_id</code>, <code>name</code>, <code>quantity</code>, <code>position</code>).</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>Validation error, or a referenced <code>product_id</code> / <code>gateway_id</code> / <code>payment_orchestrator_id</code> / bundle product does not exist for your account.</td>\n</tr>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:campaigns.upsells.create</code> permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found for this team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>POST /v1/campaigns/123/upsells</code> with the request body shown above.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","upsells"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"09bc5859-a59b-9aca-7a58-869b05ed6167","name":"Create Campaign Upsell","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"product_id\": 88,\n  \"name\": \"Premium Sleep Bundle\",\n  \"is_active\": true,\n  \"position\": 0,\n  \"price\": 49.00,\n  \"shipping_price\": 5.95,\n  \"tax_rate\": 0,\n  \"is_tax_included\": false,\n  \"allow_duplicates\": false,\n  \"dynamic_descriptor\": \"SLEEP UPSELL\",\n  \"sale_type\": \"standard\",\n  \"subscription_config\": {\n    \"interval\": \"month\",\n    \"interval_count\": 1\n  },\n  \"use_offer_gateway\": false,\n  \"gateway_id\": 7,\n  \"payment_orchestrator_id\": 3,\n  \"bundle_products\": [\n    { \"product_id\": 88, \"quantity\": 1, \"position\": 0 },\n    { \"product_id\": 92, \"quantity\": 2, \"position\": 1 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/upsells","description":"# Create Campaign Upsell\n\n**Adds a new post-purchase upsell to a campaign.**\n\nCreates an upsell on the given campaign. The upsell references a primary `product_id` (the single line that is charged) and may optionally define `bundle_products` (the underlying products sent to fulfillment when the upsell is taken). All product, gateway and payment-router ids are supplied as **internal ids** and are resolved to your team's records server-side.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.upsells.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| `product_id` | _**integer (required)**_ The primary product's `internal_id`. Must exist for your team or a 422 is returned. This is the product that is charged as the upsell line. |\n| `name` | _**string (required)**_ Upsell display name. Max 255 characters. |\n| `price` | _**numeric (required)**_ Upsell price. Min 0. |\n| `is_active` | _**boolean (optional)**_ Whether the upsell is enabled. Defaults to nullable/unset on create. |\n| `position` | _**integer (optional)**_ Sort order within the campaign. Min 0. Nullable. |\n| `shipping_price` | _**numeric (optional)**_ Shipping charged on the upsell. Min 0. Nullable. |\n| `tax_rate` | _**numeric (optional)**_ Tax rate percentage. Min 0. Nullable. |\n| `is_tax_included` | _**boolean (optional)**_ Whether tax is already included in `price`. Nullable. |\n| `allow_duplicates` | _**boolean (optional)**_ Whether the customer may take this upsell more than once. Nullable. |\n| `dynamic_descriptor` | _**string (optional)**_ Billing descriptor override. Max 255 characters. Nullable. |\n| `sale_type` | _**string (optional)**_ Subscription/sale type. One of `none`, `standard`, `trial`, `installment`, `custom`, `third_party`. Nullable. |\n| `subscription_config` | _**array/object (optional)**_ Subscription configuration payload (stored as JSON). Nullable. |\n| `use_offer_gateway` | _**boolean (optional)**_ When true, the upsell is charged on the parent offer's gateway instead of its own `gateway_id`. Nullable. |\n| `gateway_id` | _**integer (optional)**_ A gateway `internal_id` belonging to your team. Resolved server-side to the real gateway; if it does not exist for your account a 422 is returned. Nullable. |\n| `payment_orchestrator_id` | _**integer (optional)**_ A payment router (orchestrator) `internal_id` belonging to your team. Resolved server-side; if it does not exist for your account a 422 is returned. Nullable. |\n| `bundle_products` | _**array (optional)**_ The set of products shipped for this upsell. Provide more than one entry to make the upsell a bundle. Each `product_id` is an `internal_id` for your team. Nullable. |\n| `bundle_products[].product_id` | _**integer (required with `bundle_products`)**_ Product `internal_id` to include in the bundle. Must exist for your team or a 422 is returned. |\n| `bundle_products[].quantity` | _**integer (optional)**_ Quantity to ship. Min 1. Defaults to 1. |\n| `bundle_products[].position` | _**integer (optional)**_ Sort order within the bundle. Min 0. Defaults to 0. |\n\n## Response\n\nReturns `201` with `success: true`, a `message`, and a `data` object using the **detailed** representation. In addition to the base fields it includes `use_offer_gateway`, `gateway_id` (resolved back to the gateway internal id), `payment_orchestrator_id` (resolved back to the router internal id), and a `bundle_products` array (`product_id`, `name`, `quantity`, `position`).\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 422 | Validation error, or a referenced `product_id` / `gateway_id` / `payment_orchestrator_id` / bundle product does not exist for your account. |\n| 403 | Token lacks the `api:campaigns.upsells.create` permission. |\n| 404 | Campaign not found for this team. |\n\n## Example\n\n`POST /v1/campaigns/123/upsells` with the request body shown above."},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Upsell created successfully\",\n  \"data\": {\n    \"id\": 45,\n    \"name\": \"Premium Sleep Bundle\",\n    \"is_active\": true,\n    \"position\": 0,\n    \"price\": \"49.00\",\n    \"shipping_price\": \"5.95\",\n    \"tax_rate\": \"0.00\",\n    \"is_tax_included\": false,\n    \"allow_duplicates\": false,\n    \"dynamic_descriptor\": \"SLEEP UPSELL\",\n    \"sale_type\": \"standard\",\n    \"subscription_config\": {\n      \"interval\": \"month\",\n      \"interval_count\": 1\n    },\n    \"product_id\": 88,\n    \"created_at\": \"2026-06-16T15:04:22.000000Z\",\n    \"updated_at\": \"2026-06-16T15:04:22.000000Z\",\n    \"use_offer_gateway\": false,\n    \"gateway_id\": 7,\n    \"payment_orchestrator_id\": 3,\n    \"bundle_products\": [\n      {\n        \"product_id\": 88,\n        \"name\": \"Sleep Formula 30ct\",\n        \"quantity\": 1,\n        \"position\": 0\n      },\n      {\n        \"product_id\": 92,\n        \"name\": \"Magnesium Add-On\",\n        \"quantity\": 2,\n        \"position\": 1\n      }\n    ]\n  }\n}"}],"_postman_id":"49d017ed-bef2-d897-654f-d48639737038"}],"id":"5b4f139a-ace7-92d0-6b7b-46f8598c3f20","_postman_id":"5b4f139a-ace7-92d0-6b7b-46f8598c3f20","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Affiliates","item":[{"name":"List Campaign Affiliates","id":"c713fe0d-fe7c-ece8-5481-ac69f2f721ba","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/affiliates","description":"<h1 id=\"list-campaign-affiliates\">List Campaign Affiliates</h1>\n<p><strong>Return every affiliate assigned to a campaign along with its payout configuration.</strong></p>\n<p>Returns the full list of affiliate assignments for the specified campaign, ordered by most recently assigned first. Each item includes the affiliate identity plus the payout rules (type, rates, exclusions) configured for that affiliate on this campaign. Results are scoped to the authenticated team and are not paginated.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.affiliates.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>identifier</td>\n<td><em><strong>string (required)</strong></em> Path parameter. The campaign's <code>internal_id</code>. The campaign must belong to the authenticated team.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no query parameters and is not paginated; it returns every assignment for the campaign.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> array. Each element of <code>data[]</code> represents one campaign-affiliate assignment:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>affiliate_id</td>\n<td>The affiliate's <code>custom_id</code> (only present when the affiliate relation is loaded).</td>\n</tr>\n<tr>\n<td>affiliate_name</td>\n<td>The affiliate's display name.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td>Boolean. Whether the assignment is active.</td>\n</tr>\n<tr>\n<td>payout_type</td>\n<td>Payout model: <code>flat_rate</code> or <code>percentage</code>.</td>\n</tr>\n<tr>\n<td>flat_rate</td>\n<td>Decimal string (2 dp), e.g. <code>\"25.00\"</code>. Flat payout amount; <code>null</code> when not applicable.</td>\n</tr>\n<tr>\n<td>percentage_rate</td>\n<td>Decimal string (2 dp), e.g. <code>\"30.00\"</code>. Percentage of revenue; <code>null</code> when not applicable.</td>\n</tr>\n<tr>\n<td>tiered_rates</td>\n<td>Array of tiered rate rules, or <code>null</code>.</td>\n</tr>\n<tr>\n<td>custom_rules</td>\n<td>Array of custom payout rules, or <code>null</code>.</td>\n</tr>\n<tr>\n<td>pay_on_offer_purchase</td>\n<td>Boolean. Whether commission is paid on initial offer purchases.</td>\n</tr>\n<tr>\n<td>pay_on_upsell_purchase</td>\n<td>Boolean. Whether commission is paid on upsell purchases.</td>\n</tr>\n<tr>\n<td>excluded_products</td>\n<td>Array of product identifiers excluded from commission, or <code>null</code>.</td>\n</tr>\n<tr>\n<td>excluded_countries</td>\n<td>Array of country codes excluded from commission, or <code>null</code>.</td>\n</tr>\n<tr>\n<td>created_at</td>\n<td>ISO 8601 timestamp of when the assignment was created.</td>\n</tr>\n<tr>\n<td>updated_at</td>\n<td>ISO 8601 timestamp of the last update.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the necessary permissions.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found for the authenticated team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong></p>\n<p><code>GET https://api.sparkcrm.io/v1/campaigns/123/affiliates</code></p>\n<p><strong>Response</strong> <code>200 OK</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"data\": [\n    {\n      \"affiliate_id\": \"AFF-1001\",\n      \"affiliate_name\": \"Acme Media\",\n      \"is_active\": true,\n      \"payout_type\": \"percentage\",\n      \"flat_rate\": null,\n      \"percentage_rate\": \"30.00\",\n      \"tiered_rates\": null,\n      \"custom_rules\": null,\n      \"pay_on_offer_purchase\": true,\n      \"pay_on_upsell_purchase\": false,\n      \"excluded_products\": [],\n      \"excluded_countries\": [\"CA\"],\n      \"created_at\": \"2026-06-16T14:22:05.000000Z\",\n      \"updated_at\": \"2026-06-16T14:22:05.000000Z\"\n    }\n  ],\n  \"success\": true\n}\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","affiliates"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"01002eb8-acc0-b664-ab8d-4a9d269cf887","name":"List Campaign Affiliates","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/affiliates","description":"# List Campaign Affiliates\n\n**Return every affiliate assigned to a campaign along with its payout configuration.**\n\nReturns the full list of affiliate assignments for the specified campaign, ordered by most recently assigned first. Each item includes the affiliate identity plus the payout rules (type, rates, exclusions) configured for that affiliate on this campaign. Results are scoped to the authenticated team and are not paginated.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.affiliates.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| identifier | _**string (required)**_ Path parameter. The campaign's `internal_id`. The campaign must belong to the authenticated team. |\n\nThis endpoint takes no query parameters and is not paginated; it returns every assignment for the campaign.\n\n## Response Object\n\nReturns `success: true` and a `data` array. Each element of `data[]` represents one campaign-affiliate assignment:\n\n| Field | Description |\n| --- | --- |\n| affiliate_id | The affiliate's `custom_id` (only present when the affiliate relation is loaded). |\n| affiliate_name | The affiliate's display name. |\n| is_active | Boolean. Whether the assignment is active. |\n| payout_type | Payout model: `flat_rate` or `percentage`. |\n| flat_rate | Decimal string (2 dp), e.g. `\"25.00\"`. Flat payout amount; `null` when not applicable. |\n| percentage_rate | Decimal string (2 dp), e.g. `\"30.00\"`. Percentage of revenue; `null` when not applicable. |\n| tiered_rates | Array of tiered rate rules, or `null`. |\n| custom_rules | Array of custom payout rules, or `null`. |\n| pay_on_offer_purchase | Boolean. Whether commission is paid on initial offer purchases. |\n| pay_on_upsell_purchase | Boolean. Whether commission is paid on upsell purchases. |\n| excluded_products | Array of product identifiers excluded from commission, or `null`. |\n| excluded_countries | Array of country codes excluded from commission, or `null`. |\n| created_at | ISO 8601 timestamp of when the assignment was created. |\n| updated_at | ISO 8601 timestamp of the last update. |\n\n## Errors\n\n| Code | Meaning |\n| --- | --- |\n| 403 | Token lacks the necessary permissions. |\n| 404 | Campaign not found for the authenticated team. |\n\n## Example\n\n**Request**\n\n`GET https://api.sparkcrm.io/v1/campaigns/123/affiliates`\n\n**Response** `200 OK`\n\n```json\n{\n  \"data\": [\n    {\n      \"affiliate_id\": \"AFF-1001\",\n      \"affiliate_name\": \"Acme Media\",\n      \"is_active\": true,\n      \"payout_type\": \"percentage\",\n      \"flat_rate\": null,\n      \"percentage_rate\": \"30.00\",\n      \"tiered_rates\": null,\n      \"custom_rules\": null,\n      \"pay_on_offer_purchase\": true,\n      \"pay_on_upsell_purchase\": false,\n      \"excluded_products\": [],\n      \"excluded_countries\": [\"CA\"],\n      \"created_at\": \"2026-06-16T14:22:05.000000Z\",\n      \"updated_at\": \"2026-06-16T14:22:05.000000Z\"\n    }\n  ],\n  \"success\": true\n}\n```"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": [\n    {\n      \"affiliate_id\": \"AFF-1001\",\n      \"affiliate_name\": \"Acme Media\",\n      \"is_active\": true,\n      \"payout_type\": \"percentage\",\n      \"flat_rate\": null,\n      \"percentage_rate\": \"30.00\",\n      \"tiered_rates\": null,\n      \"custom_rules\": null,\n      \"pay_on_offer_purchase\": true,\n      \"pay_on_upsell_purchase\": false,\n      \"excluded_products\": [],\n      \"excluded_countries\": [\"CA\"],\n      \"created_at\": \"2026-06-16T14:22:05.000000Z\",\n      \"updated_at\": \"2026-06-16T14:22:05.000000Z\"\n    },\n    {\n      \"affiliate_id\": \"AFF-1002\",\n      \"affiliate_name\": \"Northbound Traffic\",\n      \"is_active\": true,\n      \"payout_type\": \"flat_rate\",\n      \"flat_rate\": \"25.00\",\n      \"percentage_rate\": null,\n      \"tiered_rates\": null,\n      \"custom_rules\": null,\n      \"pay_on_offer_purchase\": true,\n      \"pay_on_upsell_purchase\": true,\n      \"excluded_products\": [],\n      \"excluded_countries\": [],\n      \"created_at\": \"2026-06-15T09:10:44.000000Z\",\n      \"updated_at\": \"2026-06-15T09:10:44.000000Z\"\n    }\n  ],\n  \"success\": true\n}"}],"_postman_id":"c713fe0d-fe7c-ece8-5481-ac69f2f721ba"},{"name":"Assign Campaign Affiliate","id":"3e5b260d-46cb-df5d-de0c-d17e1a614815","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"affiliate_id\": \"AFF-1001\",\n  \"is_active\": true,\n  \"payout_type\": \"percentage\",\n  \"percentage_rate\": 30,\n  \"pay_on_offer_purchase\": true,\n  \"pay_on_upsell_purchase\": false,\n  \"excluded_products\": [],\n  \"excluded_countries\": [\"CA\"]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/affiliates","description":"<h1 id=\"assign-campaign-affiliate\">Assign Campaign Affiliate</h1>\n<p><strong>Attach an affiliate to a campaign and define how that affiliate is paid.</strong></p>\n<p>Creates a new campaign-affiliate assignment linking an existing affiliate (referenced by its <code>custom_id</code>) to the campaign, together with its payout configuration. The affiliate must already exist for the authenticated team, and the same affiliate cannot be assigned to the campaign more than once.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.affiliates.assign</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>affiliate_id</td>\n<td><em><strong>string (required)</strong></em> The affiliate's <code>custom_id</code>. Max 255 characters. Must reference an affiliate that exists for the authenticated team.</td>\n</tr>\n<tr>\n<td>payout_type</td>\n<td><em><strong>string (required)</strong></em> The payout model. One of: <code>flat_rate</code>, <code>percentage</code>.</td>\n</tr>\n<tr>\n<td>flat_rate</td>\n<td><em><strong>numeric (conditional)</strong></em> Required when <code>payout_type</code> is <code>flat_rate</code>. Flat payout amount per qualifying conversion. Minimum <code>0</code>. Otherwise optional/nullable.</td>\n</tr>\n<tr>\n<td>percentage_rate</td>\n<td><em><strong>numeric (conditional)</strong></em> Required when <code>payout_type</code> is <code>percentage</code>. Percentage of revenue paid out. Minimum <code>0</code>, maximum <code>100</code>. Otherwise optional/nullable.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><em><strong>boolean (optional)</strong></em> Whether the assignment is active. Nullable.</td>\n</tr>\n<tr>\n<td>tiered_rates</td>\n<td><em><strong>array (optional)</strong></em> Tiered rate rules. Nullable.</td>\n</tr>\n<tr>\n<td>custom_rules</td>\n<td><em><strong>array (optional)</strong></em> Custom payout rules. Nullable.</td>\n</tr>\n<tr>\n<td>pay_on_offer_purchase</td>\n<td><em><strong>boolean (optional)</strong></em> Pay commission on initial offer purchases. Nullable.</td>\n</tr>\n<tr>\n<td>pay_on_upsell_purchase</td>\n<td><em><strong>boolean (optional)</strong></em> Pay commission on upsell purchases. Nullable.</td>\n</tr>\n<tr>\n<td>excluded_products</td>\n<td><em><strong>array (optional)</strong></em> Product identifiers excluded from commission. Nullable.</td>\n</tr>\n<tr>\n<td>excluded_countries</td>\n<td><em><strong>array (optional)</strong></em> Country codes excluded from commission. Nullable.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>201 Created</code> with <code>success: true</code>, a <code>message</code>, and a <code>data</code> object representing the newly created assignment (see the List endpoint for the full field list). Decimal rate fields are returned as 2-dp strings (e.g. <code>\"30.00\"</code>).</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the necessary permissions.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found for the authenticated team.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation error. Includes: missing/invalid <code>payout_type</code>; <code>flat_rate</code> missing when <code>payout_type=flat_rate</code>; <code>percentage_rate</code> missing or over <code>100</code> when <code>payout_type=percentage</code>; <code>affiliate_id</code> does not exist for this account; or the affiliate is already assigned to the campaign.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong></p>\n<p><code>POST https://api.sparkcrm.io/v1/campaigns/123/affiliates</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"affiliate_id\": \"AFF-1001\",\n  \"is_active\": true,\n  \"payout_type\": \"percentage\",\n  \"percentage_rate\": 30,\n  \"pay_on_offer_purchase\": true,\n  \"pay_on_upsell_purchase\": false,\n  \"excluded_countries\": [\"CA\"]\n}\n</code></pre>\n<p><strong>Response</strong> <code>201 Created</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"data\": {\n    \"affiliate_id\": \"AFF-1001\",\n    \"affiliate_name\": \"Acme Media\",\n    \"is_active\": true,\n    \"payout_type\": \"percentage\",\n    \"flat_rate\": null,\n    \"percentage_rate\": \"30.00\",\n    \"tiered_rates\": null,\n    \"custom_rules\": null,\n    \"pay_on_offer_purchase\": true,\n    \"pay_on_upsell_purchase\": false,\n    \"excluded_products\": null,\n    \"excluded_countries\": [\"CA\"],\n    \"created_at\": \"2026-06-16T14:22:05.000000Z\",\n    \"updated_at\": \"2026-06-16T14:22:05.000000Z\"\n  },\n  \"success\": true,\n  \"message\": \"Affiliate assigned to campaign successfully\"\n}\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","affiliates"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"b212df4c-ff15-9be5-d6c3-925dc938ffec","name":"Assign Campaign Affiliate","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"affiliate_id\": \"AFF-1001\",\n  \"is_active\": true,\n  \"payout_type\": \"percentage\",\n  \"percentage_rate\": 30,\n  \"pay_on_offer_purchase\": true,\n  \"pay_on_upsell_purchase\": false,\n  \"excluded_products\": [],\n  \"excluded_countries\": [\"CA\"]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/affiliates","description":"# Assign Campaign Affiliate\n\n**Attach an affiliate to a campaign and define how that affiliate is paid.**\n\nCreates a new campaign-affiliate assignment linking an existing affiliate (referenced by its `custom_id`) to the campaign, together with its payout configuration. The affiliate must already exist for the authenticated team, and the same affiliate cannot be assigned to the campaign more than once.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.affiliates.assign`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| affiliate_id | _**string (required)**_ The affiliate's `custom_id`. Max 255 characters. Must reference an affiliate that exists for the authenticated team. |\n| payout_type | _**string (required)**_ The payout model. One of: `flat_rate`, `percentage`. |\n| flat_rate | _**numeric (conditional)**_ Required when `payout_type` is `flat_rate`. Flat payout amount per qualifying conversion. Minimum `0`. Otherwise optional/nullable. |\n| percentage_rate | _**numeric (conditional)**_ Required when `payout_type` is `percentage`. Percentage of revenue paid out. Minimum `0`, maximum `100`. Otherwise optional/nullable. |\n| is_active | _**boolean (optional)**_ Whether the assignment is active. Nullable. |\n| tiered_rates | _**array (optional)**_ Tiered rate rules. Nullable. |\n| custom_rules | _**array (optional)**_ Custom payout rules. Nullable. |\n| pay_on_offer_purchase | _**boolean (optional)**_ Pay commission on initial offer purchases. Nullable. |\n| pay_on_upsell_purchase | _**boolean (optional)**_ Pay commission on upsell purchases. Nullable. |\n| excluded_products | _**array (optional)**_ Product identifiers excluded from commission. Nullable. |\n| excluded_countries | _**array (optional)**_ Country codes excluded from commission. Nullable. |\n\n## Response\n\nReturns `201 Created` with `success: true`, a `message`, and a `data` object representing the newly created assignment (see the List endpoint for the full field list). Decimal rate fields are returned as 2-dp strings (e.g. `\"30.00\"`).\n\n## Errors\n\n| Code | Meaning |\n| --- | --- |\n| 403 | Token lacks the necessary permissions. |\n| 404 | Campaign not found for the authenticated team. |\n| 422 | Validation error. Includes: missing/invalid `payout_type`; `flat_rate` missing when `payout_type=flat_rate`; `percentage_rate` missing or over `100` when `payout_type=percentage`; `affiliate_id` does not exist for this account; or the affiliate is already assigned to the campaign. |\n\n## Example\n\n**Request**\n\n`POST https://api.sparkcrm.io/v1/campaigns/123/affiliates`\n\n```json\n{\n  \"affiliate_id\": \"AFF-1001\",\n  \"is_active\": true,\n  \"payout_type\": \"percentage\",\n  \"percentage_rate\": 30,\n  \"pay_on_offer_purchase\": true,\n  \"pay_on_upsell_purchase\": false,\n  \"excluded_countries\": [\"CA\"]\n}\n```\n\n**Response** `201 Created`\n\n```json\n{\n  \"data\": {\n    \"affiliate_id\": \"AFF-1001\",\n    \"affiliate_name\": \"Acme Media\",\n    \"is_active\": true,\n    \"payout_type\": \"percentage\",\n    \"flat_rate\": null,\n    \"percentage_rate\": \"30.00\",\n    \"tiered_rates\": null,\n    \"custom_rules\": null,\n    \"pay_on_offer_purchase\": true,\n    \"pay_on_upsell_purchase\": false,\n    \"excluded_products\": null,\n    \"excluded_countries\": [\"CA\"],\n    \"created_at\": \"2026-06-16T14:22:05.000000Z\",\n    \"updated_at\": \"2026-06-16T14:22:05.000000Z\"\n  },\n  \"success\": true,\n  \"message\": \"Affiliate assigned to campaign successfully\"\n}\n```"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"affiliate_id\": \"AFF-1001\",\n    \"affiliate_name\": \"Acme Media\",\n    \"is_active\": true,\n    \"payout_type\": \"percentage\",\n    \"flat_rate\": null,\n    \"percentage_rate\": \"30.00\",\n    \"tiered_rates\": null,\n    \"custom_rules\": null,\n    \"pay_on_offer_purchase\": true,\n    \"pay_on_upsell_purchase\": false,\n    \"excluded_products\": null,\n    \"excluded_countries\": [\"CA\"],\n    \"created_at\": \"2026-06-16T14:22:05.000000Z\",\n    \"updated_at\": \"2026-06-16T14:22:05.000000Z\"\n  },\n  \"success\": true,\n  \"message\": \"Affiliate assigned to campaign successfully\"\n}"}],"_postman_id":"3e5b260d-46cb-df5d-de0c-d17e1a614815"},{"name":"Unassign Campaign Affiliate","id":"2898f7b3-e05e-c79b-55bd-32c978a04a0c","request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/affiliates/AFF-1001","description":"<h1 id=\"unassign-campaign-affiliate\">Unassign Campaign Affiliate</h1>\n<p><strong>Remove an affiliate's assignment (and payout configuration) from a campaign.</strong></p>\n<p>Deletes the campaign-affiliate assignment linking the given affiliate to the campaign. The affiliate is referenced by its <code>custom_id</code> in the URL path. Both the campaign and the affiliate must belong to the authenticated team, and an active assignment must exist between them. The assignment is soft-deleted.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.affiliates.unassign</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>identifier</td>\n<td><em><strong>string (required)</strong></em> Path parameter. The campaign's <code>internal_id</code>. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td>affiliate_id</td>\n<td><em><strong>string (required)</strong></em> Path parameter. The affiliate's <code>custom_id</code>. Must reference an affiliate assigned to this campaign.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no request body.</p>\n<h2 id=\"response\">Response</h2>\n<p>Returns <code>200 OK</code> with a confirmation message:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td>Boolean. <code>true</code> on success.</td>\n</tr>\n<tr>\n<td>message</td>\n<td><code>\"Affiliate unassigned from campaign successfully\"</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the necessary permissions.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found, or no affiliate assignment exists for the given affiliate on this campaign (\"Affiliate assignment not found\").</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong></p>\n<p><code>DELETE https://api.sparkcrm.io/v1/campaigns/123/affiliates/AFF-1001</code></p>\n<p><strong>Response</strong> <code>200 OK</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Affiliate unassigned from campaign successfully\"\n}\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","affiliates","AFF-1001"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"61412ab6-3fcb-2fce-dba0-53b274a444a0","name":"Unassign Campaign Affiliate","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/affiliates/AFF-1001","description":"# Unassign Campaign Affiliate\n\n**Remove an affiliate's assignment (and payout configuration) from a campaign.**\n\nDeletes the campaign-affiliate assignment linking the given affiliate to the campaign. The affiliate is referenced by its `custom_id` in the URL path. Both the campaign and the affiliate must belong to the authenticated team, and an active assignment must exist between them. The assignment is soft-deleted.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.affiliates.unassign`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| identifier | _**string (required)**_ Path parameter. The campaign's `internal_id`. Must belong to the authenticated team. |\n| affiliate_id | _**string (required)**_ Path parameter. The affiliate's `custom_id`. Must reference an affiliate assigned to this campaign. |\n\nThis endpoint takes no request body.\n\n## Response\n\nReturns `200 OK` with a confirmation message:\n\n| Field | Description |\n| --- | --- |\n| success | Boolean. `true` on success. |\n| message | `\"Affiliate unassigned from campaign successfully\"`. |\n\n## Errors\n\n| Code | Meaning |\n| --- | --- |\n| 403 | Token lacks the necessary permissions. |\n| 404 | Campaign not found, or no affiliate assignment exists for the given affiliate on this campaign (\"Affiliate assignment not found\"). |\n\n## Example\n\n**Request**\n\n`DELETE https://api.sparkcrm.io/v1/campaigns/123/affiliates/AFF-1001`\n\n**Response** `200 OK`\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Affiliate unassigned from campaign successfully\"\n}\n```"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Affiliate unassigned from campaign successfully\"\n}"}],"_postman_id":"2898f7b3-e05e-c79b-55bd-32c978a04a0c"}],"id":"cdeb9dd1-4513-664c-9220-86267e0b3810","_postman_id":"cdeb9dd1-4513-664c-9220-86267e0b3810","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Auto Responders","item":[{"name":"List Campaign Auto Responders","id":"2fa9d3ef-2e79-f430-1e79-9f869fa1772b","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders","description":"<h1 id=\"list-campaign-auto-responders\">List Campaign Auto Responders</h1>\n<p><strong>Retrieve every auto responder configured within a single campaign.</strong></p>\n<p>Returns all auto responders attached to the specified campaign, ordered by creation date (newest first). Each auto responder defines which lifecycle events trigger an automated email, which email template and SMTP provider are used, an optional send delay, and any products that should be excluded from triggering it.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.auto_responders.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> — Path parameter. The campaign's <code>internal_id</code> (the campaign identifier returned by the campaigns API). The campaign must belong to the authenticated team.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint accepts no query parameters. The full result set is returned (not paginated).</p>\n<h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> array. Each element is an auto responder object:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>string (uuid) — The auto responder identifier. Used as <code>{assignment_id}</code> on update/delete.</td>\n</tr>\n<tr>\n<td><code>campaign_id</code></td>\n<td>string — The parent campaign's <code>internal_id</code>.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>string — Human-readable name of the auto responder.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td>boolean — Whether the auto responder is currently enabled.</td>\n</tr>\n<tr>\n<td><code>trigger_types</code></td>\n<td>array of string — Lifecycle events that fire this responder (see Create for enum values).</td>\n</tr>\n<tr>\n<td><code>trigger_conditions</code></td>\n<td>object|null — Arbitrary condition map (e.g. <code>days_before_billing</code> for subscription reminders).</td>\n</tr>\n<tr>\n<td><code>delay_minutes</code></td>\n<td>integer|null — Minutes to wait after the trigger before sending.</td>\n</tr>\n<tr>\n<td><code>email_template_id</code></td>\n<td>integer — ID of the email template that is sent.</td>\n</tr>\n<tr>\n<td><code>smtp_provider_id</code></td>\n<td>integer|null — ID of the SMTP provider used to send. <code>null</code> uses the campaign/team default.</td>\n</tr>\n<tr>\n<td><code>excluded_products</code></td>\n<td>array|null — Product IDs that should not cause this responder to fire.</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td>string (ISO 8601) — Creation timestamp.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td>string (ISO 8601) — Last update timestamp.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:campaigns.auto_responders.view</code> (or legacy <code>api:view_any</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found for the authenticated team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET https://api.sparkcrm.io/v1/campaigns/123/auto-responders</code></p>\n<p>Returns the array of auto responders for campaign <code>123</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","auto-responders"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"6b1a9009-798c-22cd-b6a2-64d509ddc34f","name":"List Campaign Auto Responders","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders","description":"# List Campaign Auto Responders\n\n**Retrieve every auto responder configured within a single campaign.**\n\nReturns all auto responders attached to the specified campaign, ordered by creation date (newest first). Each auto responder defines which lifecycle events trigger an automated email, which email template and SMTP provider are used, an optional send delay, and any products that should be excluded from triggering it.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.auto_responders.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ — Path parameter. The campaign's `internal_id` (the campaign identifier returned by the campaigns API). The campaign must belong to the authenticated team. |\n\nThis endpoint accepts no query parameters. The full result set is returned (not paginated).\n\n## Response Object\n\nReturns `success: true` and a `data` array. Each element is an auto responder object:\n\n| Field | Description |\n| --- | --- |\n| `id` | string (uuid) — The auto responder identifier. Used as `{assignment_id}` on update/delete. |\n| `campaign_id` | string — The parent campaign's `internal_id`. |\n| `name` | string — Human-readable name of the auto responder. |\n| `is_active` | boolean — Whether the auto responder is currently enabled. |\n| `trigger_types` | array of string — Lifecycle events that fire this responder (see Create for enum values). |\n| `trigger_conditions` | object\\|null — Arbitrary condition map (e.g. `days_before_billing` for subscription reminders). |\n| `delay_minutes` | integer\\|null — Minutes to wait after the trigger before sending. |\n| `email_template_id` | integer — ID of the email template that is sent. |\n| `smtp_provider_id` | integer\\|null — ID of the SMTP provider used to send. `null` uses the campaign/team default. |\n| `excluded_products` | array\\|null — Product IDs that should not cause this responder to fire. |\n| `created_at` | string (ISO 8601) — Creation timestamp. |\n| `updated_at` | string (ISO 8601) — Last update timestamp. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:campaigns.auto_responders.view` (or legacy `api:view_any`) permission. |\n| 404 | Campaign not found for the authenticated team. |\n\n## Example\n\n`GET https://api.sparkcrm.io/v1/campaigns/123/auto-responders`\n\nReturns the array of auto responders for campaign `123`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": \"9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c\",\n      \"campaign_id\": \"123\",\n      \"name\": \"Order Confirmation Email\",\n      \"is_active\": true,\n      \"trigger_types\": [\n        \"order_confirmation\"\n      ],\n      \"trigger_conditions\": null,\n      \"delay_minutes\": 0,\n      \"email_template_id\": 45,\n      \"smtp_provider_id\": 12,\n      \"excluded_products\": [],\n      \"created_at\": \"2026-06-10T14:23:05.000000Z\",\n      \"updated_at\": \"2026-06-10T14:23:05.000000Z\"\n    },\n    {\n      \"id\": \"3a8e9d10-12bf-4c77-9e44-5b6c7d8e9f01\",\n      \"campaign_id\": \"123\",\n      \"name\": \"Subscription Renewal Reminder\",\n      \"is_active\": true,\n      \"trigger_types\": [\n        \"subscription_reminder\"\n      ],\n      \"trigger_conditions\": {\n        \"days_before_billing\": 3\n      },\n      \"delay_minutes\": 60,\n      \"email_template_id\": 51,\n      \"smtp_provider_id\": null,\n      \"excluded_products\": [\n        88\n      ],\n      \"created_at\": \"2026-06-05T09:10:44.000000Z\",\n      \"updated_at\": \"2026-06-08T16:02:31.000000Z\"\n    }\n  ]\n}"}],"_postman_id":"2fa9d3ef-2e79-f430-1e79-9f869fa1772b"},{"name":"Create Campaign Auto Responder","id":"cc654050-0896-ac5e-345d-181000e0ce22","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Order Confirmation Email\",\n  \"email_template_id\": 45,\n  \"smtp_provider_id\": 12,\n  \"trigger_types\": [\n    \"order_confirmation\"\n  ],\n  \"trigger_conditions\": {\n    \"days_before_billing\": 3\n  },\n  \"delay_minutes\": 0,\n  \"excluded_products\": [\n    88\n  ],\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders","description":"<h1 id=\"create-campaign-auto-responder\">Create Campaign Auto Responder</h1>\n<p><strong>Attach a new automated email responder to a campaign.</strong></p>\n<p>Creates an auto responder that automatically sends a chosen email template when one or more of the configured lifecycle events occur for an order or subscription in this campaign. The new responder is generated with a server-side UUID and returned in full.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.auto_responders.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (required)</strong></em> — Display name for the auto responder. Max length 255.</td>\n</tr>\n<tr>\n<td><code>email_template_id</code></td>\n<td><em><strong>integer (required)</strong></em> — ID of the email template to send. Must exist in <code>email_templates</code> and belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><code>smtp_provider_id</code></td>\n<td><em><strong>integer (optional)</strong></em> — ID of the SMTP provider used to deliver the email. Must exist in <code>smtp_providers</code> and belong to the authenticated team. Nullable; omit/<code>null</code> to use the default sender.</td>\n</tr>\n<tr>\n<td><code>trigger_types</code></td>\n<td><em><strong>array (required)</strong></em> — Non-empty array of trigger event strings. At least one (<code>min:1</code>) required. Allowed values: <code>order_confirmation</code>, <code>tracking_issued</code>, <code>carrier_accepted</code>, <code>order_shipped</code>, <code>shipment_in_transit</code>, <code>shipment_out_for_delivery</code>, <code>shipment_delivered</code>, <code>order_refunded</code>, <code>order_canceled</code>, <code>order_voided</code>, <code>subscription_reminder</code>, <code>subscription_renewed</code>.</td>\n</tr>\n<tr>\n<td><code>trigger_types[]</code></td>\n<td><em><strong>string (required)</strong></em> — Each element must be one of the allowed trigger enum values listed above.</td>\n</tr>\n<tr>\n<td><code>trigger_conditions</code></td>\n<td><em><strong>object (optional)</strong></em> — Arbitrary condition map. Nullable. For <code>subscription_reminder</code> triggers, supply <code>days_before_billing</code> (integer; defaults to 3 when unset).</td>\n</tr>\n<tr>\n<td><code>delay_minutes</code></td>\n<td><em><strong>integer (optional)</strong></em> — Minutes to wait after the trigger fires before sending. Nullable. Minimum 0.</td>\n</tr>\n<tr>\n<td><code>excluded_products</code></td>\n<td><em><strong>array (optional)</strong></em> — Array of product IDs that should NOT cause this responder to fire. Nullable.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> — Whether the responder is enabled. Nullable boolean; defaults to inactive/unset when omitted.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>201 Created</code> with <code>success: true</code>, a <code>message</code>, and a <code>data</code> object containing the created auto responder. See the List endpoint for the full field reference.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>Validation error. Returned with <code>errors</code> keyed by field (e.g. invalid <code>trigger_types</code>, <code>email_template_id</code> not found for team, empty <code>trigger_types</code>).</td>\n</tr>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:campaigns.auto_responders.create</code> (or legacy <code>api:create</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found for the authenticated team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>POST https://api.sparkcrm.io/v1/campaigns/123/auto-responders</code></p>\n<p>Creates an order-confirmation responder using template 45 and SMTP provider 12.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","auto-responders"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"d1989f3f-0a3f-c625-3c78-7571ea6249da","name":"Create Campaign Auto Responder","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Order Confirmation Email\",\n  \"email_template_id\": 45,\n  \"smtp_provider_id\": 12,\n  \"trigger_types\": [\n    \"order_confirmation\"\n  ],\n  \"trigger_conditions\": {\n    \"days_before_billing\": 3\n  },\n  \"delay_minutes\": 0,\n  \"excluded_products\": [\n    88\n  ],\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders","description":"# Create Campaign Auto Responder\n\n**Attach a new automated email responder to a campaign.**\n\nCreates an auto responder that automatically sends a chosen email template when one or more of the configured lifecycle events occur for an order or subscription in this campaign. The new responder is generated with a server-side UUID and returned in full.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.auto_responders.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| `name` | _**string (required)**_ — Display name for the auto responder. Max length 255. |\n| `email_template_id` | _**integer (required)**_ — ID of the email template to send. Must exist in `email_templates` and belong to the authenticated team. |\n| `smtp_provider_id` | _**integer (optional)**_ — ID of the SMTP provider used to deliver the email. Must exist in `smtp_providers` and belong to the authenticated team. Nullable; omit/`null` to use the default sender. |\n| `trigger_types` | _**array (required)**_ — Non-empty array of trigger event strings. At least one (`min:1`) required. Allowed values: `order_confirmation`, `tracking_issued`, `carrier_accepted`, `order_shipped`, `shipment_in_transit`, `shipment_out_for_delivery`, `shipment_delivered`, `order_refunded`, `order_canceled`, `order_voided`, `subscription_reminder`, `subscription_renewed`. |\n| `trigger_types[]` | _**string (required)**_ — Each element must be one of the allowed trigger enum values listed above. |\n| `trigger_conditions` | _**object (optional)**_ — Arbitrary condition map. Nullable. For `subscription_reminder` triggers, supply `days_before_billing` (integer; defaults to 3 when unset). |\n| `delay_minutes` | _**integer (optional)**_ — Minutes to wait after the trigger fires before sending. Nullable. Minimum 0. |\n| `excluded_products` | _**array (optional)**_ — Array of product IDs that should NOT cause this responder to fire. Nullable. |\n| `is_active` | _**boolean (optional)**_ — Whether the responder is enabled. Nullable boolean; defaults to inactive/unset when omitted. |\n\n## Response\n\nReturns `201 Created` with `success: true`, a `message`, and a `data` object containing the created auto responder. See the List endpoint for the full field reference.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 422 | Validation error. Returned with `errors` keyed by field (e.g. invalid `trigger_types`, `email_template_id` not found for team, empty `trigger_types`). |\n| 403 | Token lacks the `api:campaigns.auto_responders.create` (or legacy `api:create`) permission. |\n| 404 | Campaign not found for the authenticated team. |\n\n## Example\n\n`POST https://api.sparkcrm.io/v1/campaigns/123/auto-responders`\n\nCreates an order-confirmation responder using template 45 and SMTP provider 12."},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Auto responder created successfully\",\n  \"data\": {\n    \"id\": \"9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c\",\n    \"campaign_id\": \"123\",\n    \"name\": \"Order Confirmation Email\",\n    \"is_active\": true,\n    \"trigger_types\": [\n      \"order_confirmation\"\n    ],\n    \"trigger_conditions\": {\n      \"days_before_billing\": 3\n    },\n    \"delay_minutes\": 0,\n    \"email_template_id\": 45,\n    \"smtp_provider_id\": 12,\n    \"excluded_products\": [\n      88\n    ],\n    \"created_at\": \"2026-06-16T18:42:10.000000Z\",\n    \"updated_at\": \"2026-06-16T18:42:10.000000Z\"\n  }\n}"}],"_postman_id":"cc654050-0896-ac5e-345d-181000e0ce22"},{"name":"Update Campaign Auto Responder","id":"cd021336-4431-b460-e287-50598bbaf30f","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Order Confirmation Email (v2)\",\n  \"is_active\": false,\n  \"trigger_types\": [\n    \"order_confirmation\",\n    \"order_shipped\"\n  ],\n  \"delay_minutes\": 15,\n  \"excluded_products\": [\n    88,\n    102\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c","description":"<h1 id=\"update-campaign-auto-responder\">Update Campaign Auto Responder</h1>\n<p><strong>Modify an existing auto responder on a campaign.</strong></p>\n<p>Updates one auto responder identified by its UUID (<code>assignment_id</code>). All fields are optional on update — send only the fields you wish to change. Any field that is supplied is fully re-validated using the same rules as creation.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.auto_responders.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields use <code>sometimes</code> semantics — included fields are validated, omitted fields are left unchanged.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (optional)</strong></em> — Display name. When present it is required and <code>max:255</code>.</td>\n</tr>\n<tr>\n<td><code>email_template_id</code></td>\n<td><em><strong>integer (optional)</strong></em> — When present, must exist in <code>email_templates</code> for the authenticated team.</td>\n</tr>\n<tr>\n<td><code>smtp_provider_id</code></td>\n<td><em><strong>integer (optional)</strong></em> — When present, must exist in <code>smtp_providers</code> for the authenticated team. Nullable.</td>\n</tr>\n<tr>\n<td><code>trigger_types</code></td>\n<td><em><strong>array (optional)</strong></em> — When present it is required, must be an array with at least one element (<code>min:1</code>).</td>\n</tr>\n<tr>\n<td><code>trigger_types[]</code></td>\n<td><em><strong>string (optional)</strong></em> — Each element must be one of: <code>order_confirmation</code>, <code>tracking_issued</code>, <code>carrier_accepted</code>, <code>order_shipped</code>, <code>shipment_in_transit</code>, <code>shipment_out_for_delivery</code>, <code>shipment_delivered</code>, <code>order_refunded</code>, <code>order_canceled</code>, <code>order_voided</code>, <code>subscription_reminder</code>, <code>subscription_renewed</code>.</td>\n</tr>\n<tr>\n<td><code>trigger_conditions</code></td>\n<td><em><strong>object (optional)</strong></em> — Arbitrary condition map. Nullable.</td>\n</tr>\n<tr>\n<td><code>delay_minutes</code></td>\n<td><em><strong>integer (optional)</strong></em> — Minutes to wait before sending. Nullable. Minimum 0.</td>\n</tr>\n<tr>\n<td><code>excluded_products</code></td>\n<td><em><strong>array (optional)</strong></em> — Product IDs excluded from triggering. Nullable.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> — Enable/disable the responder.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"path-parameters\">Path Parameters</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> — The campaign's <code>internal_id</code>.</td>\n</tr>\n<tr>\n<td><code>assignment_id</code></td>\n<td><em><strong>string (required)</strong></em> — The auto responder UUID (the <code>id</code> returned by List/Create).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>200 OK</code> with <code>success: true</code>, a <code>message</code>, and the updated auto responder in <code>data</code>. See the List endpoint for the full field reference.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>422</td>\n<td>Validation error. Returned with <code>errors</code> keyed by field.</td>\n</tr>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:campaigns.auto_responders.update</code> (or legacy <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found, or auto responder not found within the campaign.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>PATCH https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c</code></p>\n<p>Disables the responder and adds the <code>order_shipped</code> trigger.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","auto-responders","9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"4e79e944-17bb-2984-79fa-6a9d594d0a9e","name":"Update Campaign Auto Responder","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Order Confirmation Email (v2)\",\n  \"is_active\": false,\n  \"trigger_types\": [\n    \"order_confirmation\",\n    \"order_shipped\"\n  ],\n  \"delay_minutes\": 15,\n  \"excluded_products\": [\n    88,\n    102\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c","description":"# Update Campaign Auto Responder\n\n**Modify an existing auto responder on a campaign.**\n\nUpdates one auto responder identified by its UUID (`assignment_id`). All fields are optional on update — send only the fields you wish to change. Any field that is supplied is fully re-validated using the same rules as creation.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.auto_responders.update`\n\n## Request Body\n\nAll fields use `sometimes` semantics — included fields are validated, omitted fields are left unchanged.\n\n| Request Field | Description |\n| --- | --- |\n| `name` | _**string (optional)**_ — Display name. When present it is required and `max:255`. |\n| `email_template_id` | _**integer (optional)**_ — When present, must exist in `email_templates` for the authenticated team. |\n| `smtp_provider_id` | _**integer (optional)**_ — When present, must exist in `smtp_providers` for the authenticated team. Nullable. |\n| `trigger_types` | _**array (optional)**_ — When present it is required, must be an array with at least one element (`min:1`). |\n| `trigger_types[]` | _**string (optional)**_ — Each element must be one of: `order_confirmation`, `tracking_issued`, `carrier_accepted`, `order_shipped`, `shipment_in_transit`, `shipment_out_for_delivery`, `shipment_delivered`, `order_refunded`, `order_canceled`, `order_voided`, `subscription_reminder`, `subscription_renewed`. |\n| `trigger_conditions` | _**object (optional)**_ — Arbitrary condition map. Nullable. |\n| `delay_minutes` | _**integer (optional)**_ — Minutes to wait before sending. Nullable. Minimum 0. |\n| `excluded_products` | _**array (optional)**_ — Product IDs excluded from triggering. Nullable. |\n| `is_active` | _**boolean (optional)**_ — Enable/disable the responder. |\n\n## Path Parameters\n\n| Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ — The campaign's `internal_id`. |\n| `assignment_id` | _**string (required)**_ — The auto responder UUID (the `id` returned by List/Create). |\n\n## Response\n\nReturns `200 OK` with `success: true`, a `message`, and the updated auto responder in `data`. See the List endpoint for the full field reference.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 422 | Validation error. Returned with `errors` keyed by field. |\n| 403 | Token lacks the `api:campaigns.auto_responders.update` (or legacy `api:update`) permission. |\n| 404 | Campaign not found, or auto responder not found within the campaign. |\n\n## Example\n\n`PATCH https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c`\n\nDisables the responder and adds the `order_shipped` trigger."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Auto responder updated successfully\",\n  \"data\": {\n    \"id\": \"9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c\",\n    \"campaign_id\": \"123\",\n    \"name\": \"Order Confirmation Email (v2)\",\n    \"is_active\": false,\n    \"trigger_types\": [\n      \"order_confirmation\",\n      \"order_shipped\"\n    ],\n    \"trigger_conditions\": {\n      \"days_before_billing\": 3\n    },\n    \"delay_minutes\": 15,\n    \"email_template_id\": 45,\n    \"smtp_provider_id\": 12,\n    \"excluded_products\": [\n      88,\n      102\n    ],\n    \"created_at\": \"2026-06-16T18:42:10.000000Z\",\n    \"updated_at\": \"2026-06-16T19:05:48.000000Z\"\n  }\n}"}],"_postman_id":"cd021336-4431-b460-e287-50598bbaf30f"},{"name":"Delete Campaign Auto Responder","id":"a9240ca0-723c-c2bb-1cf1-5653fd3a8865","request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c","description":"<h1 id=\"delete-campaign-auto-responder\">Delete Campaign Auto Responder</h1>\n<p><strong>Remove an auto responder from a campaign.</strong></p>\n<p>Soft-deletes the auto responder identified by its UUID (<code>assignment_id</code>) within the given campaign. Once deleted it no longer fires on campaign lifecycle events.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.auto_responders.delete</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>identifier</code></td>\n<td><em><strong>string (required)</strong></em> — Path parameter. The campaign's <code>internal_id</code>. Campaign must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><code>assignment_id</code></td>\n<td><em><strong>string (required)</strong></em> — Path parameter. The auto responder UUID (the <code>id</code> returned by List/Create).</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint accepts no request body.</p>\n<h2 id=\"response\">Response</h2>\n<p>Returns <code>200 OK</code> with a confirmation message.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>success</code></td>\n<td>boolean — Always <code>true</code> on success.</td>\n</tr>\n<tr>\n<td><code>message</code></td>\n<td>string — <code>Auto responder deleted successfully</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:campaigns.auto_responders.delete</code> (or legacy <code>api:delete</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Campaign not found, or auto responder not found within the campaign.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>DELETE https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c</code></p>\n<p>Deletes the specified auto responder.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","123","auto-responders","9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"e920829d-b1f2-fa61-e539-b2837b30ec2f","name":"Delete Campaign Auto Responder","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c","description":"# Delete Campaign Auto Responder\n\n**Remove an auto responder from a campaign.**\n\nSoft-deletes the auto responder identified by its UUID (`assignment_id`) within the given campaign. Once deleted it no longer fires on campaign lifecycle events.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.auto_responders.delete`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `identifier` | _**string (required)**_ — Path parameter. The campaign's `internal_id`. Campaign must belong to the authenticated team. |\n| `assignment_id` | _**string (required)**_ — Path parameter. The auto responder UUID (the `id` returned by List/Create). |\n\nThis endpoint accepts no request body.\n\n## Response\n\nReturns `200 OK` with a confirmation message.\n\n| Field | Description |\n| --- | --- |\n| `success` | boolean — Always `true` on success. |\n| `message` | string — `Auto responder deleted successfully`. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:campaigns.auto_responders.delete` (or legacy `api:delete`) permission. |\n| 404 | Campaign not found, or auto responder not found within the campaign. |\n\n## Example\n\n`DELETE https://api.sparkcrm.io/v1/campaigns/123/auto-responders/9b2f1c4e-7a3d-4f2b-8c1a-2e5d6f7a8b9c`\n\nDeletes the specified auto responder."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Auto responder deleted successfully\"\n}"}],"_postman_id":"a9240ca0-723c-c2bb-1cf1-5653fd3a8865"}],"id":"87bb317e-f6f9-d0e0-8d49-2db22a65eb4e","_postman_id":"87bb317e-f6f9-d0e0-8d49-2db22a65eb4e","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Search Campaign(s)","id":"616648a1-9455-4c37-b54e-b1f57fa220f2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns?is_active=1&per_page=10","description":"<h2 id=\"get-campaigns\">Get Campaigns</h2>\n<p>Retrieve information about campaigns that match the specified search criteria, or get a specific campaign by its identifier.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>identifier</td>\n<td><em>string (optional)</em>  <br />Get a specific campaign by internal ID. When provided, returns a single campaign instead of a paginated list.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><em>string (optional)</em>  <br />Filter campaigns by active status. Supported values: <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code></td>\n</tr>\n<tr>\n<td>category_id</td>\n<td><em>integer (optional)</em>  <br />Filter campaigns by category ID.</td>\n</tr>\n<tr>\n<td>search</td>\n<td><em>string (optional)</em>  <br />Search campaigns by name or internal ID. Performs partial matching using SQL LIKE operations.</td>\n</tr>\n<tr>\n<td>per_page</td>\n<td><em>integer (optional)</em>  <br />Number of results per page. Minimum: 1, Maximum: 15. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>array/object</strong>  <br />When <code>identifier</code> is provided, returns a single campaign object. Otherwise, returns an array of campaign objects matching the search criteria</td>\n</tr>\n<tr>\n<td>data.id</td>\n<td><strong>integer</strong>  <br />Unique database identifier for the campaign</td>\n</tr>\n<tr>\n<td>data.internal_id</td>\n<td><strong>string</strong>  <br />Internal identifier for the campaign</td>\n</tr>\n<tr>\n<td>data.name</td>\n<td><strong>string</strong>  <br />Campaign name</td>\n</tr>\n<tr>\n<td>data.uuid</td>\n<td><strong>string</strong>  <br />Universal unique identifier for the campaign</td>\n</tr>\n<tr>\n<td>data.is_active</td>\n<td><strong>boolean</strong>  <br />Indicates if the campaign is currently active</td>\n</tr>\n<tr>\n<td>data.allowed_countries</td>\n<td><strong>array</strong>  <br />List of country codes where the campaign is allowed (ISO 3166-1 alpha-2 format)</td>\n</tr>\n<tr>\n<td>data.allowed_currencies</td>\n<td><strong>array</strong>  <br />List of currency codes allowed for the campaign (ISO 4217 format)</td>\n</tr>\n<tr>\n<td>data.restrict_by_ip_country</td>\n<td><strong>boolean</strong>  <br />When <code>true</code>, the order endpoints (<code>POST /checkout/leads</code>, <code>POST /checkout/orders</code>, <code>POST /checkout/orders/payment</code>) decline requests whose IP-resolved country (from <code>ip_address</code> lookup) is not in <code>allowed_countries</code>. The customer-facing response is generic (<code>errors.country_not_allowed</code>); the merchant sees the actual resolved country in the order's system notes. Fail-open: when no IP country can be resolved (no <code>ip_address</code> sent or ipdata lookup failure), the order is allowed through.</td>\n</tr>\n<tr>\n<td>data.allowed_card_brands</td>\n<td><strong>array</strong>  <br />List of card brands allowed for the campaign (e.g., \"visa\", \"mastercard\")</td>\n</tr>\n<tr>\n<td>data.allow_prepaid_cards</td>\n<td><strong>boolean</strong>  <br />Indicates if prepaid cards are allowed</td>\n</tr>\n<tr>\n<td>data.allow_virtual_cards</td>\n<td><strong>boolean</strong>  <br />Indicates if virtual cards are allowed</td>\n</tr>\n<tr>\n<td>data.allow_international_cards</td>\n<td><strong>boolean</strong>  <br />Indicates if international cards are allowed</td>\n</tr>\n<tr>\n<td>data.minimum_amount</td>\n<td><strong>string</strong>  <br />Minimum transaction amount allowed for the campaign</td>\n</tr>\n<tr>\n<td>data.maximum_amount</td>\n<td><strong>string</strong>  <br />Maximum transaction amount allowed for the campaign</td>\n</tr>\n<tr>\n<td>data.max_customer_declines</td>\n<td><strong>integer</strong>  <br />Maximum number of declines allowed per customer</td>\n</tr>\n<tr>\n<td>data.max_orders_per_email</td>\n<td><strong>integer|null</strong>  <br />Maximum number of successful orders allowed per customer email on this campaign. <code>null</code> means no limit. When the cap is reached, <code>POST /checkout/orders</code> returns 422 with <code>errors.max_orders_per_email_reached</code>.</td>\n</tr>\n<tr>\n<td>data.max_upsell_declines</td>\n<td><strong>integer|null</strong>  <br />Maximum number of declined upsell transactions allowed per order. <code>null</code> means no limit. Once reached, further <code>POST /checkout/orders/upsell</code> requests return an immediate declined response without calling the payment gateway.</td>\n</tr>\n<tr>\n<td>data.fulfillment_delay</td>\n<td><strong>integer</strong>  <br />Delay in hours before fulfillment processing</td>\n</tr>\n<tr>\n<td>data.category</td>\n<td><strong>object/null</strong>  <br />Campaign category information</td>\n</tr>\n<tr>\n<td>data.category.id</td>\n<td><strong>integer</strong>  <br />Category ID</td>\n</tr>\n<tr>\n<td>data.category.name</td>\n<td><strong>string</strong>  <br />Category name</td>\n</tr>\n<tr>\n<td>data.gateway_id</td>\n<td><strong>integer/null</strong>  <br />Payment gateway ID associated with the campaign</td>\n</tr>\n<tr>\n<td>data.payment_orchestrator_id</td>\n<td><strong>integer/null</strong>  <br />Payment orchestrator ID associated with the campaign</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date and time when the campaign was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the campaign was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.offers_count</td>\n<td><strong>integer</strong>  <br />Number of active offers associated with the campaign</td>\n</tr>\n<tr>\n<td>data.upsells_count</td>\n<td><strong>integer</strong>  <br />Number of active upsells associated with the campaign</td>\n</tr>\n<tr>\n<td>pagination</td>\n<td><strong>object</strong>  <br />Contains pagination information for the response (only present when returning multiple campaigns)</td>\n</tr>\n<tr>\n<td>pagination.total</td>\n<td><strong>integer</strong>  <br />Total number of campaigns matching the search criteria</td>\n</tr>\n<tr>\n<td>pagination.per_page</td>\n<td><strong>integer</strong>  <br />Number of campaigns displayed per page</td>\n</tr>\n<tr>\n<td>pagination.current_page</td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td>pagination.last_page</td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td>pagination.from</td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td>pagination.to</td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example-requests\">Example Requests</h2>\n<h3 id=\"get-all-campaigns-paginated\">Get All Campaigns (Paginated)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h3 id=\"get-specific-campaign-by-internal-id\">Get Specific Campaign by Internal ID</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns?identifier=123\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h2 id=\"example-response-single-campaign\">Example Response (Single Campaign)</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"id\": 1,\n    \"internal_id\": \"123\",\n    \"name\": \"Summer Sale Campaign\",\n    \"uuid\": \"550e8400-e29b-41d4-a716-446655440000\",\n    \"is_active\": true,\n    \"allowed_countries\": [\"US\", \"CA\", \"GB\"],\n    \"allowed_currencies\": [\"USD\", \"CAD\", \"GBP\"],\n    \"restrict_by_ip_country\": false,\n    \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\"],\n    \"allow_prepaid_cards\": true,\n    \"allow_virtual_cards\": false,\n    \"allow_international_cards\": true,\n    \"minimum_amount\": \"1000\",\n    \"maximum_amount\": \"50000\",\n    \"max_customer_declines\": 3,\n    \"max_orders_per_email\": 1,\n    \"max_upsell_declines\": 2,\n    \"fulfillment_delay\": 24,\n    \"category\": {\n      \"id\": 1,\n      \"name\": \"E-commerce\"\n    },\n    \"gateway_id\": 1,\n    \"payment_orchestrator_id\": null,\n    \"created_at\": \"2024-01-15T10:30:00.000Z\",\n    \"updated_at\": \"2024-01-20T14:45:00.000Z\",\n    \"offers_count\": 3,\n    \"upsells_count\": 2\n  }\n}\n\n</code></pre>\n<h2 id=\"example-response-multiple-campaigns\">Example Response (Multiple Campaigns)</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 1,\n      \"internal_id\": \"123\",\n      \"name\": \"Summer Sale Campaign\",\n      \"uuid\": \"550e8400-e29b-41d4-a716-446655440000\",\n      \"is_active\": true,\n      \"allowed_countries\": [\"US\", \"CA\", \"GB\"],\n      \"allowed_currencies\": [\"USD\", \"CAD\", \"GBP\"],\n      \"restrict_by_ip_country\": false,\n      \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\"],\n      \"allow_prepaid_cards\": true,\n      \"allow_virtual_cards\": false,\n      \"allow_international_cards\": true,\n      \"minimum_amount\": \"1000\",\n      \"maximum_amount\": \"50000\",\n      \"max_customer_declines\": 3,\n      \"max_orders_per_email\": null,\n      \"max_upsell_declines\": null,\n      \"fulfillment_delay\": 24,\n      \"category\": {\n        \"id\": 1,\n        \"name\": \"E-commerce\"\n      },\n      \"gateway_id\": 1,\n      \"payment_orchestrator_id\": null,\n      \"created_at\": \"2024-01-15T10:30:00.000Z\",\n      \"updated_at\": \"2024-01-20T14:45:00.000Z\",\n      \"offers_count\": 3,\n      \"upsells_count\": 2\n    }\n  ],\n  \"pagination\": {\n    \"total\": 1,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 1\n  }\n}\n\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns"],"host":["api","sparkcrm","io"],"query":[{"key":"is_active","value":"1"},{"key":"per_page","value":"10"},{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"05130008-cb41-47b9-87dc-9835df34f68c","name":"Search Campaign(s)","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/campaigns?is_active=1&per_page=10","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","campaigns"],"query":[{"key":"is_active","value":"1"},{"key":"per_page","value":"10"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.7"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 18 Jun 2025 17:43:12 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"32000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": 1,\n            \"name\": \"smartewatch.com\",\n            \"is_active\": true,\n            \"allowed_countries\": [\n                \"US\"\n            ],\n            \"allowed_currencies\": [\n                \"USD\"\n            ],\n            \"restrict_by_ip_country\": false,\n            \"allowed_card_brands\": [\n                \"visa\",\n                \"mastercard\",\n                \"discover\",\n                \"amex\"\n            ],\n            \"allow_prepaid_cards\": true,\n            \"allow_virtual_cards\": true,\n            \"allow_international_cards\": 1,\n            \"minimum_amount\": null,\n            \"maximum_amount\": null,\n            \"max_customer_declines\": 3,\n            \"max_orders_per_email\": null,\n            \"max_upsell_declines\": null,\n            \"fulfillment_delay\": 0,\n            \"category\": {\n                \"name\": \"Watches\"\n            },\n            \"offers_count\": 2,\n            \"upsells_count\": 1,\n            \"created_at\": \"2025-03-25T20:47:49.000000Z\",\n            \"updated_at\": \"2025-07-30T23:56:55.000000Z\"\n        }\n    ],\n    \"pagination\": {\n        \"total\": 1,\n        \"per_page\": 10,\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 1\n    }\n}"}],"_postman_id":"616648a1-9455-4c37-b54e-b1f57fa220f2"},{"name":"Create Campaign","id":"04ee7289-0528-8696-11b5-31ae0bc14d29","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Summer Skincare Funnel\",\n  \"is_active\": true,\n  \"allowed_countries\": [\"US\", \"CA\"],\n  \"allowed_currencies\": [\"USD\"],\n  \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\", \"discover\"],\n  \"allow_prepaid_cards\": true,\n  \"allow_virtual_cards\": true,\n  \"allow_international_cards\": true,\n  \"restrict_by_ip_country\": false,\n  \"minimum_amount\": 1.00,\n  \"maximum_amount\": 5000.00,\n  \"fulfillment_delay\": 0,\n  \"max_customer_declines\": 3,\n  \"max_orders_per_email\": 0,\n  \"max_upsell_declines\": 3,\n  \"max_reprocess_attempts_per_decline\": 2,\n  \"gateway_id\": 1,\n  \"payment_orchestrator_id\": 1,\n  \"decline_salvage_profile_id\": 4,\n  \"decline_salvage_disabled\": false,\n  \"campaign_category_id\": 2,\n  \"tax_enabled\": true,\n  \"bypass_email_validation\": false,\n  \"bypass_phone_validation\": false,\n  \"bypass_address_validation\": false\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns","description":"<h1 id=\"create-campaign\">Create Campaign</h1>\n<p><strong>Create a New Campaign</strong></p>\n<p>Create a new campaign for the authenticated account. Returns the detailed campaign object on success. Foreign-key fields (<code>gateway_id</code>, <code>payment_orchestrator_id</code>) are supplied as the team's internal ids, not database ids. When omitted, several fields fall back to system defaults (e.g. <code>allowed_countries</code> → <code>[\"US\"]</code>, <code>allowed_currencies</code> → <code>[\"USD\"]</code>, <code>allowed_card_brands</code> → <code>[\"visa\", \"mastercard\", \"amex\", \"discover\"]</code>, <code>is_active</code> → <code>true</code>, <code>max_customer_declines</code> → <code>3</code>).</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Campaign name. Must be unique within the team (excluding soft-deleted campaigns). Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether the campaign is active. Defaults to <code>true</code>.</td>\n</tr>\n<tr>\n<td><strong>allowed_countries</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of allowed ISO country codes. Defaults to <code>[\"US\"]</code>.</td>\n</tr>\n<tr>\n<td><strong>allowed_currencies</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of allowed currency codes. Defaults to <code>[\"USD\"]</code>.</td>\n</tr>\n<tr>\n<td><strong>allowed_card_brands</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of allowed card brands. Defaults to <code>[\"visa\", \"mastercard\", \"amex\", \"discover\"]</code>.</td>\n</tr>\n<tr>\n<td><strong>allow_prepaid_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether prepaid cards are allowed. Defaults to <code>true</code>.</td>\n</tr>\n<tr>\n<td><strong>allow_virtual_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether virtual cards are allowed. Defaults to <code>true</code>.</td>\n</tr>\n<tr>\n<td><strong>allow_international_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether international cards are allowed. Defaults to enabled.</td>\n</tr>\n<tr>\n<td><strong>restrict_by_ip_country</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Restrict checkout to customers whose IP geolocates to an allowed country.</td>\n</tr>\n<tr>\n<td><strong>minimum_amount</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Minimum order amount. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>maximum_amount</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Maximum order amount. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>fulfillment_delay</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Delay (in hours) before orders are released to fulfillment. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>max_customer_declines</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Maximum declined attempts allowed per customer before blocking. Minimum 0. Defaults to <code>3</code>.</td>\n</tr>\n<tr>\n<td><strong>max_orders_per_email</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Maximum number of orders allowed per email address. Minimum 0 (0 = unlimited).</td>\n</tr>\n<tr>\n<td><strong>max_upsell_declines</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Maximum declined upsell attempts allowed. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>max_reprocess_attempts_per_decline</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Maximum reprocess attempts allowed per decline. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>gateway_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Default gateway for the campaign, referenced by the team's internal gateway id. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>payment_orchestrator_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Payment router (orchestrator) for the campaign, referenced by the team's internal id. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>decline_salvage_profile_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Decline salvage profile id. Must reference a profile that belongs to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>decline_salvage_disabled</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Disable decline salvage for this campaign. When <code>false</code> (and no profile is set), the team's auto-apply default profile is attached automatically.</td>\n</tr>\n<tr>\n<td><strong>campaign_category_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Campaign category id. Must reference a category that belongs to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>tax_enabled</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Enable tax calculation for this campaign (requires an active tax provider to actually charge tax).</td>\n</tr>\n<tr>\n<td><strong>bypass_email_validation</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Skip email enrichment/validation at checkout.</td>\n</tr>\n<tr>\n<td><strong>bypass_phone_validation</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Skip phone enrichment/validation at checkout.</td>\n</tr>\n<tr>\n<td><strong>bypass_address_validation</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Skip address verification at checkout.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p><code>201 Created</code> — returns the full detailed campaign object identical to the <code>Get Campaign</code> response, plus:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Campaign created successfully\"\n}\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Unauthorized. Token lacks the necessary permissions.</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages). Also returned when a referenced <code>gateway_id</code> or <code>payment_orchestrator_id</code> does not exist for this account.</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"89413ab3-f7b4-b0ae-5f44-654632379fa8","name":"Create Campaign","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Summer Skincare Funnel\",\n  \"is_active\": true,\n  \"allowed_countries\": [\"US\", \"CA\"],\n  \"allowed_currencies\": [\"USD\"],\n  \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\", \"discover\"],\n  \"allow_prepaid_cards\": true,\n  \"allow_virtual_cards\": true,\n  \"allow_international_cards\": true,\n  \"restrict_by_ip_country\": false,\n  \"minimum_amount\": 1.00,\n  \"maximum_amount\": 5000.00,\n  \"fulfillment_delay\": 0,\n  \"max_customer_declines\": 3,\n  \"max_orders_per_email\": 0,\n  \"max_upsell_declines\": 3,\n  \"max_reprocess_attempts_per_decline\": 2,\n  \"gateway_id\": 1,\n  \"payment_orchestrator_id\": 1,\n  \"decline_salvage_profile_id\": 4,\n  \"decline_salvage_disabled\": false,\n  \"campaign_category_id\": 2,\n  \"tax_enabled\": true,\n  \"bypass_email_validation\": false,\n  \"bypass_phone_validation\": false,\n  \"bypass_address_validation\": false\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns","description":"# Create Campaign\n\n**Create a New Campaign**\n\nCreate a new campaign for the authenticated account. Returns the detailed campaign object on success. Foreign-key fields (`gateway_id`, `payment_orchestrator_id`) are supplied as the team's internal ids, not database ids. When omitted, several fields fall back to system defaults (e.g. `allowed_countries` → `[\"US\"]`, `allowed_currencies` → `[\"USD\"]`, `allowed_card_brands` → `[\"visa\", \"mastercard\", \"amex\", \"discover\"]`, `is_active` → `true`, `max_customer_declines` → `3`).\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| **name** | _**string (required)**_  <br>Campaign name. Must be unique within the team (excluding soft-deleted campaigns). Maximum 255 characters. |\n| **is_active** | _**boolean (optional)**_  <br>Whether the campaign is active. Defaults to `true`. |\n| **allowed_countries** | _**array (optional)**_  <br>List of allowed ISO country codes. Defaults to `[\"US\"]`. |\n| **allowed_currencies** | _**array (optional)**_  <br>List of allowed currency codes. Defaults to `[\"USD\"]`. |\n| **allowed_card_brands** | _**array (optional)**_  <br>List of allowed card brands. Defaults to `[\"visa\", \"mastercard\", \"amex\", \"discover\"]`. |\n| **allow_prepaid_cards** | _**boolean (optional)**_  <br>Whether prepaid cards are allowed. Defaults to `true`. |\n| **allow_virtual_cards** | _**boolean (optional)**_  <br>Whether virtual cards are allowed. Defaults to `true`. |\n| **allow_international_cards** | _**boolean (optional)**_  <br>Whether international cards are allowed. Defaults to enabled. |\n| **restrict_by_ip_country** | _**boolean (optional)**_  <br>Restrict checkout to customers whose IP geolocates to an allowed country. |\n| **minimum_amount** | _**number (optional)**_  <br>Minimum order amount. Minimum 0. |\n| **maximum_amount** | _**number (optional)**_  <br>Maximum order amount. Minimum 0. |\n| **fulfillment_delay** | _**integer (optional)**_  <br>Delay (in hours) before orders are released to fulfillment. Minimum 0. |\n| **max_customer_declines** | _**integer (optional)**_  <br>Maximum declined attempts allowed per customer before blocking. Minimum 0. Defaults to `3`. |\n| **max_orders_per_email** | _**integer (optional)**_  <br>Maximum number of orders allowed per email address. Minimum 0 (0 = unlimited). |\n| **max_upsell_declines** | _**integer (optional)**_  <br>Maximum declined upsell attempts allowed. Minimum 0. |\n| **max_reprocess_attempts_per_decline** | _**integer (optional)**_  <br>Maximum reprocess attempts allowed per decline. Minimum 0. |\n| **gateway_id** | _**integer (optional)**_  <br>Default gateway for the campaign, referenced by the team's internal gateway id. Must belong to the authenticated team. |\n| **payment_orchestrator_id** | _**integer (optional)**_  <br>Payment router (orchestrator) for the campaign, referenced by the team's internal id. Must belong to the authenticated team. |\n| **decline_salvage_profile_id** | _**integer (optional)**_  <br>Decline salvage profile id. Must reference a profile that belongs to the authenticated team. |\n| **decline_salvage_disabled** | _**boolean (optional)**_  <br>Disable decline salvage for this campaign. When `false` (and no profile is set), the team's auto-apply default profile is attached automatically. |\n| **campaign_category_id** | _**integer (optional)**_  <br>Campaign category id. Must reference a category that belongs to the authenticated team. |\n| **tax_enabled** | _**boolean (optional)**_  <br>Enable tax calculation for this campaign (requires an active tax provider to actually charge tax). |\n| **bypass_email_validation** | _**boolean (optional)**_  <br>Skip email enrichment/validation at checkout. |\n| **bypass_phone_validation** | _**boolean (optional)**_  <br>Skip phone enrichment/validation at checkout. |\n| **bypass_address_validation** | _**boolean (optional)**_  <br>Skip address verification at checkout. |\n\n## Response\n\n`201 Created` — returns the full detailed campaign object identical to the `Get Campaign` response, plus:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Campaign created successfully\"\n}\n```\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Unauthorized. Token lacks the necessary permissions. |\n| **422** | Validation error (returns `errors` object with field-level messages). Also returned when a referenced `gateway_id` or `payment_orchestrator_id` does not exist for this account. |"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"id\": 7,\n    \"name\": \"Summer Skincare Funnel\",\n    \"is_active\": true,\n    \"allowed_countries\": [\"US\", \"CA\"],\n    \"allowed_currencies\": [\"USD\"],\n    \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\", \"discover\"],\n    \"allow_prepaid_cards\": true,\n    \"allow_virtual_cards\": true,\n    \"allow_international_cards\": true,\n    \"restrict_by_ip_country\": false,\n    \"minimum_amount\": \"1.00\",\n    \"maximum_amount\": \"5000.00\",\n    \"max_customer_declines\": 3,\n    \"max_orders_per_email\": 0,\n    \"max_upsell_declines\": 3,\n    \"fulfillment_delay\": 0,\n    \"gateway_id\": 1,\n    \"payment_orchestrator_id\": 1,\n    \"category\": {\n      \"name\": \"Skincare\"\n    },\n    \"offers_count\": 0,\n    \"upsells_count\": 0,\n    \"created_at\": \"2026-06-16T14:05:22.000000Z\",\n    \"updated_at\": \"2026-06-16T14:05:22.000000Z\",\n    \"uuid\": \"9f1c2d4e-7a8b-4c3d-9e2f-1a2b3c4d5e6f\",\n    \"campaign_category_id\": 2,\n    \"decline_salvage_profile_id\": 4,\n    \"decline_salvage_disabled\": false,\n    \"tax_enabled\": true,\n    \"max_reprocess_attempts_per_decline\": 2,\n    \"bypass_email_validation\": false,\n    \"bypass_phone_validation\": false,\n    \"bypass_address_validation\": false\n  },\n  \"success\": true,\n  \"message\": \"Campaign created successfully\"\n}"}],"_postman_id":"04ee7289-0528-8696-11b5-31ae0bc14d29"},{"name":"Get Campaign","id":"32897bd4-8240-80ee-b56b-f2756a099021","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/1","description":"<h1 id=\"get-campaign\">Get Campaign</h1>\n<p><strong>Retrieve a Single Campaign</strong></p>\n<p>Retrieve a single campaign by its identifier (the team's internal campaign id). Database ids are never exposed. The response is the detailed campaign object, including the salvage, tax, and validation-bypass settings.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/campaigns/1\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.view</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>identifier</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal campaign id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />Campaign object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Campaign identifier (team's internal id)</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Campaign name</td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the campaign is active</td>\n</tr>\n<tr>\n<td><strong>data.allowed_countries</strong></td>\n<td><strong>array</strong>  <br />List of allowed ISO country codes</td>\n</tr>\n<tr>\n<td><strong>data.allowed_currencies</strong></td>\n<td><strong>array</strong>  <br />List of allowed currency codes</td>\n</tr>\n<tr>\n<td><strong>data.allowed_card_brands</strong></td>\n<td><strong>array</strong>  <br />List of allowed card brands</td>\n</tr>\n<tr>\n<td><strong>data.allow_prepaid_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether prepaid cards are allowed</td>\n</tr>\n<tr>\n<td><strong>data.allow_virtual_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether virtual cards are allowed</td>\n</tr>\n<tr>\n<td><strong>data.allow_international_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether international cards are allowed</td>\n</tr>\n<tr>\n<td><strong>data.restrict_by_ip_country</strong></td>\n<td><strong>boolean</strong>  <br />Whether checkout is restricted by IP country</td>\n</tr>\n<tr>\n<td><strong>data.minimum_amount</strong></td>\n<td><strong>string</strong>  <br />Minimum order amount (2-decimal string)</td>\n</tr>\n<tr>\n<td><strong>data.maximum_amount</strong></td>\n<td><strong>string</strong>  <br />Maximum order amount (2-decimal string)</td>\n</tr>\n<tr>\n<td><strong>data.max_customer_declines</strong></td>\n<td><strong>integer</strong>  <br />Maximum declined attempts allowed per customer</td>\n</tr>\n<tr>\n<td><strong>data.max_orders_per_email</strong></td>\n<td><strong>integer</strong>  <br />Maximum orders allowed per email address</td>\n</tr>\n<tr>\n<td><strong>data.max_upsell_declines</strong></td>\n<td><strong>integer</strong>  <br />Maximum declined upsell attempts allowed</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_delay</strong></td>\n<td><strong>integer</strong>  <br />Delay (in hours) before orders release to fulfillment</td>\n</tr>\n<tr>\n<td><strong>data.gateway_id</strong></td>\n<td><strong>integer</strong>  <br />Default gateway, as the team's internal gateway id (null if unset)</td>\n</tr>\n<tr>\n<td><strong>data.payment_orchestrator_id</strong></td>\n<td><strong>integer</strong>  <br />Payment router, as the team's internal id (null if unset)</td>\n</tr>\n<tr>\n<td><strong>data.category</strong></td>\n<td><strong>object</strong>  <br />Linked campaign category, e.g. <code>{ \"name\": \"Skincare\" }</code> (null if unset)</td>\n</tr>\n<tr>\n<td><strong>data.offers_count</strong></td>\n<td><strong>integer</strong>  <br />Count of active offers on the campaign</td>\n</tr>\n<tr>\n<td><strong>data.upsells_count</strong></td>\n<td><strong>integer</strong>  <br />Count of active upsells on the campaign</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the campaign was created</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the campaign was last updated</td>\n</tr>\n<tr>\n<td><strong>data.uuid</strong></td>\n<td><strong>string</strong>  <br />Campaign UUID</td>\n</tr>\n<tr>\n<td><strong>data.campaign_category_id</strong></td>\n<td><strong>integer</strong>  <br />Linked campaign category id</td>\n</tr>\n<tr>\n<td><strong>data.decline_salvage_profile_id</strong></td>\n<td><strong>integer</strong>  <br />Associated decline salvage profile id, if any</td>\n</tr>\n<tr>\n<td><strong>data.decline_salvage_disabled</strong></td>\n<td><strong>boolean</strong>  <br />Whether decline salvage is disabled for this campaign</td>\n</tr>\n<tr>\n<td><strong>data.tax_enabled</strong></td>\n<td><strong>boolean</strong>  <br />Whether tax calculation is enabled</td>\n</tr>\n<tr>\n<td><strong>data.max_reprocess_attempts_per_decline</strong></td>\n<td><strong>integer</strong>  <br />Maximum reprocess attempts allowed per decline</td>\n</tr>\n<tr>\n<td><strong>data.bypass_email_validation</strong></td>\n<td><strong>boolean</strong>  <br />Whether email validation is bypassed at checkout</td>\n</tr>\n<tr>\n<td><strong>data.bypass_phone_validation</strong></td>\n<td><strong>boolean</strong>  <br />Whether phone validation is bypassed at checkout</td>\n</tr>\n<tr>\n<td><strong>data.bypass_address_validation</strong></td>\n<td><strong>boolean</strong>  <br />Whether address validation is bypassed at checkout</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Unauthorized. Token lacks the necessary permissions.</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Campaign not found</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","1"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"cd88481b-ed6f-49da-b216-cfd4fe3c4a2d","name":"Get Campaign","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/1","description":"# Get Campaign\n\n**Retrieve a Single Campaign**\n\nRetrieve a single campaign by its identifier (the team's internal campaign id). Database ids are never exposed. The response is the detailed campaign object, including the salvage, tax, and validation-bypass settings.\n\n## Example\n\n```\nGET https://api.sparkcrm.io/v1/campaigns/1\n```\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.view`\n\n## Path Variables\n\n| Variable | Description |\n| --- | --- |\n| **identifier** | _**integer (required)**_  <br>The team's internal campaign id. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **data** | **object**  <br>Campaign object |\n| **data.id** | **integer**  <br>Campaign identifier (team's internal id) |\n| **data.name** | **string**  <br>Campaign name |\n| **data.is_active** | **boolean**  <br>Whether the campaign is active |\n| **data.allowed_countries** | **array**  <br>List of allowed ISO country codes |\n| **data.allowed_currencies** | **array**  <br>List of allowed currency codes |\n| **data.allowed_card_brands** | **array**  <br>List of allowed card brands |\n| **data.allow_prepaid_cards** | **boolean**  <br>Whether prepaid cards are allowed |\n| **data.allow_virtual_cards** | **boolean**  <br>Whether virtual cards are allowed |\n| **data.allow_international_cards** | **boolean**  <br>Whether international cards are allowed |\n| **data.restrict_by_ip_country** | **boolean**  <br>Whether checkout is restricted by IP country |\n| **data.minimum_amount** | **string**  <br>Minimum order amount (2-decimal string) |\n| **data.maximum_amount** | **string**  <br>Maximum order amount (2-decimal string) |\n| **data.max_customer_declines** | **integer**  <br>Maximum declined attempts allowed per customer |\n| **data.max_orders_per_email** | **integer**  <br>Maximum orders allowed per email address |\n| **data.max_upsell_declines** | **integer**  <br>Maximum declined upsell attempts allowed |\n| **data.fulfillment_delay** | **integer**  <br>Delay (in hours) before orders release to fulfillment |\n| **data.gateway_id** | **integer**  <br>Default gateway, as the team's internal gateway id (null if unset) |\n| **data.payment_orchestrator_id** | **integer**  <br>Payment router, as the team's internal id (null if unset) |\n| **data.category** | **object**  <br>Linked campaign category, e.g. `{ \"name\": \"Skincare\" }` (null if unset) |\n| **data.offers_count** | **integer**  <br>Count of active offers on the campaign |\n| **data.upsells_count** | **integer**  <br>Count of active upsells on the campaign |\n| **data.created_at** | **string**  <br>ISO 8601 timestamp when the campaign was created |\n| **data.updated_at** | **string**  <br>ISO 8601 timestamp when the campaign was last updated |\n| **data.uuid** | **string**  <br>Campaign UUID |\n| **data.campaign_category_id** | **integer**  <br>Linked campaign category id |\n| **data.decline_salvage_profile_id** | **integer**  <br>Associated decline salvage profile id, if any |\n| **data.decline_salvage_disabled** | **boolean**  <br>Whether decline salvage is disabled for this campaign |\n| **data.tax_enabled** | **boolean**  <br>Whether tax calculation is enabled |\n| **data.max_reprocess_attempts_per_decline** | **integer**  <br>Maximum reprocess attempts allowed per decline |\n| **data.bypass_email_validation** | **boolean**  <br>Whether email validation is bypassed at checkout |\n| **data.bypass_phone_validation** | **boolean**  <br>Whether phone validation is bypassed at checkout |\n| **data.bypass_address_validation** | **boolean**  <br>Whether address validation is bypassed at checkout |\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Unauthorized. Token lacks the necessary permissions. |\n| **404** | Campaign not found |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"Summer Skincare Funnel\",\n    \"is_active\": true,\n    \"allowed_countries\": [\"US\", \"CA\"],\n    \"allowed_currencies\": [\"USD\"],\n    \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\", \"discover\"],\n    \"allow_prepaid_cards\": true,\n    \"allow_virtual_cards\": true,\n    \"allow_international_cards\": true,\n    \"restrict_by_ip_country\": false,\n    \"minimum_amount\": \"1.00\",\n    \"maximum_amount\": \"5000.00\",\n    \"max_customer_declines\": 3,\n    \"max_orders_per_email\": 0,\n    \"max_upsell_declines\": 3,\n    \"fulfillment_delay\": 0,\n    \"gateway_id\": 1,\n    \"payment_orchestrator_id\": 1,\n    \"category\": {\n      \"name\": \"Skincare\"\n    },\n    \"offers_count\": 3,\n    \"upsells_count\": 2,\n    \"created_at\": \"2026-06-16T14:05:22.000000Z\",\n    \"updated_at\": \"2026-06-16T14:05:22.000000Z\",\n    \"uuid\": \"9f1c2d4e-7a8b-4c3d-9e2f-1a2b3c4d5e6f\",\n    \"campaign_category_id\": 2,\n    \"decline_salvage_profile_id\": 4,\n    \"decline_salvage_disabled\": false,\n    \"tax_enabled\": true,\n    \"max_reprocess_attempts_per_decline\": 2,\n    \"bypass_email_validation\": false,\n    \"bypass_phone_validation\": false,\n    \"bypass_address_validation\": false\n  },\n  \"success\": true\n}"}],"_postman_id":"32897bd4-8240-80ee-b56b-f2756a099021"},{"name":"Update Campaign","id":"71bef619-c4d7-3ac4-746c-37c32ae39434","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Summer Skincare Funnel (v2)\",\n  \"is_active\": false,\n  \"allowed_countries\": [\"US\"],\n  \"maximum_amount\": 7500.00,\n  \"gateway_id\": 2,\n  \"tax_enabled\": false\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/1","description":"<h1 id=\"update-campaign\">Update Campaign</h1>\n<p><strong>Partially Update a Campaign</strong></p>\n<p>Update mutable fields on a campaign. All fields are optional; only validated fields that are present in the request body will be saved. The identifier in the URL is the team's internal campaign id. Foreign-key fields (<code>gateway_id</code>, <code>payment_orchestrator_id</code>) are supplied as the team's internal ids and must belong to the authenticated team.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:campaigns.update</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>identifier</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal campaign id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional. Only the fields included will be updated.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Campaign name. Must be unique within the team (excluding soft-deleted campaigns). Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether the campaign is active.</td>\n</tr>\n<tr>\n<td><strong>allowed_countries</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of allowed ISO country codes.</td>\n</tr>\n<tr>\n<td><strong>allowed_currencies</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of allowed currency codes.</td>\n</tr>\n<tr>\n<td><strong>allowed_card_brands</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of allowed card brands.</td>\n</tr>\n<tr>\n<td><strong>allow_prepaid_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>allow_virtual_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>allow_international_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>restrict_by_ip_country</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>minimum_amount</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>maximum_amount</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>fulfillment_delay</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>max_customer_declines</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>max_orders_per_email</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>max_upsell_declines</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>max_reprocess_attempts_per_decline</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>gateway_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Default gateway, referenced by the team's internal gateway id. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>payment_orchestrator_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Payment router, referenced by the team's internal id. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>decline_salvage_profile_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Decline salvage profile id. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>decline_salvage_disabled</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>campaign_category_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Campaign category id. Must belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><strong>tax_enabled</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>bypass_email_validation</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>bypass_phone_validation</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>bypass_address_validation</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p><code>200 OK</code> — returns the updated detailed campaign object identical to the <code>Get Campaign</code> response, plus:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Campaign updated successfully\"\n}\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Unauthorized. Token lacks the necessary permissions.</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Campaign not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages). Also returned when a referenced <code>gateway_id</code> or <code>payment_orchestrator_id</code> does not exist for this account.</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","1"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"a416c4ba-8787-7bd6-8695-429f065f0c65","name":"Update Campaign","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Summer Skincare Funnel (v2)\",\n  \"is_active\": false,\n  \"allowed_countries\": [\"US\"],\n  \"maximum_amount\": 7500.00,\n  \"gateway_id\": 2,\n  \"tax_enabled\": false\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/campaigns/1","description":"# Update Campaign\n\n**Partially Update a Campaign**\n\nUpdate mutable fields on a campaign. All fields are optional; only validated fields that are present in the request body will be saved. The identifier in the URL is the team's internal campaign id. Foreign-key fields (`gateway_id`, `payment_orchestrator_id`) are supplied as the team's internal ids and must belong to the authenticated team.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:campaigns.update`\n\n## Path Variables\n\n| Variable | Description |\n| --- | --- |\n| **identifier** | _**integer (required)**_  <br>The team's internal campaign id. |\n\n## Request Body\n\nAll fields are optional. Only the fields included will be updated.\n\n| Request Field | Description |\n| --- | --- |\n| **name** | _**string (optional)**_  <br>Campaign name. Must be unique within the team (excluding soft-deleted campaigns). Maximum 255 characters. |\n| **is_active** | _**boolean (optional)**_  <br>Whether the campaign is active. |\n| **allowed_countries** | _**array (optional)**_  <br>List of allowed ISO country codes. |\n| **allowed_currencies** | _**array (optional)**_  <br>List of allowed currency codes. |\n| **allowed_card_brands** | _**array (optional)**_  <br>List of allowed card brands. |\n| **allow_prepaid_cards** | _**boolean (optional)**_ |\n| **allow_virtual_cards** | _**boolean (optional)**_ |\n| **allow_international_cards** | _**boolean (optional)**_ |\n| **restrict_by_ip_country** | _**boolean (optional)**_ |\n| **minimum_amount** | _**number (optional)**_  <br>Minimum 0. |\n| **maximum_amount** | _**number (optional)**_  <br>Minimum 0. |\n| **fulfillment_delay** | _**integer (optional)**_  <br>Minimum 0. |\n| **max_customer_declines** | _**integer (optional)**_  <br>Minimum 0. |\n| **max_orders_per_email** | _**integer (optional)**_  <br>Minimum 0. |\n| **max_upsell_declines** | _**integer (optional)**_  <br>Minimum 0. |\n| **max_reprocess_attempts_per_decline** | _**integer (optional)**_  <br>Minimum 0. |\n| **gateway_id** | _**integer (optional)**_  <br>Default gateway, referenced by the team's internal gateway id. Must belong to the authenticated team. |\n| **payment_orchestrator_id** | _**integer (optional)**_  <br>Payment router, referenced by the team's internal id. Must belong to the authenticated team. |\n| **decline_salvage_profile_id** | _**integer (optional)**_  <br>Decline salvage profile id. Must belong to the authenticated team. |\n| **decline_salvage_disabled** | _**boolean (optional)**_ |\n| **campaign_category_id** | _**integer (optional)**_  <br>Campaign category id. Must belong to the authenticated team. |\n| **tax_enabled** | _**boolean (optional)**_ |\n| **bypass_email_validation** | _**boolean (optional)**_ |\n| **bypass_phone_validation** | _**boolean (optional)**_ |\n| **bypass_address_validation** | _**boolean (optional)**_ |\n\n## Response\n\n`200 OK` — returns the updated detailed campaign object identical to the `Get Campaign` response, plus:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Campaign updated successfully\"\n}\n```\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Unauthorized. Token lacks the necessary permissions. |\n| **404** | Campaign not found |\n| **422** | Validation error (returns `errors` object with field-level messages). Also returned when a referenced `gateway_id` or `payment_orchestrator_id` does not exist for this account. |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"Summer Skincare Funnel (v2)\",\n    \"is_active\": false,\n    \"allowed_countries\": [\"US\"],\n    \"allowed_currencies\": [\"USD\"],\n    \"allowed_card_brands\": [\"visa\", \"mastercard\", \"amex\", \"discover\"],\n    \"allow_prepaid_cards\": true,\n    \"allow_virtual_cards\": true,\n    \"allow_international_cards\": true,\n    \"restrict_by_ip_country\": false,\n    \"minimum_amount\": \"1.00\",\n    \"maximum_amount\": \"7500.00\",\n    \"max_customer_declines\": 3,\n    \"max_orders_per_email\": 0,\n    \"max_upsell_declines\": 3,\n    \"fulfillment_delay\": 0,\n    \"gateway_id\": 2,\n    \"payment_orchestrator_id\": 1,\n    \"category\": {\n      \"name\": \"Skincare\"\n    },\n    \"offers_count\": 3,\n    \"upsells_count\": 2,\n    \"created_at\": \"2026-06-16T14:05:22.000000Z\",\n    \"updated_at\": \"2026-06-16T15:11:48.000000Z\",\n    \"uuid\": \"9f1c2d4e-7a8b-4c3d-9e2f-1a2b3c4d5e6f\",\n    \"campaign_category_id\": 2,\n    \"decline_salvage_profile_id\": 4,\n    \"decline_salvage_disabled\": false,\n    \"tax_enabled\": false,\n    \"max_reprocess_attempts_per_decline\": 2,\n    \"bypass_email_validation\": false,\n    \"bypass_phone_validation\": false,\n    \"bypass_address_validation\": false\n  },\n  \"success\": true,\n  \"message\": \"Campaign updated successfully\"\n}"}],"_postman_id":"71bef619-c4d7-3ac4-746c-37c32ae39434"}],"id":"97b4bd28-c525-450b-9715-409493fbf0db","_postman_id":"97b4bd28-c525-450b-9715-409493fbf0db","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Alternative Payments","item":[{"name":"Get Alternative Payment","id":"b6505325-85ab-4c10-9c9b-ef78d995a22b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/alternative-payments/{{id}}","description":"<h1 id=\"get-alternative-payment\">Get Alternative Payment</h1>\n<p>Retrieve a specific alternative payment method by its ID.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>id</td>\n<td><strong>integer (required, URL parameter)</strong>  <br />The ID of the alternative payment method. This is the same <code>id</code> returned in the list endpoint</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />The alternative payment method object</td>\n</tr>\n<tr>\n<td>data.id</td>\n<td><strong>integer</strong>  <br />Internal identifier for the payment method</td>\n</tr>\n<tr>\n<td>data.name</td>\n<td><strong>string</strong>  <br />Display name for the payment method</td>\n</tr>\n<tr>\n<td>data.payment_type</td>\n<td><strong>string</strong>  <br />Payment type identifier (e.g., <code>zelle</code>, <code>paypal_wallet</code>, <code>cash_app</code>)</td>\n</tr>\n<tr>\n<td>data.payment_type_label</td>\n<td><strong>string</strong>  <br />Human-readable label for the payment type</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Current status: <code>active</code>, <code>inactive</code>, or <code>testing</code></td>\n</tr>\n<tr>\n<td>data.supports_refunds</td>\n<td><strong>boolean</strong>  <br />Whether this payment method supports refunds</td>\n</tr>\n<tr>\n<td>data.supports_voids</td>\n<td><strong>boolean</strong>  <br />Whether this payment method supports voids</td>\n</tr>\n<tr>\n<td>data.supports_upsells</td>\n<td><strong>boolean</strong>  <br />Whether this payment method supports seamless upsells</td>\n</tr>\n<tr>\n<td>data.test_mode</td>\n<td><strong>boolean</strong>  <br />Whether the payment method is in test/sandbox mode</td>\n</tr>\n<tr>\n<td>data.requires_redirect</td>\n<td><strong>boolean</strong>  <br />Whether the payment flow requires redirecting the customer</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date and time when the payment method was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the payment method was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example-request\">Example Request</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/alternative-payments/2\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h2 id=\"example-response\">Example Response</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"id\": 2,\n    \"name\": \"Zelle Payments\",\n    \"payment_type\": \"zelle\",\n    \"payment_type_label\": \"Zelle\",\n    \"status\": \"active\",\n    \"supports_refunds\": false,\n    \"supports_voids\": false,\n    \"supports_upsells\": false,\n    \"test_mode\": false,\n    \"requires_redirect\": false,\n    \"created_at\": \"2026-02-12T11:00:00.000000Z\",\n    \"updated_at\": \"2026-02-12T11:00:00.000000Z\"\n  }\n}\n\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","alternative-payments","{{id}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"363efb9d-34d2-434e-b68c-616b21062431","name":"Get Alternative Payment","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/alternative-payments/{{id}}","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","alternative-payments","{{id}}"],"query":[{"key":"per_page","value":"10","disabled":true}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.7"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 18 Jun 2025 17:43:12 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"32000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"id\": 2,\n    \"name\": \"Zelle Payments\",\n    \"payment_type\": \"zelle\",\n    \"payment_type_label\": \"Zelle\",\n    \"status\": \"active\",\n    \"supports_refunds\": false,\n    \"supports_voids\": false,\n    \"supports_upsells\": false,\n    \"test_mode\": false,\n    \"requires_redirect\": false,\n    \"created_at\": \"2026-02-12T11:00:00.000000Z\",\n    \"updated_at\": \"2026-02-12T11:00:00.000000Z\"\n  }\n}"}],"_postman_id":"b6505325-85ab-4c10-9c9b-ef78d995a22b"},{"name":"List Alternative Payments","id":"aa098d7a-1059-4cb9-822c-d40f268b3fb8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/alternative-payments?payment_type=paypal_wallet&status=active&search=paypal&per_page=10","description":"<h1 id=\"list-alternative-payments\">List Alternative Payments</h1>\n<p>Retrieve a paginated list of alternative payment methods configured for your account. Use the <code>id</code> field from the response as the <code>payment[external_payment_id]</code> when creating orders.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>payment_type</td>\n<td><em>string (optional)</em>  <br />Filter by payment type. Allowed values: <code>paypal_wallet</code>, <code>external</code>, <code>cash_app</code>, <code>zelle</code>, <code>venmo</code>, <code>crypto</code>, <code>bank_transfer</code></td>\n</tr>\n<tr>\n<td>status</td>\n<td><em>string (optional)</em>  <br />Filter by status. Allowed values: <code>active</code>, <code>inactive</code>, <code>testing</code></td>\n</tr>\n<tr>\n<td>search</td>\n<td><em>string (optional)</em>  <br />Search by name. Performs partial matching. Maximum length: 255 characters</td>\n</tr>\n<tr>\n<td>per_page</td>\n<td><em>integer (optional)</em>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>array</strong>  <br />Array of alternative payment method objects</td>\n</tr>\n<tr>\n<td>data.id</td>\n<td><strong>integer</strong>  <br />Internal identifier for the payment method. Use this value as <code>payment[external_payment_id]</code> when creating orders</td>\n</tr>\n<tr>\n<td>data.name</td>\n<td><strong>string</strong>  <br />Display name for the payment method</td>\n</tr>\n<tr>\n<td>data.payment_type</td>\n<td><strong>string</strong>  <br />Payment type identifier (e.g., <code>zelle</code>, <code>paypal_wallet</code>, <code>cash_app</code>)</td>\n</tr>\n<tr>\n<td>data.payment_type_label</td>\n<td><strong>string</strong>  <br />Human-readable label for the payment type (e.g., \"Zelle\", \"PayPal Wallet\", \"Cash App\")</td>\n</tr>\n<tr>\n<td>data.status</td>\n<td><strong>string</strong>  <br />Current status: <code>active</code>, <code>inactive</code>, or <code>testing</code></td>\n</tr>\n<tr>\n<td>data.supports_refunds</td>\n<td><strong>boolean</strong>  <br />Whether this payment method supports refunds</td>\n</tr>\n<tr>\n<td>data.supports_voids</td>\n<td><strong>boolean</strong>  <br />Whether this payment method supports voids</td>\n</tr>\n<tr>\n<td>data.supports_upsells</td>\n<td><strong>boolean</strong>  <br />Whether this payment method supports seamless upsells</td>\n</tr>\n<tr>\n<td>data.test_mode</td>\n<td><strong>boolean</strong>  <br />Whether the payment method is in test/sandbox mode</td>\n</tr>\n<tr>\n<td>data.requires_redirect</td>\n<td><strong>boolean</strong>  <br />Whether the payment flow requires redirecting the customer (e.g., PayPal Wallet)</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date and time when the payment method was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the payment method was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>pagination</td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td>pagination.total</td>\n<td><strong>integer</strong>  <br />Total number of payment methods matching the search criteria</td>\n</tr>\n<tr>\n<td>pagination.per_page</td>\n<td><strong>integer</strong>  <br />Number of results displayed per page</td>\n</tr>\n<tr>\n<td>pagination.current_page</td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td>pagination.last_page</td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td>pagination.from</td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td>pagination.to</td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example-requests\">Example Requests</h2>\n<h3 id=\"get-all-alternative-payments-paginated\">Get All Alternative Payments (Paginated)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/alternative-payments\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h3 id=\"filter-by-payment-type\">Filter by Payment Type</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/alternative-payments?payment_type=paypal_wallet\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h3 id=\"filter-by-status\">Filter by Status</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/alternative-payments?status=active\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h3 id=\"search-by-name\">Search by Name</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/alternative-payments?search=zelle\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h3 id=\"combined-filters\">Combined Filters</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/alternative-payments?status=active&amp;payment_type=external&amp;per_page=10\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n\n</code></pre>\n<h2 id=\"example-response\">Example Response</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"PayPal Business\",\n      \"payment_type\": \"paypal_wallet\",\n      \"payment_type_label\": \"PayPal Wallet\",\n      \"status\": \"active\",\n      \"supports_refunds\": true,\n      \"supports_voids\": true,\n      \"supports_upsells\": true,\n      \"test_mode\": false,\n      \"requires_redirect\": true,\n      \"created_at\": \"2026-02-12T10:00:00.000000Z\",\n      \"updated_at\": \"2026-02-12T13:33:00.000000Z\"\n    },\n    {\n      \"id\": 2,\n      \"name\": \"Zelle Payments\",\n      \"payment_type\": \"zelle\",\n      \"payment_type_label\": \"Zelle\",\n      \"status\": \"active\",\n      \"supports_refunds\": false,\n      \"supports_voids\": false,\n      \"supports_upsells\": false,\n      \"test_mode\": false,\n      \"requires_redirect\": false,\n      \"created_at\": \"2026-02-12T11:00:00.000000Z\",\n      \"updated_at\": \"2026-02-12T11:00:00.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 2,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 2\n  }\n}\n\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","alternative-payments"],"host":["api","sparkcrm","io"],"query":[{"key":"payment_type","value":"paypal_wallet"},{"key":"status","value":"active"},{"key":"search","value":"paypal"},{"key":"per_page","value":"10"},{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"4ce263d9-58fe-4078-b6be-e47d8d048066","name":"List Alternative Payments","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/alternative-payments?payment_type=paypal_wallet&status=active&search=paypal&per_page=10","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","alternative-payments"],"query":[{"key":"payment_type","value":"paypal_wallet"},{"key":"status","value":"active"},{"key":"search","value":"paypal"},{"key":"per_page","value":"10"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.7"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 18 Jun 2025 17:43:12 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"32000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"PayPal Business\",\n      \"payment_type\": \"paypal_wallet\",\n      \"payment_type_label\": \"PayPal Wallet\",\n      \"status\": \"active\",\n      \"supports_refunds\": true,\n      \"supports_voids\": true,\n      \"supports_upsells\": true,\n      \"test_mode\": false,\n      \"requires_redirect\": true,\n      \"created_at\": \"2026-02-12T10:00:00.000000Z\",\n      \"updated_at\": \"2026-02-12T13:33:00.000000Z\"\n    },\n    {\n      \"id\": 2,\n      \"name\": \"Zelle Payments\",\n      \"payment_type\": \"zelle\",\n      \"payment_type_label\": \"Zelle\",\n      \"status\": \"active\",\n      \"supports_refunds\": false,\n      \"supports_voids\": false,\n      \"supports_upsells\": false,\n      \"test_mode\": false,\n      \"requires_redirect\": false,\n      \"created_at\": \"2026-02-12T11:00:00.000000Z\",\n      \"updated_at\": \"2026-02-12T11:00:00.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 2,\n    \"per_page\": 10,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 2\n  }\n}\n\n"}],"_postman_id":"aa098d7a-1059-4cb9-822c-d40f268b3fb8"}],"id":"7d9f025b-bc73-4abd-b6ac-840dc8cda06b","_postman_id":"7d9f025b-bc73-4abd-b6ac-840dc8cda06b","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Coupons","item":[{"name":"Search Coupons","id":"06606fab-1b95-4031-bbeb-b391dcdf02b4","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/coupons","description":"<h1 id=\"listsearch-coupons\">List/Search Coupons</h1>\n<p>Retrieve a paginated list of coupons with optional filtering and search capabilities.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>code</td>\n<td><strong>string (optional)</strong>  <br />Filter by specific coupon code. If provided, returns a single coupon instead of a list</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><strong>boolean (optional)</strong>  <br />Filter by active status (true/false)</td>\n</tr>\n<tr>\n<td>type</td>\n<td><strong>string (optional)</strong>  <br />Filter by coupon type (percentage, fixed_amount, free_shipping, buy_x_get_y, fixed_price)</td>\n</tr>\n<tr>\n<td>search</td>\n<td><strong>string (optional)</strong>  <br />Search across coupon name, code, and description</td>\n</tr>\n<tr>\n<td>per_page</td>\n<td><strong>integer (optional)</strong>  <br />Number of results per page (1-100, default: 15)</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>array</strong>  <br />Array of coupon objects matching the search criteria</td>\n</tr>\n<tr>\n<td>data[].code</td>\n<td><strong>string</strong>  <br />Unique coupon code</td>\n</tr>\n<tr>\n<td>data[].name</td>\n<td><strong>string</strong>  <br />Display name of the coupon</td>\n</tr>\n<tr>\n<td>data[].description</td>\n<td><strong>string</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>data[].type</td>\n<td><strong>string</strong>  <br />Type of discount (percentage, fixed_amount, free_shipping, buy_x_get_y, fixed_price)</td>\n</tr>\n<tr>\n<td>data[].is_active</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently active</td>\n</tr>\n<tr>\n<td>data[].discount_amount</td>\n<td><strong>string</strong>  <br />Discount value (percentage or fixed amount)</td>\n</tr>\n<tr>\n<td>data[].minimum_purchase</td>\n<td><strong>number/null</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>data[].maximum_discount</td>\n<td><strong>number/null</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>data[].usage_limit_per_coupon</td>\n<td><strong>integer/null</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>data[].usage_limit_per_customer</td>\n<td><strong>integer/null</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>data[].total_uses</td>\n<td><strong>integer</strong>  <br />Current number of times the coupon has been used</td>\n</tr>\n<tr>\n<td>data[].starts_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon becomes valid (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data[].expires_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon expires (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data[].individual_use_only</td>\n<td><strong>boolean</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>data[].allowed_products</td>\n<td><strong>array</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data[].excluded_products</td>\n<td><strong>array</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data[].allowed_categories</td>\n<td><strong>array</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data[].excluded_categories</td>\n<td><strong>array</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data[].allowed_countries</td>\n<td><strong>array</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>data[].excluded_countries</td>\n<td><strong>array</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>data[].allowed_emails</td>\n<td><strong>array</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>data[].first_time_customer_only</td>\n<td><strong>boolean</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>data[].is_valid</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently valid for use</td>\n</tr>\n<tr>\n<td>data[].is_expired</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has expired</td>\n</tr>\n<tr>\n<td>data[].has_reached_usage_limit</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has reached its usage limit</td>\n</tr>\n<tr>\n<td>data[].provider</td>\n<td><strong>object/null</strong>  <br />CS provider team information if coupon was created by a provider</td>\n</tr>\n<tr>\n<td>data[].created_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data[].updated_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>pagination</td>\n<td><strong>object</strong>  <br />Pagination metadata</td>\n</tr>\n<tr>\n<td>pagination.total</td>\n<td><strong>integer</strong>  <br />Total number of coupons</td>\n</tr>\n<tr>\n<td>pagination.per_page</td>\n<td><strong>integer</strong>  <br />Results per page</td>\n</tr>\n<tr>\n<td>pagination.current_page</td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td>pagination.last_page</td>\n<td><strong>integer</strong>  <br />Last page number</td>\n</tr>\n<tr>\n<td>pagination.from</td>\n<td><strong>integer</strong>  <br />Starting result number</td>\n</tr>\n<tr>\n<td>pagination.to</td>\n<td><strong>integer</strong>  <br />Ending result number</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","coupons"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"key":"code","value":"SUMMER2025"},{"disabled":true,"key":"is_active","value":"true"},{"disabled":true,"key":"type","value":"percentage"},{"disabled":true,"key":"search","value":"summer"},{"disabled":true,"key":"per_page","value":"15"},{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"2677291d-2b10-4bb8-903f-fa3f2fa3834b","name":"Search Coupons Success","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/coupons","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","coupons"],"query":[{"key":" code","value":" SUMMER2025","type":"text","disabled":true},{"key":" is_active","value":" true","type":"text","disabled":true},{"key":" type","value":" percentage","type":"text","disabled":true},{"key":" search","value":" summer","type":"text","disabled":true},{"key":" per_page","value":" 15","type":"text","disabled":true}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.11"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 21 Aug 2025 02:38:24 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"code\": \"TEST10\",\n            \"name\": \"TEST10\",\n            \"description\": \"\",\n            \"type\": \"fixed_amount\",\n            \"is_active\": true,\n            \"discount_amount\": \"10.00\",\n            \"minimum_purchase\": null,\n            \"maximum_discount\": null,\n            \"usage_limit_per_coupon\": null,\n            \"usage_limit_per_customer\": null,\n            \"total_uses\": 2,\n            \"starts_at\": null,\n            \"expires_at\": null,\n            \"individual_use_only\": false,\n            \"allowed_products\": [],\n            \"excluded_products\": [],\n            \"allowed_categories\": [],\n            \"excluded_categories\": [],\n            \"allowed_countries\": [],\n            \"excluded_countries\": [],\n            \"allowed_emails\": [],\n            \"first_time_customer_only\": false,\n            \"is_valid\": true,\n            \"is_expired\": false,\n            \"has_reached_usage_limit\": false,\n            \"provider\": null,\n            \"created_at\": \"2025-08-20T21:30:52.000000Z\",\n            \"updated_at\": \"2025-08-20T21:39:54.000000Z\"\n        }\n    ],\n    \"pagination\": {\n        \"total\": 1,\n        \"per_page\": 15,\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 1\n    }\n}"}],"_postman_id":"06606fab-1b95-4031-bbeb-b391dcdf02b4"},{"name":"Get Coupon","id":"f810153e-242a-418d-a093-d8ca9ac4d906","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/coupons/{{code}}","description":"<h1 id=\"get-specific-coupon\">Get Specific Coupon</h1>\n<p>Retrieve detailed information about a specific coupon by its code.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>code</td>\n<td><strong>string (required)</strong>  <br />The unique coupon code (path parameter)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Detailed coupon information</td>\n</tr>\n<tr>\n<td>data.code</td>\n<td><strong>string</strong>  <br />Unique coupon code</td>\n</tr>\n<tr>\n<td>data.name</td>\n<td><strong>string</strong>  <br />Display name of the coupon</td>\n</tr>\n<tr>\n<td>data.description</td>\n<td><strong>string</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>data.type</td>\n<td><strong>string</strong>  <br />Type of discount (percentage, fixed_amount, free_shipping, buy_x_get_y, fixed_price)</td>\n</tr>\n<tr>\n<td>data.is_active</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently active</td>\n</tr>\n<tr>\n<td>data.discount_amount</td>\n<td><strong>string</strong>  <br />Discount value (percentage for percentage type, amount for fixed types)</td>\n</tr>\n<tr>\n<td>data.minimum_purchase</td>\n<td><strong>number/null</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>data.maximum_discount</td>\n<td><strong>number/null</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>data.usage_limit_per_coupon</td>\n<td><strong>integer/null</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>data.usage_limit_per_customer</td>\n<td><strong>integer/null</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>data.total_uses</td>\n<td><strong>integer</strong>  <br />Current number of times the coupon has been used</td>\n</tr>\n<tr>\n<td>data.starts_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon becomes valid (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.expires_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon expires (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.individual_use_only</td>\n<td><strong>boolean</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>data.allowed_products</td>\n<td><strong>array</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data.excluded_products</td>\n<td><strong>array</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data.allowed_categories</td>\n<td><strong>array</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data.excluded_categories</td>\n<td><strong>array</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data.allowed_countries</td>\n<td><strong>array</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>data.excluded_countries</td>\n<td><strong>array</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>data.allowed_emails</td>\n<td><strong>array</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>data.first_time_customer_only</td>\n<td><strong>boolean</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>data.is_valid</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently valid for use</td>\n</tr>\n<tr>\n<td>data.is_expired</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has expired</td>\n</tr>\n<tr>\n<td>data.has_reached_usage_limit</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has reached its usage limit</td>\n</tr>\n<tr>\n<td>data.provider</td>\n<td><strong>object/null</strong>  <br />CS provider team information if coupon was created by a provider</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.updated_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","coupons","{{code}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"6124f347-47ac-4d9a-868a-8ee51f0b806d","name":"Get Coupon Success","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/coupons/{{code}}"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.11"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 21 Aug 2025 02:52:15 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"code\": \"TEST10\",\n        \"name\": \"TEST10\",\n        \"description\": \"\",\n        \"type\": \"fixed_amount\",\n        \"is_active\": true,\n        \"discount_amount\": \"10.00\",\n        \"minimum_purchase\": null,\n        \"maximum_discount\": null,\n        \"usage_limit_per_coupon\": null,\n        \"usage_limit_per_customer\": null,\n        \"total_uses\": 2,\n        \"starts_at\": null,\n        \"expires_at\": null,\n        \"individual_use_only\": false,\n        \"allowed_products\": [],\n        \"excluded_products\": [],\n        \"allowed_categories\": [],\n        \"excluded_categories\": [],\n        \"allowed_countries\": [],\n        \"excluded_countries\": [],\n        \"allowed_emails\": [],\n        \"first_time_customer_only\": false,\n        \"is_valid\": true,\n        \"is_expired\": false,\n        \"has_reached_usage_limit\": false,\n        \"provider\": null,\n        \"created_at\": \"2025-08-20T21:30:52.000000Z\",\n        \"updated_at\": \"2025-08-20T21:39:54.000000Z\"\n    }\n}"}],"_postman_id":"f810153e-242a-418d-a093-d8ca9ac4d906"},{"name":"Create Coupon","id":"bfe1ec62-afef-4307-9cfd-01d1c3628675","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"code","value":" NEWCOUPON2025","type":"text"},{"key":"name","value":" New Year Sale","type":"text"},{"key":"type","value":" percentage","type":"text"},{"key":"discount_amount","value":" 25","type":"text"},{"key":" description","value":" Special discount for new year","type":"text","disabled":true},{"key":" is_active","value":" true","type":"text","disabled":true},{"key":" minimum_purchase","value":" 100","type":"text","disabled":true},{"key":" maximum_discount","value":" 50","type":"text","disabled":true},{"key":" usage_limit_per_coupon","value":" 100","type":"text","disabled":true},{"key":" usage_limit_per_customer","value":" 1","type":"text","disabled":true},{"key":" starts_at","value":" 2025-08-21","type":"text","disabled":true},{"key":" expires_at","value":" 2025-09-21","type":"text","disabled":true},{"key":" individual_use_only","value":" false","type":"text","disabled":true},{"key":" first_time_customer_only","value":" false","type":"text","disabled":true},{"key":" allowed_products","value":" [1, 2, 3]","type":"text","disabled":true},{"key":" excluded_products","value":" [4, 5]","type":"text","disabled":true},{"key":" allowed_categories","value":" [1, 2]","type":"text","disabled":true},{"key":" excluded_categories","value":" [3, 4]","type":"text","disabled":true},{"key":" allowed_countries","value":" [\"US\", \"CA\"]","type":"text","disabled":true},{"key":" excluded_countries","value":" [\"MX\"]","type":"text","disabled":true},{"key":" allowed_emails","value":" [\"customer@example.com\"]","type":"text","disabled":true},{"key":" buy_product_id","value":" 1","type":"text","disabled":true},{"key":" free_product_id","value":" 2","type":"text","disabled":true},{"key":" buy_quantity","value":" 2","type":"text","disabled":true},{"key":" free_quantity","value":" 1","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/v1/coupons","description":"<h1 id=\"create-coupon\">Create Coupon</h1>\n<p>Create a new coupon with specified discount rules and restrictions.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>code</td>\n<td><strong>string (required)</strong>  <br />Unique coupon code (must be unique across all coupons)</td>\n</tr>\n<tr>\n<td>name</td>\n<td><strong>string (required)</strong>  <br />Display name for the coupon</td>\n</tr>\n<tr>\n<td>type</td>\n<td><strong>string (required)</strong>  <br />Type of discount (percentage, fixed_amount, free_shipping, buy_x_get_y, fixed_price)</td>\n</tr>\n<tr>\n<td>discount_amount</td>\n<td><strong>number (required)</strong>  <br />Discount value (percentage for percentage type, amount for fixed types)</td>\n</tr>\n<tr>\n<td>description</td>\n<td><strong>string (optional)</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><strong>boolean (optional)</strong>  <br />Whether the coupon is active (default: true)</td>\n</tr>\n<tr>\n<td>minimum_purchase</td>\n<td><strong>number (optional)</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>maximum_discount</td>\n<td><strong>number (optional)</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>usage_limit_per_coupon</td>\n<td><strong>integer (optional)</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>usage_limit_per_customer</td>\n<td><strong>integer (optional)</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>starts_at</td>\n<td><strong>string (optional)</strong>  <br />Date/time when the coupon becomes valid (YYYY-MM-DD or ISO 8601)</td>\n</tr>\n<tr>\n<td>expires_at</td>\n<td><strong>string (optional)</strong>  <br />Date/time when the coupon expires (YYYY-MM-DD or ISO 8601)</td>\n</tr>\n<tr>\n<td>individual_use_only</td>\n<td><strong>boolean (optional)</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>first_time_customer_only</td>\n<td><strong>boolean (optional)</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>allowed_products</td>\n<td><strong>array (optional)</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>excluded_products</td>\n<td><strong>array (optional)</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>allowed_categories</td>\n<td><strong>array (optional)</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>excluded_categories</td>\n<td><strong>array (optional)</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>allowed_countries</td>\n<td><strong>array (optional)</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>excluded_countries</td>\n<td><strong>array (optional)</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>allowed_emails</td>\n<td><strong>array (optional)</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>buy_product_id</td>\n<td><strong>integer (optional)</strong>  <br />Product ID that must be purchased for buy_x_get_y type</td>\n</tr>\n<tr>\n<td>free_product_id</td>\n<td><strong>integer (optional)</strong>  <br />Product ID that will be free for buy_x_get_y type</td>\n</tr>\n<tr>\n<td>buy_quantity</td>\n<td><strong>integer (optional)</strong>  <br />Quantity required to purchase for buy_x_get_y type</td>\n</tr>\n<tr>\n<td>free_quantity</td>\n<td><strong>integer (optional)</strong>  <br />Quantity that will be free for buy_x_get_y type</td>\n</tr>\n<tr>\n<td>metadata</td>\n<td><strong>object (optional)</strong>  <br />Additional custom metadata as key-value pairs</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result (\"Coupon created successfully\")</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Created coupon details</td>\n</tr>\n<tr>\n<td>data.code</td>\n<td><strong>string</strong>  <br />Unique coupon code</td>\n</tr>\n<tr>\n<td>data.name</td>\n<td><strong>string</strong>  <br />Display name of the coupon</td>\n</tr>\n<tr>\n<td>data.description</td>\n<td><strong>string/null</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>data.type</td>\n<td><strong>string</strong>  <br />Type of discount applied</td>\n</tr>\n<tr>\n<td>data.is_active</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently active</td>\n</tr>\n<tr>\n<td>data.discount_amount</td>\n<td><strong>string</strong>  <br />Discount value (percentage or fixed amount)</td>\n</tr>\n<tr>\n<td>data.minimum_purchase</td>\n<td><strong>number/null</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>data.maximum_discount</td>\n<td><strong>number/null</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>data.usage_limit_per_coupon</td>\n<td><strong>integer/null</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>data.usage_limit_per_customer</td>\n<td><strong>integer/null</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>data.total_uses</td>\n<td><strong>integer</strong>  <br />Current number of times the coupon has been used (0 for new coupons)</td>\n</tr>\n<tr>\n<td>data.starts_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon becomes valid (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.expires_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon expires (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.individual_use_only</td>\n<td><strong>boolean/null</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>data.allowed_products</td>\n<td><strong>array/null</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data.excluded_products</td>\n<td><strong>array/null</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data.allowed_categories</td>\n<td><strong>array/null</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data.excluded_categories</td>\n<td><strong>array/null</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data.allowed_countries</td>\n<td><strong>array/null</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>data.excluded_countries</td>\n<td><strong>array/null</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>data.allowed_emails</td>\n<td><strong>array/null</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>data.first_time_customer_only</td>\n<td><strong>boolean/null</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>data.is_valid</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently valid for use</td>\n</tr>\n<tr>\n<td>data.is_expired</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has expired</td>\n</tr>\n<tr>\n<td>data.has_reached_usage_limit</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has reached its usage limit</td>\n</tr>\n<tr>\n<td>data.provider</td>\n<td><strong>object/null</strong>  <br />CS provider team information if coupon was created by a provider</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.updated_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","coupons"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"a0cd74ad-ba7d-4cce-9088-124b1f4ef7bd","name":"Create Coupon Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"code","value":" NEWCOUPON2025","type":"text"},{"key":"name","value":" New Year Sale","type":"text"},{"key":"type","value":" percentage","type":"text"},{"key":"discount_amount","value":" 25","type":"text"},{"key":" description","value":" Special discount for new year","type":"text","disabled":true},{"key":" is_active","value":" true","type":"text","disabled":true},{"key":" minimum_purchase","value":" 100","type":"text","disabled":true},{"key":" maximum_discount","value":" 50","type":"text","disabled":true},{"key":" usage_limit_per_coupon","value":" 100","type":"text","disabled":true},{"key":" usage_limit_per_customer","value":" 1","type":"text","disabled":true},{"key":" starts_at","value":" 2025-08-21","type":"text","disabled":true},{"key":" expires_at","value":" 2025-09-21","type":"text","disabled":true},{"key":" individual_use_only","value":" false","type":"text","disabled":true},{"key":" first_time_customer_only","value":" false","type":"text","disabled":true},{"key":" allowed_products","value":" [1, 2, 3]","type":"text","disabled":true},{"key":" excluded_products","value":" [4, 5]","type":"text","disabled":true},{"key":" allowed_categories","value":" [1, 2]","type":"text","disabled":true},{"key":" excluded_categories","value":" [3, 4]","type":"text","disabled":true},{"key":" allowed_countries","value":" [\"US\", \"CA\"]","type":"text","disabled":true},{"key":" excluded_countries","value":" [\"MX\"]","type":"text","disabled":true},{"key":" allowed_emails","value":" [\"customer@example.com\"]","type":"text","disabled":true},{"key":" buy_product_id","value":" 1","type":"text","disabled":true},{"key":" free_product_id","value":" 2","type":"text","disabled":true},{"key":" buy_quantity","value":" 2","type":"text","disabled":true},{"key":" free_quantity","value":" 1","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/v1/coupons"},"status":"Created","code":201,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.4.11"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 21 Aug 2025 03:08:01 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Coupon created successfully\",\n    \"data\": {\n        \"code\": \"NEWCOUPON2025\",\n        \"name\": \"New Year Sale\",\n        \"description\": null,\n        \"type\": \"percentage\",\n        \"is_active\": true,\n        \"discount_amount\": \"25\",\n        \"minimum_purchase\": null,\n        \"maximum_discount\": null,\n        \"usage_limit_per_coupon\": null,\n        \"usage_limit_per_customer\": null,\n        \"total_uses\": 0,\n        \"starts_at\": null,\n        \"expires_at\": null,\n        \"individual_use_only\": null,\n        \"allowed_products\": null,\n        \"excluded_products\": null,\n        \"allowed_categories\": null,\n        \"excluded_categories\": null,\n        \"allowed_countries\": null,\n        \"excluded_countries\": null,\n        \"allowed_emails\": null,\n        \"first_time_customer_only\": null,\n        \"is_valid\": true,\n        \"is_expired\": false,\n        \"has_reached_usage_limit\": false,\n        \"provider\": null,\n        \"created_at\": \"2025-08-21T03:08:01.000000Z\",\n        \"updated_at\": \"2025-08-21T03:08:01.000000Z\"\n    }\n}"}],"_postman_id":"bfe1ec62-afef-4307-9cfd-01d1c3628675"},{"name":"Validate Coupon","id":"8c482e72-aa2f-486f-94eb-6a25cc2b47bb","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"subtotal","value":" 150.00","type":"text"},{"key":" customer_email","value":" customer@example.com","type":"text","disabled":true},{"key":" country","value":" US","type":"text","disabled":true},{"key":" product_ids","value":" [1, 2, 3]","type":"text","disabled":true},{"key":" category_ids","value":" [1, 2]","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/v1/coupons/{{code}}/validate","description":"<h1 id=\"validate-coupon\">Validate Coupon</h1>\n<p>Validate a coupon for checkout and calculate the discount amount based on the provided context.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>code</td>\n<td><strong>string (required)</strong>  <br />The unique coupon code to validate (path parameter)</td>\n</tr>\n<tr>\n<td>subtotal</td>\n<td><strong>number (required)</strong>  <br />Cart subtotal amount to calculate discount against</td>\n</tr>\n<tr>\n<td>customer_email</td>\n<td><strong>string (optional)</strong>  <br />Customer email address for email-restricted coupons</td>\n</tr>\n<tr>\n<td>country</td>\n<td><strong>string (optional)</strong>  <br />2-letter country code for location-based restrictions</td>\n</tr>\n<tr>\n<td>product_ids</td>\n<td><strong>array (optional)</strong>  <br />Array of product IDs in the cart for product-specific coupons</td>\n</tr>\n<tr>\n<td>category_ids</td>\n<td><strong>array (optional)</strong>  <br />Array of category IDs in the cart for category-specific coupons</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>is_valid</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is valid for the provided context</td>\n</tr>\n<tr>\n<td>discount_amount</td>\n<td><strong>number</strong>  <br />Calculated discount amount based on coupon type and cart subtotal</td>\n</tr>\n<tr>\n<td>coupon</td>\n<td><strong>object</strong>  <br />Full coupon details</td>\n</tr>\n<tr>\n<td>coupon.code</td>\n<td><strong>string</strong>  <br />Unique coupon code</td>\n</tr>\n<tr>\n<td>coupon.name</td>\n<td><strong>string</strong>  <br />Display name of the coupon</td>\n</tr>\n<tr>\n<td>coupon.description</td>\n<td><strong>string</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>coupon.type</td>\n<td><strong>string</strong>  <br />Type of discount (percentage, fixed_amount, free_shipping, buy_x_get_y, fixed_price)</td>\n</tr>\n<tr>\n<td>coupon.is_active</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently active</td>\n</tr>\n<tr>\n<td>coupon.discount_amount</td>\n<td><strong>string</strong>  <br />Base discount value (percentage or fixed amount)</td>\n</tr>\n<tr>\n<td>coupon.minimum_purchase</td>\n<td><strong>number/null</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>coupon.maximum_discount</td>\n<td><strong>number/null</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>coupon.usage_limit_per_coupon</td>\n<td><strong>integer/null</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>coupon.usage_limit_per_customer</td>\n<td><strong>integer/null</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>coupon.total_uses</td>\n<td><strong>integer</strong>  <br />Current number of times the coupon has been used</td>\n</tr>\n<tr>\n<td>coupon.starts_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon becomes valid (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>coupon.expires_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon expires (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>coupon.individual_use_only</td>\n<td><strong>boolean</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>coupon.allowed_products</td>\n<td><strong>array/null</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>coupon.excluded_products</td>\n<td><strong>array/null</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>coupon.allowed_categories</td>\n<td><strong>array/null</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>coupon.excluded_categories</td>\n<td><strong>array/null</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>coupon.allowed_countries</td>\n<td><strong>array/null</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>coupon.excluded_countries</td>\n<td><strong>array/null</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>coupon.allowed_emails</td>\n<td><strong>array/null</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>coupon.first_time_customer_only</td>\n<td><strong>boolean</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>coupon.is_valid</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently valid for use</td>\n</tr>\n<tr>\n<td>coupon.is_expired</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has expired</td>\n</tr>\n<tr>\n<td>coupon.has_reached_usage_limit</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has reached its usage limit</td>\n</tr>\n<tr>\n<td>coupon.provider</td>\n<td><strong>object/null</strong>  <br />CS provider team information if coupon was created by a provider</td>\n</tr>\n<tr>\n<td>coupon.created_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>coupon.updated_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>validation_errors</td>\n<td><strong>array</strong>  <br />Array of validation error messages if coupon is invalid (empty array if valid)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","coupons","{{code}}","validate"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"0e03e4f7-4b1e-4cb8-bf93-e2e8b838846d","name":"Validate Coupon Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":"subtotal","value":" 150.00","type":"text"},{"key":" customer_email","value":" customer@example.com","type":"text","disabled":true},{"key":" country","value":" US","type":"text","disabled":true},{"key":" product_ids","value":" [1, 2, 3]","type":"text","disabled":true},{"key":" category_ids","value":" [1, 2]","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/v1/coupons/{{code}}/validate"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.11"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 21 Aug 2025 04:51:04 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"is_valid\": true,\n    \"discount_amount\": 37.5,\n    \"coupon\": {\n        \"code\": \"UPDATEDCODE\",\n        \"name\": \"Updated Summer Sale\",\n        \"description\": \"Updated description\",\n        \"type\": \"percentage\",\n        \"is_active\": true,\n        \"discount_amount\": \"25.00\",\n        \"minimum_purchase\": null,\n        \"maximum_discount\": null,\n        \"usage_limit_per_coupon\": null,\n        \"usage_limit_per_customer\": null,\n        \"total_uses\": 0,\n        \"starts_at\": null,\n        \"expires_at\": null,\n        \"individual_use_only\": false,\n        \"allowed_products\": null,\n        \"excluded_products\": null,\n        \"allowed_categories\": null,\n        \"excluded_categories\": null,\n        \"allowed_countries\": null,\n        \"excluded_countries\": null,\n        \"allowed_emails\": null,\n        \"first_time_customer_only\": false,\n        \"is_valid\": true,\n        \"is_expired\": false,\n        \"has_reached_usage_limit\": false,\n        \"provider\": null,\n        \"created_at\": \"2025-08-21T03:08:01.000000Z\",\n        \"updated_at\": \"2025-08-21T03:11:30.000000Z\"\n    },\n    \"validation_errors\": []\n}"}],"_postman_id":"8c482e72-aa2f-486f-94eb-6a25cc2b47bb"},{"name":"Update Coupon","id":"aa5eb227-8544-4bb7-acb5-86448b13d996","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PUT","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":" code","value":" UPDATEDCODE","type":"text"},{"key":" name","value":" Updated Summer Sale","type":"text"},{"key":" description","value":" Updated description","type":"text"},{"key":" type","value":" fixed_amount","type":"text","disabled":true},{"key":" is_active","value":" false","type":"text","disabled":true},{"key":" discount_amount","value":" 30","type":"text","disabled":true},{"key":" minimum_purchase","value":" 150","type":"text","disabled":true},{"key":" maximum_discount","value":" 75","type":"text","disabled":true},{"key":" usage_limit_per_coupon","value":" 200","type":"text","disabled":true},{"key":" usage_limit_per_customer","value":" 2","type":"text","disabled":true},{"key":" starts_at","value":" 2025-08-25","type":"text","disabled":true},{"key":" expires_at","value":" 2025-10-25","type":"text","disabled":true},{"key":" individual_use_only","value":" true","type":"text","disabled":true},{"key":" first_time_customer_only","value":" true","type":"text","disabled":true},{"key":" allowed_products","value":" [6, 7, 8]","type":"text","disabled":true},{"key":" excluded_products","value":" [9, 10]","type":"text","disabled":true},{"key":" allowed_categories","value":" [5, 6]","type":"text","disabled":true},{"key":" excluded_categories","value":" [7, 8]","type":"text","disabled":true},{"key":" allowed_countries","value":" [\"GB\", \"AU\"]","type":"text","disabled":true},{"key":" excluded_countries","value":" [\"NZ\"]","type":"text","disabled":true},{"key":" allowed_emails","value":" [\"vip@example.com\"]","type":"text","disabled":true},{"key":" metadata","value":" {\"updated\": true}","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/v1/coupons/{{code}}","description":"<h1 id=\"update-coupon\">Update Coupon</h1>\n<p>Update an existing coupon's properties and restrictions.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>code</td>\n<td><strong>string (optional)</strong>  <br />New coupon code (must be unique if changing)</td>\n</tr>\n<tr>\n<td>name</td>\n<td><strong>string (optional)</strong>  <br />Display name for the coupon</td>\n</tr>\n<tr>\n<td>type</td>\n<td><strong>string (optional)</strong>  <br />Type of discount (percentage, fixed_amount, free_shipping, buy_x_get_y, fixed_price)</td>\n</tr>\n<tr>\n<td>discount_amount</td>\n<td><strong>number (optional)</strong>  <br />Discount value (percentage for percentage type, amount for fixed types)</td>\n</tr>\n<tr>\n<td>description</td>\n<td><strong>string (optional)</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><strong>boolean (optional)</strong>  <br />Whether the coupon is active</td>\n</tr>\n<tr>\n<td>minimum_purchase</td>\n<td><strong>number (optional)</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>maximum_discount</td>\n<td><strong>number (optional)</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>usage_limit_per_coupon</td>\n<td><strong>integer (optional)</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>usage_limit_per_customer</td>\n<td><strong>integer (optional)</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>starts_at</td>\n<td><strong>string (optional)</strong>  <br />Date/time when the coupon becomes valid (YYYY-MM-DD or ISO 8601)</td>\n</tr>\n<tr>\n<td>expires_at</td>\n<td><strong>string (optional)</strong>  <br />Date/time when the coupon expires (YYYY-MM-DD or ISO 8601)</td>\n</tr>\n<tr>\n<td>individual_use_only</td>\n<td><strong>boolean (optional)</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>first_time_customer_only</td>\n<td><strong>boolean (optional)</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>allowed_products</td>\n<td><strong>array (optional)</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>excluded_products</td>\n<td><strong>array (optional)</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>allowed_categories</td>\n<td><strong>array (optional)</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>excluded_categories</td>\n<td><strong>array (optional)</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>allowed_countries</td>\n<td><strong>array (optional)</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>excluded_countries</td>\n<td><strong>array (optional)</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>allowed_emails</td>\n<td><strong>array (optional)</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>metadata</td>\n<td><strong>object (optional)</strong>  <br />Additional custom metadata as key-value pairs</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result (\"Coupon updated successfully\")</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>object</strong>  <br />Updated coupon details</td>\n</tr>\n<tr>\n<td>data.code</td>\n<td><strong>string</strong>  <br />Unique coupon code</td>\n</tr>\n<tr>\n<td>data.name</td>\n<td><strong>string</strong>  <br />Display name of the coupon</td>\n</tr>\n<tr>\n<td>data.description</td>\n<td><strong>string</strong>  <br />Detailed description of the coupon</td>\n</tr>\n<tr>\n<td>data.type</td>\n<td><strong>string</strong>  <br />Type of discount applied</td>\n</tr>\n<tr>\n<td>data.is_active</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently active</td>\n</tr>\n<tr>\n<td>data.discount_amount</td>\n<td><strong>string</strong>  <br />Discount value (percentage or fixed amount)</td>\n</tr>\n<tr>\n<td>data.minimum_purchase</td>\n<td><strong>number/null</strong>  <br />Minimum purchase amount required to use this coupon</td>\n</tr>\n<tr>\n<td>data.maximum_discount</td>\n<td><strong>number/null</strong>  <br />Maximum discount amount that can be applied</td>\n</tr>\n<tr>\n<td>data.usage_limit_per_coupon</td>\n<td><strong>integer/null</strong>  <br />Total number of times this coupon can be used</td>\n</tr>\n<tr>\n<td>data.usage_limit_per_customer</td>\n<td><strong>integer/null</strong>  <br />Number of times a single customer can use this coupon</td>\n</tr>\n<tr>\n<td>data.total_uses</td>\n<td><strong>integer</strong>  <br />Current number of times the coupon has been used</td>\n</tr>\n<tr>\n<td>data.starts_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon becomes valid (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.expires_at</td>\n<td><strong>string/null</strong>  <br />Date/time when the coupon expires (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.individual_use_only</td>\n<td><strong>boolean</strong>  <br />If true, coupon cannot be combined with other coupons</td>\n</tr>\n<tr>\n<td>data.allowed_products</td>\n<td><strong>array/null</strong>  <br />Array of product IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data.excluded_products</td>\n<td><strong>array/null</strong>  <br />Array of product IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data.allowed_categories</td>\n<td><strong>array/null</strong>  <br />Array of category IDs this coupon is valid for</td>\n</tr>\n<tr>\n<td>data.excluded_categories</td>\n<td><strong>array/null</strong>  <br />Array of category IDs this coupon cannot be used with</td>\n</tr>\n<tr>\n<td>data.allowed_countries</td>\n<td><strong>array/null</strong>  <br />Array of 2-letter country codes where coupon is valid</td>\n</tr>\n<tr>\n<td>data.excluded_countries</td>\n<td><strong>array/null</strong>  <br />Array of 2-letter country codes where coupon is not valid</td>\n</tr>\n<tr>\n<td>data.allowed_emails</td>\n<td><strong>array/null</strong>  <br />Array of email addresses that can use this coupon</td>\n</tr>\n<tr>\n<td>data.first_time_customer_only</td>\n<td><strong>boolean</strong>  <br />If true, only first-time customers can use this coupon</td>\n</tr>\n<tr>\n<td>data.is_valid</td>\n<td><strong>boolean</strong>  <br />Whether the coupon is currently valid for use</td>\n</tr>\n<tr>\n<td>data.is_expired</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has expired</td>\n</tr>\n<tr>\n<td>data.has_reached_usage_limit</td>\n<td><strong>boolean</strong>  <br />Whether the coupon has reached its usage limit</td>\n</tr>\n<tr>\n<td>data.provider</td>\n<td><strong>object/null</strong>  <br />CS provider team information if coupon was created by a provider</td>\n</tr>\n<tr>\n<td>data.created_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data.updated_at</td>\n<td><strong>string</strong>  <br />Date/time when the coupon was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","coupons","{{code}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"4a5b03f7-1a78-464a-b972-d70865bf4594","name":"Update Coupon Success","originalRequest":{"method":"PUT","header":[],"body":{"mode":"urlencoded","urlencoded":[{"key":" code","value":" UPDATEDCODE","type":"text"},{"key":" name","value":" Updated Summer Sale","type":"text"},{"key":" description","value":" Updated description","type":"text"},{"key":" type","value":" fixed_amount","type":"text","disabled":true},{"key":" is_active","value":" false","type":"text","disabled":true},{"key":" discount_amount","value":" 30","type":"text","disabled":true},{"key":" minimum_purchase","value":" 150","type":"text","disabled":true},{"key":" maximum_discount","value":" 75","type":"text","disabled":true},{"key":" usage_limit_per_coupon","value":" 200","type":"text","disabled":true},{"key":" usage_limit_per_customer","value":" 2","type":"text","disabled":true},{"key":" starts_at","value":" 2025-08-25","type":"text","disabled":true},{"key":" expires_at","value":" 2025-10-25","type":"text","disabled":true},{"key":" individual_use_only","value":" true","type":"text","disabled":true},{"key":" first_time_customer_only","value":" true","type":"text","disabled":true},{"key":" allowed_products","value":" [6, 7, 8]","type":"text","disabled":true},{"key":" excluded_products","value":" [9, 10]","type":"text","disabled":true},{"key":" allowed_categories","value":" [5, 6]","type":"text","disabled":true},{"key":" excluded_categories","value":" [7, 8]","type":"text","disabled":true},{"key":" allowed_countries","value":" [\"GB\", \"AU\"]","type":"text","disabled":true},{"key":" excluded_countries","value":" [\"NZ\"]","type":"text","disabled":true},{"key":" allowed_emails","value":" [\"vip@example.com\"]","type":"text","disabled":true},{"key":" metadata","value":" {\"updated\": true}","type":"text","disabled":true}]},"url":"https://api.sparkcrm.io/v1/coupons/{{code}}"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.11"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 21 Aug 2025 03:11:30 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Coupon updated successfully\",\n    \"data\": {\n        \"code\": \"UPDATEDCODE\",\n        \"name\": \"Updated Summer Sale\",\n        \"description\": \"Updated description\",\n        \"type\": \"percentage\",\n        \"is_active\": true,\n        \"discount_amount\": \"25.00\",\n        \"minimum_purchase\": null,\n        \"maximum_discount\": null,\n        \"usage_limit_per_coupon\": null,\n        \"usage_limit_per_customer\": null,\n        \"total_uses\": 0,\n        \"starts_at\": null,\n        \"expires_at\": null,\n        \"individual_use_only\": false,\n        \"allowed_products\": null,\n        \"excluded_products\": null,\n        \"allowed_categories\": null,\n        \"excluded_categories\": null,\n        \"allowed_countries\": null,\n        \"excluded_countries\": null,\n        \"allowed_emails\": null,\n        \"first_time_customer_only\": false,\n        \"is_valid\": true,\n        \"is_expired\": false,\n        \"has_reached_usage_limit\": false,\n        \"provider\": null,\n        \"created_at\": \"2025-08-21T03:08:01.000000Z\",\n        \"updated_at\": \"2025-08-21T03:11:30.000000Z\"\n    }\n}"}],"_postman_id":"aa5eb227-8544-4bb7-acb5-86448b13d996"},{"name":"Delete Coupon","id":"7cadddd2-7232-43cf-ac5f-d110ca5c6814","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/coupons/{{code}}","description":"<h1 id=\"delete-coupon\">Delete Coupon</h1>\n<p>Soft delete a coupon from the system.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>code</td>\n<td><strong>string (required)</strong>  <br />The unique coupon code to delete (path parameter)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>message</td>\n<td><strong>string</strong>  <br />Human-readable description of the result (\"Coupon deleted successfully\")</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","coupons","{{code}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"93d9615a-3333-4492-831e-6ad6262fc918","name":"Delete Coupon Success","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/coupons/{{code}}"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.11"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 21 Aug 2025 04:49:04 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Coupon deleted successfully\"\n}"}],"_postman_id":"7cadddd2-7232-43cf-ac5f-d110ca5c6814"}],"id":"b390c564-84f3-48e6-b17e-ac93f2dacc37","_postman_id":"b390c564-84f3-48e6-b17e-ac93f2dacc37","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Customers","item":[{"name":"Notes","item":[{"name":"Get Notes","id":"569d87b4-40b3-4403-8906-21174af5e217","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/customers/{customer_number}/notes","description":"<h1 id=\"get-customer-notes\">Get Customer Notes</h1>\n<p>Retrieve notes for a specific customer that match the specified search criteria.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter notes by type. Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>search</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Search notes by title or content. Performs partial matching using SQL LIKE operations. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><strong><em>integer (optional)</em></strong>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of customer note objects matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>string</strong>  <br />Name of the user or system that created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>customer</strong></td>\n<td><strong>object</strong>  <br />Customer information</td>\n</tr>\n<tr>\n<td><strong>customer.customer_number</strong></td>\n<td><strong>string</strong>  <br />Customer's unique identifier</td>\n</tr>\n<tr>\n<td><strong>customer.email</strong></td>\n<td><strong>string</strong>  <br />Customer's email address</td>\n</tr>\n<tr>\n<td><strong>customer.name</strong></td>\n<td><strong>string</strong>  <br />Customer's full name</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of notes matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of notes displayed per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","customers","{customer_number}","notes"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"f24a145a-fe33-431d-8fed-b09aa08aeb6a","name":"Get Notes","originalRequest":{"method":"GET","header":[],"url":"https://sparkcrm.test/v1/customers/CUST-250815-00142/notes"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:19:20 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"56000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": 584,\n            \"title\": null,\n            \"content\": \"Eos dolorem eos omnis optio. Molestiae assumenda itaque ea voluptate in. Optio dicta asperiores porro earum repudiandae velit aut.\",\n            \"type\": \"support\",\n            \"created_by\": \"Ut magni autem sunt fuga iure.\",\n            \"created_at\": \"2025-02-04T02:25:14.000000Z\",\n            \"updated_at\": \"2025-08-15T01:57:33.000000Z\"\n        },\n        {\n            \"id\": 583,\n            \"title\": \"Soluta vel et ut.\",\n            \"content\": \"Nesciunt est voluptatem non reiciendis sed. Non a est tempore commodi.\",\n            \"type\": \"fraud\",\n            \"created_by\": \"Neque doloremque totam quasi recusandae natus numquam.\",\n            \"created_at\": \"2024-10-08T05:55:00.000000Z\",\n            \"updated_at\": \"2025-08-15T01:57:33.000000Z\"\n        }\n    ],\n    \"customer\": {\n        \"customer_number\": \"CUST-250815-00142\",\n        \"email\": \"waelchi.emerald@example.net\",\n        \"name\": \"Alec Schmeler\"\n    },\n    \"pagination\": {\n        \"total\": 2,\n        \"per_page\": 15,\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 2\n    }\n}"}],"_postman_id":"569d87b4-40b3-4403-8906-21174af5e217"},{"name":"Get Note","id":"9b6d8382-75aa-49e5-aa91-f60f6a11ca87","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/customers/{customer_number}/notes/{noteId}","description":"<h1 id=\"get-specific-customer-note\">Get Specific Customer Note</h1>\n<p>Retrieve a specific note for a customer by note ID.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body parameters. The customer number and note ID are provided in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The requested note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>string</strong>  <br />Name of the user or system that created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","customers","{customer_number}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"4960db4a-018b-414b-8dc1-b6e1d15c438e","name":"Get Note","originalRequest":{"method":"GET","header":[],"url":"https://sparkcrm.test/v1/customers/CUST-250815-00142/notes/584"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:19:54 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"96"},{"key":"X-RateLimit-Reset","value":"22000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"id\": 584,\n        \"title\": null,\n        \"content\": \"Eos dolorem eos omnis optio. Molestiae assumenda itaque ea voluptate in. Optio dicta asperiores porro earum repudiandae velit aut.\",\n        \"type\": \"support\",\n        \"created_by\": \"Ut magni autem sunt fuga iure.\",\n        \"created_at\": \"2025-02-04T02:25:14.000000Z\",\n        \"updated_at\": \"2025-08-15T01:57:33.000000Z\"\n    }\n}"}],"_postman_id":"9b6d8382-75aa-49e5-aa91-f60f6a11ca87"},{"name":"Create Note","id":"288f461d-1a63-444a-a935-cbd338605ab2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"url":"https://api.sparkcrm.io/v1/customers/{customer_number}/notes","description":"<h1 id=\"create-customer-note\">Create Customer Note</h1>\n<p>Create a new note for a specific customer.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>title</strong></td>\n<td><strong><em>string (required)</em></strong>  <br />Note title. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>content</strong></td>\n<td><strong><em>string (required)</em></strong>  <br />Note content. Maximum 5000 characters.</td>\n</tr>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note type/category. Maximum 50 characters. Defaults to \"general\" if not provided.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The created note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>string</strong>  <br />Name of the user or system that created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","customers","{customer_number}","notes"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"8d4217ac-33ee-4c62-be5c-6b9f82d373e9","name":"Create Note","originalRequest":{"method":"POST","header":[],"url":{"raw":"https://sparkcrm.test/v1/customers/CUST-250815-00142/notes?title=new customer note&content=This is a new customer note&type=shipping","protocol":"https","host":["sparkcrm","test"],"path":["v1","customers","CUST-250815-00142","notes"],"query":[{"key":"title","value":"new customer note","type":"text"},{"key":"content","value":"This is a new customer note","type":"text"},{"key":"type","value":"shipping","type":"text"}]}},"status":"Created","code":201,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:20:52 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note added successfully\",\n    \"data\": {\n        \"id\": 983,\n        \"title\": \"new customer note\",\n        \"content\": \"This is a new customer note\",\n        \"type\": \"shipping\",\n        \"created_by\": \"API\",\n        \"created_at\": \"2025-09-17T03:20:52.000000Z\",\n        \"updated_at\": \"2025-09-17T03:20:52.000000Z\"\n    }\n}"}],"_postman_id":"288f461d-1a63-444a-a935-cbd338605ab2"},{"name":"Update Note","id":"6888fdcc-3614-4ea3-8ccd-d4d598b4d91b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PUT","header":[],"url":"https://api.sparkcrm.io/v1/customers/{customer_number}/notes/{noteId}","description":"<h1 id=\"update-customer-note\">Update Customer Note</h1>\n<p>Update an existing note for a specific customer.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>title</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note title. Maximum 255 characters. Only required if updating the title.</td>\n</tr>\n<tr>\n<td><strong>content</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note content. Maximum 5000 characters. Only required if updating the content.</td>\n</tr>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note type/category. Maximum 50 characters. Can be set to null.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Note:</strong> At least one field must be provided to update the note. All fields use \"sometimes\" validation, meaning they're only validated if present in the request.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The updated note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>string</strong>  <br />Name of the user or system that created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","customers","{customer_number}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"e94bba1b-0092-46e0-9869-03e96935ff2f","name":"Update Note","originalRequest":{"method":"PUT","header":[],"url":{"raw":"https://sparkcrm.test/v1/customers/CUST-250815-00142/notes/983?content=This is an updated note","protocol":"https","host":["sparkcrm","test"],"path":["v1","customers","CUST-250815-00142","notes","983"],"query":[{"key":"content","value":"This is an updated note","type":"text"}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:21:30 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"21000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note updated successfully\",\n    \"data\": {\n        \"id\": 983,\n        \"title\": \"new customer note\",\n        \"content\": \"This is an updated note\",\n        \"type\": \"shipping\",\n        \"created_by\": \"API\",\n        \"created_at\": \"2025-09-17T03:20:52.000000Z\",\n        \"updated_at\": \"2025-09-17T03:21:30.000000Z\"\n    }\n}"}],"_postman_id":"6888fdcc-3614-4ea3-8ccd-d4d598b4d91b"},{"name":"Delete Note","id":"733d08e2-0b15-43fe-aa01-1b5211804af1","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/customers/{customer_number}/notes/{noteId}","description":"<h1 id=\"delete-customer-note\">Delete Customer Note</h1>\n<p>Delete a specific note for a customer by note ID.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body parameters. The customer number and note ID are provided in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message confirming the note deletion</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","customers","{customer_number}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"0986492d-e3d7-44cd-8ee6-8aa9a8199bc1","name":"Delete Note","originalRequest":{"method":"DELETE","header":[],"url":"https://sparkcrm.test/v1/customers/CUST-250815-00142/notes/983"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:21:47 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"97"},{"key":"X-RateLimit-Reset","value":"4000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note deleted successfully\"\n}"}],"_postman_id":"733d08e2-0b15-43fe-aa01-1b5211804af1"}],"id":"05cd0aba-21cb-4948-819f-9a990e468e82","_postman_id":"05cd0aba-21cb-4948-819f-9a990e468e82","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}}],"id":"86d2ab23-3289-4d92-b569-605255a061ac","_postman_id":"86d2ab23-3289-4d92-b569-605255a061ac","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Fulfillments","item":[{"name":"Actions","item":[{"name":"Add Tracking","id":"b163e53a-fa1a-4359-983e-98cde1ec6f5e","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"shipping_carrier\": \"UPS\",\r\n  \"tracking_number\": \"1Z999AA10123456784\",\r\n  \"tracking_urls\": [\r\n    \"https://www.ups.com/track?tracknum=1Z999AA10123456784\"\r\n  ]\r\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}/add_tracking","description":"<h1 id=\"add-tracking\">Add Tracking</h1>\n<p>Add tracking information to a fulfillment. When tracking is added, Spark automatically updates the fulfillment status to <code>shipped</code>, sets the shipped timestamp, and triggers any webhooks, auto-responders, or other system functionality tied to tracking being issued.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://api.sparkcrm.io/v1/fulfillments/FUL-260310-00001/add_tracking\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.add_tracking</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>fulfillmentNumber</strong></td>\n<td><em><strong>string (required, URL path)</strong></em>  <br />The fulfillment number to add tracking to. Format: <code>FUL-XXXXXX-XXXXX</code>.</td>\n</tr>\n<tr>\n<td><strong>shipping_carrier</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />The shipping carrier name (e.g., UPS, FedEx, USPS). Maximum 100 characters.</td>\n</tr>\n<tr>\n<td><strong>tracking_number</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />The package tracking number assigned by the carrier. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>tracking_urls</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />Array of tracking URLs. Each entry must be a valid URL.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns the updated fulfillment in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>. The <code>status</code> will be <code>shipped</code> and <code>shipped_at</code> populated.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Fulfillment not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error — required fields are missing or invalid</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{{fulfillmentNumber}}","add_tracking"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"ed7604d5-227e-4099-8a32-2556442009db","name":"Get Fulfillments","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/x-www-form-urlencoded","type":"text"}],"body":{"mode":"urlencoded","urlencoded":[],"options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}/add_tracking"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:04:02 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"id\": 543,\n        \"fulfillment_number\": \"FUL-250815-00543\",\n        \"shipping_group_number\": \"ccfafc41-daaf-3496-8ec4-db3804936b3f\",\n        \"status\": \"shipped\",\n        \"fulfillment_type\": \"manual\",\n        \"items\": [\n            {\n                \"quantity\": 1,\n                \"product_id\": 1,\n                \"unit_price\": \"299.99\",\n                \"product_sku\": \"SKU-4991om\",\n                \"total_price\": 299.99,\n                \"product_name\": \"Smart Watch Pro\",\n                \"base_quantity\": 1,\n                \"order_quantity\": 1,\n                \"product_options\": null\n            },\n            {\n                \"quantity\": 1,\n                \"product_id\": 8,\n                \"unit_price\": \"45.99\",\n                \"product_sku\": \"SKU-7191sf\",\n                \"total_price\": 45.99,\n                \"product_name\": \"Smart Water Bottle\",\n                \"base_quantity\": 1,\n                \"order_quantity\": 1,\n                \"product_options\": null\n            }\n        ],\n        \"shipping_carrier\": \"UPS\",\n        \"shipping_service\": null,\n        \"tracking_number\": \"1Z999AA10123456784\",\n        \"tracking_urls\": [\n            \"https://www.ups.com/track?tracknum=1Z999AA10123456784\"\n        ],\n        \"rma_number\": null,\n        \"created_at\": \"2025-09-14T17:13:19.000000Z\",\n        \"updated_at\": \"2025-09-18T14:22:07.000000Z\",\n        \"order\": {\n            \"id\": 659,\n            \"order_number\": \"ORD-250815-00318\"\n        },\n        \"customer\": {\n            \"customer_number\": \"CUST-250815-00157\",\n            \"email\": \"lwest@example.net\",\n            \"name\": \"Bonita Botsford\"\n        },\n        \"external_fulfillment_id\": null,\n        \"transaction_id\": 1284,\n        \"shipping_cost\": \"8.99\",\n        \"handling_cost\": \"2.50\",\n        \"shipping_name\": \"Bonita Botsford\",\n        \"shipping_company\": null,\n        \"shipping_address1\": \"482 Oakridge Lane\",\n        \"shipping_address2\": \"Apt 12B\",\n        \"shipping_city\": \"Austin\",\n        \"shipping_state\": \"TX\",\n        \"shipping_postal_code\": \"78704\",\n        \"shipping_country\": \"US\",\n        \"shipping_phone\": \"512-555-0134\",\n        \"shipping_notes\": null,\n        \"download_url\": null,\n        \"download_limit\": null,\n        \"download_expiry\": null,\n        \"return_status\": null,\n        \"return_reason\": null,\n        \"return_tracking_number\": null,\n        \"return_meta\": null,\n        \"requires_signature\": false,\n        \"is_gift\": false,\n        \"is_backordered\": false,\n        \"is_preorder\": false,\n        \"is_custom\": false,\n        \"custom_fields\": null,\n        \"metadata\": null,\n        \"rma_created_at\": null,\n        \"rma_created_by\": null,\n        \"sent_to_shipper_at\": \"2025-09-17T09:45:11.000000Z\",\n        \"tracking_number_generated_at\": \"2025-09-18T14:22:07.000000Z\",\n        \"shipped_at\": \"2025-09-18T14:22:07.000000Z\",\n        \"delivered_at\": null,\n        \"returned_at\": null,\n        \"fulfillment_provider\": {\n            \"id\": 4,\n            \"name\": \"Warehouse Central\",\n            \"integration_type\": \"manual\",\n            \"status\": \"active\"\n        },\n        \"products\": [\n            {\n                \"id\": 1,\n                \"name\": \"Smart Watch Pro\",\n                \"sku\": \"SKU-4991om\",\n                \"quantity\": 1\n            },\n            {\n                \"id\": 8,\n                \"name\": \"Smart Water Bottle\",\n                \"sku\": \"SKU-7191sf\",\n                \"quantity\": 1\n            }\n        ]\n    }\n}\n"}],"_postman_id":"b163e53a-fa1a-4359-983e-98cde1ec6f5e"},{"name":"Cancel","id":"9b38065a-f91e-7482-99ea-7a1979270a4c","request":{"method":"POST","header":[{"key":"Accept","value":"application/json"},{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"reason\": \"Customer requested cancellation\"\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}/cancel","description":"<h1 id=\"cancel\">Cancel</h1>\n<p>Cancel a fulfillment. Restores product stock and attempts to cancel with the fulfillment provider if an external ID is set.</p>\n<p><strong>Allowed when:</strong> the current status is <code>pending</code>, <code>processing</code>, or <code>tracking_issued</code>. Returns 422 otherwise.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://api.sparkcrm.io/v1/fulfillments/FUL-260310-00001/cancel\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.cancel</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>fulfillmentNumber</strong></td>\n<td><em><strong>string (required, URL path)</strong></em>  <br />The fulfillment number to cancel. Format: <code>FUL-XXXXXX-XXXXX</code>.</td>\n</tr>\n<tr>\n<td><strong>reason</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Cancellation reason. Maximum 500 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns the updated fulfillment in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>. The <code>status</code> will be <code>canceled</code>.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Fulfillment not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Fulfillment cannot be canceled in its current status</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{{fulfillmentNumber}}","cancel"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"9b38065a-f91e-7482-99ea-7a1979270a4c"},{"name":"Reship","id":"44f3db2f-c181-a577-0ac7-ad4261135486","request":{"method":"POST","header":[{"key":"Accept","value":"application/json"},{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"reason\": \"Customer did not receive package\"\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}/reship","description":"<h1 id=\"reship\">Reship</h1>\n<p>Create a new replacement fulfillment from an existing one. Works regardless of the original fulfillment's current status. If the original was <code>shipped</code> or <code>delivered</code>, it is automatically marked as <code>returned</code>.</p>\n<p>The response returns the <strong>new</strong> fulfillment object. The new fulfillment's <code>metadata.is_reship</code> is <code>true</code>.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://api.sparkcrm.io/v1/fulfillments/FUL-260310-00001/reship\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.reship</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>fulfillmentNumber</strong></td>\n<td><em><strong>string (required, URL path)</strong></em>  <br />The original fulfillment number to reship. Format: <code>FUL-XXXXXX-XXXXX</code>.</td>\n</tr>\n<tr>\n<td><strong>reason</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Reship reason. Maximum 500 characters. Appears in shipping notes and order activity.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns the new reship fulfillment in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>. Its <code>metadata.is_reship</code> is <code>true</code> and <code>metadata.reship_count</code> is incremented.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Fulfillment not found</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{{fulfillmentNumber}}","reship"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"44f3db2f-c181-a577-0ac7-ad4261135486"},{"name":"Mark Shipped","id":"b61d601d-2f49-f7ea-ff5d-6c8c1084ab34","request":{"method":"POST","header":[{"key":"Accept","value":"application/json"},{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}/mark_shipped","description":"<h1 id=\"mark-shipped\">Mark Shipped</h1>\n<p>Update the fulfillment status to <code>shipped</code> and record the <code>shipped_at</code> timestamp. Triggers any webhooks, auto-responders, or system functionality configured for the shipped event.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://api.sparkcrm.io/v1/fulfillments/FUL-260310-00001/mark_shipped\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.mark_shipped</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body required.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>fulfillmentNumber</strong></td>\n<td><em><strong>string (required, URL path)</strong></em>  <br />The fulfillment number to mark as shipped. Format: <code>FUL-XXXXXX-XXXXX</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns the updated fulfillment in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>. The <code>status</code> will be <code>shipped</code> and <code>shipped_at</code> populated.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Fulfillment not found</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{{fulfillmentNumber}}","mark_shipped"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"b61d601d-2f49-f7ea-ff5d-6c8c1084ab34"},{"name":"Mark Delivered","id":"49d9032c-482e-005f-4770-0ccf3c5577c0","request":{"method":"POST","header":[{"value":"application/json","key":"Accept"},{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}/mark_delivered","description":"<h1 id=\"mark-delivered\">Mark Delivered</h1>\n<p>Update the fulfillment status to <code>delivered</code> and record the <code>delivered_at</code> timestamp. Triggers any webhooks, auto-responders, or system functionality configured for the delivered event.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://api.sparkcrm.io/v1/fulfillments/FUL-260310-00001/mark_delivered\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.mark_delivered</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body required.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>fulfillmentNumber</strong></td>\n<td><em><strong>string (required, URL path)</strong></em>  <br />The fulfillment number to mark as delivered. Format: <code>FUL-XXXXXX-XXXXX</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns the updated fulfillment in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>. The <code>status</code> will be <code>delivered</code> and <code>delivered_at</code> populated.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Fulfillment not found</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{{fulfillmentNumber}}","mark_delivered"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"49d9032c-482e-005f-4770-0ccf3c5577c0"}],"id":"6e56e23b-23c0-4a13-a81e-2fb4e9298a0d","_postman_id":"6e56e23b-23c0-4a13-a81e-2fb4e9298a0d","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Get Fulfillments (list/search)","id":"cc8fda64-658d-4f94-9b20-f245f3b656b7","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/fulfillments","description":"<h1 id=\"get-fulfillments-listsearch\">Get Fulfillments (list/search)</h1>\n<p><strong>List &amp; Search for Fulfillments</strong></p>\n<p>Retrieve fulfillments that match the specified search criteria with filtering and pagination support.</p>\n<h2 id=\"example--search-for-pending-fulfillments\">Example — Search for Pending Fulfillments</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/fulfillments?status=pending\n</code></pre><p>Returns a paginated list of all fulfillments currently in <code>pending</code> status for the authenticated team. Combine with <code>per_page</code>, <code>sort_by</code>, or any other filter to narrow the results further.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>order_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by order number. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>fulfillment_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by fulfillment number. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>shipping_group_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by shipping group number. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>tracking_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by tracking number. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>customer_email</strong></td>\n<td><em><strong>email (optional)</strong></em>  <br />Filter by customer email address. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>customer_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by customer number. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>status</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by fulfillment status. Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>fulfillment_type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by fulfillment type. Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>shipping_carrier</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by shipping carrier. Maximum 100 characters.</td>\n</tr>\n<tr>\n<td><strong>rma_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by RMA number. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>search</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Search across fulfillment number, shipping group number, tracking number, RMA number, shipping carrier, order number, customer email, and customer name. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n<tr>\n<td><strong>sort_by</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sort field. Options: created_at, updated_at, shipped_at, delivered_at, fulfillment_number. Default: created_at</td>\n</tr>\n<tr>\n<td><strong>sort_order</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sort order. Options: asc, desc. Default: desc</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of fulfillment objects matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_number</strong></td>\n<td><strong>string</strong>  <br />Fulfillment number — canonical identifier</td>\n</tr>\n<tr>\n<td><strong>data.shipping_group_number</strong></td>\n<td><strong>string</strong>  <br />Shipping group number</td>\n</tr>\n<tr>\n<td><strong>data.status</strong></td>\n<td><strong>string</strong>  <br />Current fulfillment status</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_type</strong></td>\n<td><strong>string</strong>  <br />Type of fulfillment</td>\n</tr>\n<tr>\n<td><strong>data.items</strong></td>\n<td><strong>array</strong>  <br />Items in the fulfillment</td>\n</tr>\n<tr>\n<td><strong>data.shipping_carrier</strong></td>\n<td><strong>string</strong>  <br />Shipping carrier name</td>\n</tr>\n<tr>\n<td><strong>data.shipping_service</strong></td>\n<td><strong>string</strong>  <br />Shipping service type</td>\n</tr>\n<tr>\n<td><strong>data.tracking_number</strong></td>\n<td><strong>string</strong>  <br />Package tracking number</td>\n</tr>\n<tr>\n<td><strong>data.tracking_urls</strong></td>\n<td><strong>array</strong>  <br />Array of tracking URLs</td>\n</tr>\n<tr>\n<td><strong>data.rma_number</strong></td>\n<td><strong>string</strong>  <br />Return merchandise authorization number</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the fulfillment was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the fulfillment was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.order</strong></td>\n<td><strong>object</strong>  <br />Associated order information</td>\n</tr>\n<tr>\n<td><strong>data.order.order_number</strong></td>\n<td><strong>string</strong>  <br />Order number</td>\n</tr>\n<tr>\n<td><strong>data.customer</strong></td>\n<td><strong>object</strong>  <br />Customer information (if available)</td>\n</tr>\n<tr>\n<td><strong>data.customer.customer_number</strong></td>\n<td><strong>string</strong>  <br />Customer's unique identifier</td>\n</tr>\n<tr>\n<td><strong>data.customer.email</strong></td>\n<td><strong>string</strong>  <br />Customer's email address</td>\n</tr>\n<tr>\n<td><strong>data.customer.name</strong></td>\n<td><strong>string</strong>  <br />Customer's full name</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of fulfillments matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of fulfillments displayed per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"a2109539-1b6a-4b20-8898-77a51b225a64","name":"Get Fulfillments","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://sparkcrm.test/v1/fulfillments?per_page=1","protocol":"https","host":["sparkcrm","test"],"path":["v1","fulfillments"],"query":[{"key":"per_page","value":"1","type":"text"}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:04:02 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": 543,\n            \"fulfillment_number\": \"FUL-250815-00543\",\n            \"shipping_group_number\": \"ccfafc41-daaf-3496-8ec4-db3804936b3f\",\n            \"status\": \"pending\",\n            \"fulfillment_type\": \"manual\",\n            \"items\": [\n                {\n                    \"quantity\": 1,\n                    \"product_id\": 1,\n                    \"unit_price\": \"299.99\",\n                    \"product_sku\": \"SKU-4991om\",\n                    \"total_price\": 299.99,\n                    \"product_name\": \"Smart Watch Pro\",\n                    \"base_quantity\": 1,\n                    \"order_quantity\": 1,\n                    \"product_options\": null\n                },\n                {\n                    \"quantity\": 1,\n                    \"product_id\": 8,\n                    \"unit_price\": \"45.99\",\n                    \"product_sku\": \"SKU-7191sf\",\n                    \"total_price\": 45.99,\n                    \"product_name\": \"Smart Water Bottle\",\n                    \"base_quantity\": 1,\n                    \"order_quantity\": 1,\n                    \"product_options\": null\n                }\n            ],\n            \"shipping_carrier\": null,\n            \"shipping_service\": null,\n            \"tracking_number\": null,\n            \"tracking_urls\": null,\n            \"rma_number\": null,\n            \"created_at\": \"2025-09-14T17:13:19.000000Z\",\n            \"updated_at\": \"2025-09-17T17:13:19.000000Z\",\n            \"order\": {\n                \"id\": 659,\n                \"order_number\": \"ORD-250815-00318\"\n            },\n            \"customer\": {\n                \"customer_number\": \"CUST-250815-00157\",\n                \"email\": \"lwest@example.net\",\n                \"name\": \"Bonita Botsford\"\n            }\n        }\n    ],\n    \"pagination\": {\n        \"total\": 1148,\n        \"per_page\": 1,\n        \"current_page\": 1,\n        \"last_page\": 1148,\n        \"from\": 1,\n        \"to\": 1\n    }\n}"}],"_postman_id":"cc8fda64-658d-4f94-9b20-f245f3b656b7"},{"name":"Get Fulfillment","id":"6e4ce771-17e9-4043-985e-7efd9433f001","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/fulfillments/{fulfillmentNumber}","description":"<h1 id=\"get-fulfillment\">Get Fulfillment</h1>\n<p>Retrieve detailed information for a specific fulfillment by fulfillment number.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body parameters. The fulfillment number is provided in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The requested fulfillment object with detailed information</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_number</strong></td>\n<td><strong>string</strong>  <br />Fulfillment number — canonical identifier</td>\n</tr>\n<tr>\n<td><strong>data.shipping_group_number</strong></td>\n<td><strong>string</strong>  <br />Shipping group number</td>\n</tr>\n<tr>\n<td><strong>data.status</strong></td>\n<td><strong>string</strong>  <br />Current fulfillment status</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_type</strong></td>\n<td><strong>string</strong>  <br />Type of fulfillment</td>\n</tr>\n<tr>\n<td><strong>data.items</strong></td>\n<td><strong>array</strong>  <br />Items in the fulfillment</td>\n</tr>\n<tr>\n<td><strong>data.shipping_carrier</strong></td>\n<td><strong>string</strong>  <br />Shipping carrier name</td>\n</tr>\n<tr>\n<td><strong>data.shipping_service</strong></td>\n<td><strong>string</strong>  <br />Shipping service type</td>\n</tr>\n<tr>\n<td><strong>data.tracking_number</strong></td>\n<td><strong>string</strong>  <br />Package tracking number</td>\n</tr>\n<tr>\n<td><strong>data.tracking_urls</strong></td>\n<td><strong>array</strong>  <br />Array of tracking URLs</td>\n</tr>\n<tr>\n<td><strong>data.rma_number</strong></td>\n<td><strong>string</strong>  <br />Return merchandise authorization number</td>\n</tr>\n<tr>\n<td><strong>data.external_fulfillment_id</strong></td>\n<td><strong>string</strong>  <br />External fulfillment provider ID</td>\n</tr>\n<tr>\n<td><strong>data.transaction_id</strong></td>\n<td><strong>integer</strong>  <br />Associated transaction ID</td>\n</tr>\n<tr>\n<td><strong>data.shipping_cost</strong></td>\n<td><strong>string</strong>  <br />Shipping cost amount</td>\n</tr>\n<tr>\n<td><strong>data.handling_cost</strong></td>\n<td><strong>string</strong>  <br />Handling cost amount</td>\n</tr>\n<tr>\n<td><strong>data.shipping_name</strong></td>\n<td><strong>string</strong>  <br />Recipient name</td>\n</tr>\n<tr>\n<td><strong>data.shipping_company</strong></td>\n<td><strong>string</strong>  <br />Recipient company</td>\n</tr>\n<tr>\n<td><strong>data.shipping_address1</strong></td>\n<td><strong>string</strong>  <br />Shipping address line 1</td>\n</tr>\n<tr>\n<td><strong>data.shipping_address2</strong></td>\n<td><strong>string</strong>  <br />Shipping address line 2</td>\n</tr>\n<tr>\n<td><strong>data.shipping_city</strong></td>\n<td><strong>string</strong>  <br />Shipping city</td>\n</tr>\n<tr>\n<td><strong>data.shipping_state</strong></td>\n<td><strong>string</strong>  <br />Shipping state/province</td>\n</tr>\n<tr>\n<td><strong>data.shipping_postal_code</strong></td>\n<td><strong>string</strong>  <br />Shipping postal code</td>\n</tr>\n<tr>\n<td><strong>data.shipping_country</strong></td>\n<td><strong>string</strong>  <br />Shipping country</td>\n</tr>\n<tr>\n<td><strong>data.shipping_phone</strong></td>\n<td><strong>string</strong>  <br />Recipient phone number</td>\n</tr>\n<tr>\n<td><strong>data.shipping_notes</strong></td>\n<td><strong>string</strong>  <br />Special shipping instructions</td>\n</tr>\n<tr>\n<td><strong>data.download_url</strong></td>\n<td><strong>string</strong>  <br />Download URL for digital fulfillments</td>\n</tr>\n<tr>\n<td><strong>data.download_limit</strong></td>\n<td><strong>integer</strong>  <br />Maximum number of downloads allowed</td>\n</tr>\n<tr>\n<td><strong>data.download_expiry</strong></td>\n<td><strong>string</strong>  <br />Download expiration date (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.return_status</strong></td>\n<td><strong>string</strong>  <br />Return status if applicable</td>\n</tr>\n<tr>\n<td><strong>data.return_reason</strong></td>\n<td><strong>string</strong>  <br />Reason for return</td>\n</tr>\n<tr>\n<td><strong>data.return_tracking_number</strong></td>\n<td><strong>string</strong>  <br />Return tracking number</td>\n</tr>\n<tr>\n<td><strong>data.return_meta</strong></td>\n<td><strong>object</strong>  <br />Additional return metadata</td>\n</tr>\n<tr>\n<td><strong>data.requires_signature</strong></td>\n<td><strong>boolean</strong>  <br />Whether delivery requires signature</td>\n</tr>\n<tr>\n<td><strong>data.is_gift</strong></td>\n<td><strong>boolean</strong>  <br />Whether fulfillment is marked as gift</td>\n</tr>\n<tr>\n<td><strong>data.is_backordered</strong></td>\n<td><strong>boolean</strong>  <br />Whether items are backordered</td>\n</tr>\n<tr>\n<td><strong>data.is_preorder</strong></td>\n<td><strong>boolean</strong>  <br />Whether items are preorders</td>\n</tr>\n<tr>\n<td><strong>data.is_custom</strong></td>\n<td><strong>boolean</strong>  <br />Whether fulfillment includes custom items</td>\n</tr>\n<tr>\n<td><strong>data.custom_fields</strong></td>\n<td><strong>object</strong>  <br />Custom field data</td>\n</tr>\n<tr>\n<td><strong>data.metadata</strong></td>\n<td><strong>object</strong>  <br />Additional metadata</td>\n</tr>\n<tr>\n<td><strong>data.rma_created_at</strong></td>\n<td><strong>string</strong>  <br />RMA creation date (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.rma_created_by</strong></td>\n<td><strong>string</strong>  <br />User who created the RMA</td>\n</tr>\n<tr>\n<td><strong>data.sent_to_shipper_at</strong></td>\n<td><strong>string</strong>  <br />Date sent to shipping provider (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.tracking_number_generated_at</strong></td>\n<td><strong>string</strong>  <br />Date tracking number was generated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.shipped_at</strong></td>\n<td><strong>string</strong>  <br />Date package was shipped (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.delivered_at</strong></td>\n<td><strong>string</strong>  <br />Date package was delivered (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.returned_at</strong></td>\n<td><strong>string</strong>  <br />Date package was returned (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the fulfillment was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the fulfillment was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.proof_images</strong></td>\n<td><strong>array</strong>  <br />Array of proof of delivery image URLs (if available)</td>\n</tr>\n<tr>\n<td><strong>data.order</strong></td>\n<td><strong>object</strong>  <br />Associated order information</td>\n</tr>\n<tr>\n<td><strong>data.order.order_number</strong></td>\n<td><strong>string</strong>  <br />Order number</td>\n</tr>\n<tr>\n<td><strong>data.customer</strong></td>\n<td><strong>object</strong>  <br />Customer information (if available)</td>\n</tr>\n<tr>\n<td><strong>data.customer.customer_number</strong></td>\n<td><strong>string</strong>  <br />Customer's unique identifier</td>\n</tr>\n<tr>\n<td><strong>data.customer.email</strong></td>\n<td><strong>string</strong>  <br />Customer's email address</td>\n</tr>\n<tr>\n<td><strong>data.customer.name</strong></td>\n<td><strong>string</strong>  <br />Customer's full name</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_provider</strong></td>\n<td><strong>object</strong>  <br />Fulfillment provider information (if available)</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_provider.name</strong></td>\n<td><strong>string</strong>  <br />Provider name</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_provider.integration_type</strong></td>\n<td><strong>string</strong>  <br />Integration type</td>\n</tr>\n<tr>\n<td><strong>data.fulfillment_provider.status</strong></td>\n<td><strong>string</strong>  <br />Provider status</td>\n</tr>\n<tr>\n<td><strong>data.products</strong></td>\n<td><strong>array</strong>  <br />Array of products in the fulfillment (if available)</td>\n</tr>\n<tr>\n<td><strong>data.products[].id</strong></td>\n<td><strong>integer</strong>  <br />Product ID — pass to <code>product_ids</code> on POST /v1/fulfillments</td>\n</tr>\n<tr>\n<td><strong>data.products[].name</strong></td>\n<td><strong>string</strong>  <br />Product name</td>\n</tr>\n<tr>\n<td><strong>data.products[].sku</strong></td>\n<td><strong>string</strong>  <br />Product SKU</td>\n</tr>\n<tr>\n<td><strong>data.products[].quantity</strong></td>\n<td><strong>integer</strong>  <br />Quantity of this product in the fulfillment</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{fulfillmentNumber}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"9d1069d6-57a4-4917-b2c5-9870ab982907","name":"Get Fulfillment","originalRequest":{"method":"GET","header":[],"url":"https://sparkcrm.test/v1/fulfillments/FUL-250815-00543"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:05:23 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"id\": 543,\n        \"fulfillment_number\": \"FUL-250815-00543\",\n        \"shipping_group_number\": \"ccfafc41-daaf-3496-8ec4-db3804936b3f\",\n        \"status\": \"pending\",\n        \"fulfillment_type\": \"manual\",\n        \"items\": [\n            {\n                \"quantity\": 1,\n                \"product_id\": 1,\n                \"unit_price\": \"299.99\",\n                \"product_sku\": \"SKU-4991om\",\n                \"total_price\": 299.99,\n                \"product_name\": \"Smart Watch Pro\",\n                \"base_quantity\": 1,\n                \"order_quantity\": 1,\n                \"product_options\": null\n            },\n            {\n                \"quantity\": 1,\n                \"product_id\": 8,\n                \"unit_price\": \"45.99\",\n                \"product_sku\": \"SKU-7191sf\",\n                \"total_price\": 45.99,\n                \"product_name\": \"Smart Water Bottle\",\n                \"base_quantity\": 1,\n                \"order_quantity\": 1,\n                \"product_options\": null\n            }\n        ],\n        \"shipping_carrier\": null,\n        \"shipping_service\": null,\n        \"tracking_number\": null,\n        \"tracking_urls\": null,\n        \"rma_number\": null,\n        \"created_at\": \"2025-09-14T17:13:19.000000Z\",\n        \"updated_at\": \"2025-09-17T17:13:19.000000Z\",\n        \"order\": {\n            \"id\": 659,\n            \"order_number\": \"ORD-250815-00318\"\n        },\n        \"customer\": {\n            \"customer_number\": \"CUST-250815-00157\",\n            \"email\": \"lwest@example.net\",\n            \"name\": \"Bonita Botsford\"\n        },\n        \"external_fulfillment_id\": \"SHIP00324\",\n        \"transaction_id\": 538,\n        \"shipping_cost\": \"36.44\",\n        \"handling_cost\": \"9.92\",\n        \"shipping_name\": \"Bonita Botsford\",\n        \"shipping_company\": \"Harvey-Hintz\",\n        \"shipping_address1\": \"52129 Collins Station\",\n        \"shipping_address2\": null,\n        \"shipping_city\": \"Issacborough\",\n        \"shipping_state\": \"TX\",\n        \"shipping_postal_code\": \"63857-0260\",\n        \"shipping_country\": \"US\",\n        \"shipping_phone\": \"+1-631-474-1299\",\n        \"shipping_notes\": null,\n        \"download_url\": null,\n        \"download_limit\": null,\n        \"download_expiry\": null,\n        \"return_status\": null,\n        \"return_reason\": null,\n        \"return_tracking_number\": null,\n        \"return_meta\": null,\n        \"requires_signature\": false,\n        \"is_gift\": true,\n        \"is_backordered\": false,\n        \"is_preorder\": false,\n        \"is_custom\": false,\n        \"custom_fields\": {\n            \"notes\": \"Ea quia est necessitatibus fuga ea aut.\",\n            \"source\": \"email\",\n            \"priority\": \"medium\"\n        },\n        \"metadata\": {\n            \"picker_id\": \"PICK977\",\n            \"bin_location\": \"ZONE09-SHELF14-BIN03\",\n            \"warehouse_id\": \"WH853\"\n        },\n        \"rma_created_at\": null,\n        \"rma_created_by\": null,\n        \"sent_to_shipper_at\": null,\n        \"tracking_number_generated_at\": null,\n        \"shipped_at\": null,\n        \"delivered_at\": null,\n        \"returned_at\": null,\n        \"products\": [\n            {\n                \"id\": 8,\n                \"name\": \"Smart Water Bottle\",\n                \"sku\": null,\n                \"quantity\": 1\n            },\n            {\n                \"id\": 1,\n                \"name\": \"Smart Watch Pro\",\n                \"sku\": null,\n                \"quantity\": 1\n            }\n        ]\n    }\n}"}],"_postman_id":"6e4ce771-17e9-4043-985e-7efd9433f001"},{"name":"Create Fulfillment","id":"d0909911-ae24-e705-941e-7bb630a8c1c1","request":{"method":"POST","header":[{"key":"Accept","value":"application/json"},{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"order_number\": \"ORD-XXXXXX-XXXXX\",\n  \"product_ids\": [1, 2]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments","description":"<h1 id=\"create-fulfillment\">Create Fulfillment</h1>\n<p>Create one or more fulfillments for an existing order. Returns an array of created fulfillments — one per fulfillment provider when products span multiple providers.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://api.sparkcrm.io/v1/fulfillments\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.create</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>order_number</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Order number (e.g. <code>ORD-841130-10316</code>).</td>\n</tr>\n<tr>\n<td><strong>product_ids</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />Specific product IDs to fulfill. If omitted, all products on the order are fulfilled.</td>\n</tr>\n<tr>\n<td><strong>transaction_id</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Specific transaction to attach. Defaults to the latest transaction on the order.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns an array of fulfillment objects in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>. One fulfillment per provider.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Order not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error — invalid order_number or product_ids</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"d0909911-ae24-e705-941e-7bb630a8c1c1"},{"name":"Update Fulfillment","id":"605801be-b361-5d74-c8a7-a54614f596c9","request":{"method":"PATCH","header":[{"value":"application/json","key":"Accept"},{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"tracking_number\": \"1Z999AA10123456784\",\n  \"shipping_carrier\": \"UPS\"\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/fulfillments/{{fulfillmentNumber}}","description":"<h1 id=\"update-fulfillment\">Update Fulfillment</h1>\n<p>Update a fulfillment's tracking info, shipping address, or status. All fields are optional (PATCH semantics).</p>\n<p><strong>Important:</strong> Providing a <code>tracking_number</code> automatically sets the status to <code>shipped</code> and dispatches tracking events — clients should not separately update the status when adding tracking.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>PATCH https://api.sparkcrm.io/v1/fulfillments/FUL-260310-00001\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:fulfillments.update</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>fulfillmentNumber</strong></td>\n<td><em><strong>string (required, URL path)</strong></em>  <br />The fulfillment number to update. Format: <code>FUL-XXXXXX-XXXXX</code>.</td>\n</tr>\n<tr>\n<td><strong>tracking_number</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Tracking number — auto-sets status to <code>shipped</code>.</td>\n</tr>\n<tr>\n<td><strong>shipping_carrier</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Carrier name (e.g., UPS, FedEx, USPS).</td>\n</tr>\n<tr>\n<td><strong>tracking_urls</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />Tracking URLs (each must be a valid URL).</td>\n</tr>\n<tr>\n<td><strong>shipping_name</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Recipient name.</td>\n</tr>\n<tr>\n<td><strong>shipping_address1</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Street address.</td>\n</tr>\n<tr>\n<td><strong>shipping_address2</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Suite / apt.</td>\n</tr>\n<tr>\n<td><strong>shipping_city</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />City.</td>\n</tr>\n<tr>\n<td><strong>shipping_state</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />State or province.</td>\n</tr>\n<tr>\n<td><strong>shipping_postal_code</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Postal code.</td>\n</tr>\n<tr>\n<td><strong>shipping_country</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />ISO 3166-1 alpha-2 country code (e.g., <code>US</code>).</td>\n</tr>\n<tr>\n<td><strong>status</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Override status. Any valid fulfillment status value.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns the updated fulfillment in the same shape as <code>GET /v1/fulfillments/{fulfillmentNumber}</code>.</p>\n<h2 id=\"error-responses\">Error Responses</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Token does not have permission to access this endpoint</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Fulfillment not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error — invalid fields</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","fulfillments","{{fulfillmentNumber}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"605801be-b361-5d74-c8a7-a54614f596c9"}],"id":"405a7a66-6297-4119-87f4-e78c68ffee93","_postman_id":"405a7a66-6297-4119-87f4-e78c68ffee93","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Orders","item":[{"name":"Notes","item":[{"name":"Get Order Notes","id":"3e54f66a-b2f9-41f1-a8f9-85e575aa9641","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/orders/{orderNumber}/notes","description":"<h1 id=\"get-order-notes\">Get Order Notes</h1>\n<p>Retrieve notes for a specific order that match the specified search criteria.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Filter notes by type. Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>search</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Search notes by title or content. Performs partial matching using SQL LIKE operations. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><strong><em>integer (optional)</em></strong>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of order note objects matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>order</strong></td>\n<td><strong>object</strong>  <br />Order information</td>\n</tr>\n<tr>\n<td><strong>order.order_number</strong></td>\n<td><strong>string</strong>  <br />Order's unique identifier</td>\n</tr>\n<tr>\n<td><strong>order.status</strong></td>\n<td><strong>string</strong>  <br />Current order status</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of notes matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of notes displayed per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","orders","{orderNumber}","notes"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"ecbbab19-a277-4b5a-9fed-f459d00c3291","name":"Get Order Notes","originalRequest":{"method":"GET","header":[],"body":{"mode":"urlencoded","urlencoded":[]},"url":"https://sparkcrm.test/v1/orders/ORD-250815-00297/notes"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:06:47 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": 1243,\n            \"title\": \"Iusto aperiam hic.\",\n            \"content\": \"Voluptatem quo dolores error autem. Consequatur explicabo velit quo aut veritatis modi eius. Odit harum maxime beatae velit officiis sed architecto.\",\n            \"type\": \"shipping\",\n            \"created_by\": \"Tempore deserunt blanditiis velit amet.\",\n            \"created_at\": \"2024-10-12T15:06:27.000000Z\",\n            \"updated_at\": \"2025-08-15T01:57:50.000000Z\"\n        }\n    ],\n    \"order\": {\n        \"order_number\": \"ORD-250815-00297\",\n        \"status\": \"completed\"\n    },\n    \"pagination\": {\n        \"total\": 1,\n        \"per_page\": 15,\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 1\n    }\n}"}],"_postman_id":"3e54f66a-b2f9-41f1-a8f9-85e575aa9641"},{"name":"Create Order Note","id":"8f92fa01-bca8-4a55-9307-aecd97a64c5c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"url":"https://api.sparkcrm.io/v1/orders/{orderNumber}/notes","description":"<h1 id=\"create-order-note\">Create Order Note</h1>\n<p>Create a new note for a specific order.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>title</strong></td>\n<td><strong><em>string (required)</em></strong>  <br />Note title. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>content</strong></td>\n<td><strong><em>string (required)</em></strong>  <br />Note content. Maximum 5000 characters.</td>\n</tr>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note type/category. Maximum 50 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The created note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","orders","{orderNumber}","notes"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"2dd05835-2d83-4c58-b12b-f6bec57e2266","name":"Create Order Note","originalRequest":{"method":"POST","header":[],"url":{"raw":"https://sparkcrm.test/v1/orders/ORD-250815-00297/notes?title=new note&content=New note for this order&type=shipping","protocol":"https","host":["sparkcrm","test"],"path":["v1","orders","ORD-250815-00297","notes"],"query":[{"key":"title","value":"new note","type":"text"},{"key":"content","value":"New note for this order","type":"text"},{"key":"type","value":"shipping","type":"text"}]}},"status":"Created","code":201,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:11:17 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note added successfully\",\n    \"data\": {\n        \"id\": 2018,\n        \"title\": \"new note\",\n        \"content\": \"New note for this order\",\n        \"type\": \"shipping\",\n        \"created_by\": 2,\n        \"created_at\": \"2025-09-17T03:11:17.000000Z\",\n        \"updated_at\": \"2025-09-17T03:11:17.000000Z\"\n    }\n}"}],"_postman_id":"8f92fa01-bca8-4a55-9307-aecd97a64c5c"},{"name":"Get Order Note","id":"e68eeb7a-a5b7-4dac-92ac-d61341bc4780","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/orders/{orderNumber}/notes/{noteId}","description":"<h1 id=\"get-specific-order-note\">Get Specific Order Note</h1>\n<p>Retrieve a specific note for an order by note ID.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body parameters. The order number and note ID are provided in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The requested note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","orders","{orderNumber}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"749946eb-a90a-45fc-924f-7e7db50a3206","name":"Get Order Note","originalRequest":{"method":"GET","header":[],"url":"https://sparkcrm.test/v1/orders/ORD-250815-00297/notes/1243"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:08:10 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"id\": 1243,\n        \"title\": \"Iusto aperiam hic.\",\n        \"content\": \"Voluptatem quo dolores error autem. Consequatur explicabo velit quo aut veritatis modi eius. Odit harum maxime beatae velit officiis sed architecto.\",\n        \"type\": \"shipping\",\n        \"created_by\": \"Tempore deserunt blanditiis velit amet.\",\n        \"created_at\": \"2024-10-12T15:06:27.000000Z\",\n        \"updated_at\": \"2025-08-15T01:57:50.000000Z\"\n    }\n}"}],"_postman_id":"e68eeb7a-a5b7-4dac-92ac-d61341bc4780"},{"name":"Update Order Note","id":"427d50ff-5cb0-49a1-9b93-812d862d9a12","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PUT","header":[],"url":"https://api.sparkcrm.io/v1/orders/{orderNumber}/notes/{noteId}","description":"<h1 id=\"update-order-note\">Update Order Note</h1>\n<p>Update an existing note for a specific order.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>title</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note title. Maximum 255 characters. Only required if updating the title.</td>\n</tr>\n<tr>\n<td><strong>content</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note content. Maximum 5000 characters. Only required if updating the content.</td>\n</tr>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note type/category. Maximum 50 characters. Can be set to null.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Note:</strong> At least one field must be provided to update the note. All fields use \"sometimes\" validation, meaning they're only validated if present in the request.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The updated note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","orders","{orderNumber}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"4448c22a-d72c-4c9f-ae54-0b2aba6a40d0","name":"Update Order Note","originalRequest":{"method":"PUT","header":[],"url":{"raw":"https://sparkcrm.test/v1/orders/ORD-250815-00297/notes/1243?content=updated note","protocol":"https","host":["sparkcrm","test"],"path":["v1","orders","ORD-250815-00297","notes","1243"],"query":[{"key":"content","value":"updated note","type":"text"}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:09:31 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note updated successfully\",\n    \"data\": {\n        \"id\": 1243,\n        \"title\": \"Iusto aperiam hic.\",\n        \"content\": \"updated note\",\n        \"type\": \"shipping\",\n        \"created_by\": \"Tempore deserunt blanditiis velit amet.\",\n        \"created_at\": \"2024-10-12T15:06:27.000000Z\",\n        \"updated_at\": \"2025-09-17T03:09:31.000000Z\"\n    }\n}"}],"_postman_id":"427d50ff-5cb0-49a1-9b93-812d862d9a12"},{"name":"Delete Order Note","id":"07aea145-674f-4086-9c6b-36bf27ab48f4","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/orders/{orderNumber}/notes/{noteId}","description":"<h1 id=\"delete-order-note\">Delete Order Note</h1>\n<p>Delete a specific note for an order by note ID.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body parameters. The order number and note ID are provided in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message confirming the note deletion</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","orders","{orderNumber}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"32d4e7dc-cbfd-4fcb-bab1-f644a0f269c6","name":"Delete Order Note","originalRequest":{"method":"DELETE","header":[],"url":"https://sparkcrm.test/v1/orders/ORD-250815-00297/notes/2018"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:12:16 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"0"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note deleted successfully\"\n}"}],"_postman_id":"07aea145-674f-4086-9c6b-36bf27ab48f4"}],"id":"3e8aa443-41b1-4a81-a107-b6ceb5cd5978","_postman_id":"3e8aa443-41b1-4a81-a107-b6ceb5cd5978","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}}],"id":"8cfedf34-e7f8-4a95-b416-0e4682d57d2a","_postman_id":"8cfedf34-e7f8-4a95-b416-0e4682d57d2a","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Products","item":[{"name":"Search Campaign Product(s)","id":"500b4b94-b764-4e59-b043-36fa042c0f4c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/campaigns/1/products?per_page=100","description":"<h1 id=\"get-campaign-products\">Get Campaign Products</h1>\n<p>Retrieve all products (offers and upsells combined) for a specific campaign. Products are returned sorted by position and can be filtered by type and active status.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>identifier</td>\n<td><em>string (required - URL parameter)</em>  <br />Campaign identifier (internal ID only) to get products for</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><em>string (optional)</em>  <br />Filter products by active status. Supported values: <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code></td>\n</tr>\n<tr>\n<td>product_type</td>\n<td><em>string (optional)</em>  <br />Filter by product type. Supported values: <code>offer</code>, <code>upsell</code>. If not provided, returns both offers and upsells.</td>\n</tr>\n<tr>\n<td>per_page</td>\n<td><em>integer (optional)</em>  <br />Number of results per page. Minimum: 1, Maximum: 15. Default: 15</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>success</td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td>data</td>\n<td><strong>array</strong>  <br />Array of product objects (offers and upsells combined) sorted by position</td>\n</tr>\n<tr>\n<td>data[].id</td>\n<td><strong>integer</strong>  <br />Unique identifier for the product (offer or upsell)</td>\n</tr>\n<tr>\n<td>data[].internal_id</td>\n<td><strong>string</strong>  <br />Internal identifier for the product</td>\n</tr>\n<tr>\n<td>data[].name</td>\n<td><strong>string</strong>  <br />Product name (for upsells, uses product name or defaults to \"Upsell Product\")</td>\n</tr>\n<tr>\n<td>data[].product_type</td>\n<td><strong>string</strong>  <br />Type of product: <code>offer</code> or <code>upsell</code></td>\n</tr>\n<tr>\n<td>data[].is_active</td>\n<td><strong>boolean</strong>  <br />Indicates if the product is currently active</td>\n</tr>\n<tr>\n<td>data[].position</td>\n<td><strong>integer</strong>  <br />Position/order of the product in the sales funnel</td>\n</tr>\n<tr>\n<td>data[].price</td>\n<td><strong>string</strong>  <br />Product price in smallest currency unit (e.g., cents)</td>\n</tr>\n<tr>\n<td>data[].shipping_price</td>\n<td><strong>string</strong>  <br />Shipping cost for the product</td>\n</tr>\n<tr>\n<td>data[].tax_rate</td>\n<td><strong>string</strong>  <br />Tax rate applied to the product</td>\n</tr>\n<tr>\n<td>data[].is_tax_included</td>\n<td><strong>boolean</strong>  <br />Indicates if tax is included in the price</td>\n</tr>\n<tr>\n<td>data[].dynamic_descriptor</td>\n<td><strong>string</strong>  <br />Dynamic descriptor for payment processing</td>\n</tr>\n<tr>\n<td>data[].sale_type</td>\n<td><strong>string/null</strong>  <br />Type of sale (e.g., \"one_time\", \"subscription\")</td>\n</tr>\n<tr>\n<td>data[].subscription_config</td>\n<td><strong>object/null</strong>  <br />Subscription configuration details</td>\n</tr>\n<tr>\n<td>data[].allow_duplicates</td>\n<td><strong>boolean/null</strong>  <br />Whether duplicates are allowed (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].requires_shipping_on_trial</td>\n<td><strong>boolean/null</strong>  <br />Whether shipping is required on trial (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].billing_interval</td>\n<td><strong>string/null</strong>  <br />Billing interval for subscriptions (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].billing_cycles</td>\n<td><strong>integer/null</strong>  <br />Number of billing cycles (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].billing_schedule</td>\n<td><strong>object/null</strong>  <br />Billing schedule details (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].use_offer_gateway</td>\n<td><strong>boolean/null</strong>  <br />Whether to use offer gateway (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].gateway_id</td>\n<td><strong>integer/null</strong>  <br />Payment gateway ID (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].payment_orchestrator_id</td>\n<td><strong>integer/null</strong>  <br />Payment orchestrator ID (upsell-specific, null for offers)</td>\n</tr>\n<tr>\n<td>data[].product</td>\n<td><strong>object/null</strong>  <br />Associated product information</td>\n</tr>\n<tr>\n<td>data[].product.id</td>\n<td><strong>integer</strong>  <br />Unique identifier for the associated product</td>\n</tr>\n<tr>\n<td>data[].product.name</td>\n<td><strong>string</strong>  <br />Name of the associated product</td>\n</tr>\n<tr>\n<td>data[].product.sku</td>\n<td><strong>string</strong>  <br />Stock keeping unit (SKU) of the product</td>\n</tr>\n<tr>\n<td>data[].product.description</td>\n<td><strong>string</strong>  <br />Product description</td>\n</tr>\n<tr>\n<td>data[].product.weight</td>\n<td><strong>string</strong>  <br />Product weight</td>\n</tr>\n<tr>\n<td>data[].product.dimensions</td>\n<td><strong>object</strong>  <br />Product dimensions (length, width, height)</td>\n</tr>\n<tr>\n<td>data[].product.requires_shipping</td>\n<td><strong>boolean</strong>  <br />Whether the product requires shipping</td>\n</tr>\n<tr>\n<td>data[].created_at</td>\n<td><strong>string</strong>  <br />Date and time when the product was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>data[].updated_at</td>\n<td><strong>string</strong>  <br />Date and time when the product was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td>campaign</td>\n<td><strong>object</strong>  <br />Campaign information</td>\n</tr>\n<tr>\n<td>campaign.internal_id</td>\n<td><strong>string</strong>  <br />Internal identifier of the campaign</td>\n</tr>\n<tr>\n<td>campaign.name</td>\n<td><strong>string</strong>  <br />Name of the campaign</td>\n</tr>\n<tr>\n<td>campaign.uuid</td>\n<td><strong>string</strong>  <br />UUID of the campaign</td>\n</tr>\n<tr>\n<td>pagination</td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td>pagination.total</td>\n<td><strong>integer</strong>  <br />Total number of products matching the criteria</td>\n</tr>\n<tr>\n<td>pagination.per_page</td>\n<td><strong>integer</strong>  <br />Number of products displayed per page</td>\n</tr>\n<tr>\n<td>pagination.current_page</td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td>pagination.last_page</td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td>pagination.from</td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td>pagination.to</td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example-requests\">Example Requests</h2>\n<h3 id=\"get-all-campaign-products\">Get All Campaign Products</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns/123/products\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n</code></pre>\n<h3 id=\"get-active-products-only\">Get Active Products Only</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns/123/products?is_active=true\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n</code></pre>\n<h3 id=\"get-offers-only\">Get Offers Only</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns/123/products?product_type=offer\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n</code></pre>\n<h3 id=\"get-upsells-only\">Get Upsells Only</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns/123/products?product_type=upsell\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n</code></pre>\n<h3 id=\"get-active-offers-with-pagination\">Get Active Offers with Pagination</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/campaigns/123/products?product_type=offer&amp;is_active=true&amp;per_page=10\nAuthorization: Bearer YOUR_API_KEY_HERE\nContent-Type: application/json\nAccept: application/json\n</code></pre>\n<h2 id=\"example-response\">Example Response</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 1,\n      \"internal_id\": \"offer_001\",\n      \"name\": \"Premium Package\",\n      \"product_type\": \"offer\",\n      \"is_active\": true,\n      \"position\": 1,\n      \"price\": \"2999\",\n      \"shipping_price\": \"599\",\n      \"tax_rate\": \"0.08\",\n      \"is_tax_included\": false,\n      \"dynamic_descriptor\": \"PREMIUM PKG\",\n      \"sale_type\": \"one_time\",\n      \"subscription_config\": null,\n      \"allow_duplicates\": null,\n      \"requires_shipping_on_trial\": null,\n      \"billing_interval\": null,\n      \"billing_cycles\": null,\n      \"billing_schedule\": null,\n      \"use_offer_gateway\": null,\n      \"gateway_id\": null,\n      \"payment_orchestrator_id\": null,\n      \"product\": {\n        \"id\": 1,\n        \"name\": \"Premium Package\",\n        \"sku\": \"PREM-001\",\n        \"description\": \"Our premium package with all features included\",\n        \"weight\": \"2.5\",\n        \"dimensions\": {\n          \"length\": \"10\",\n          \"width\": \"8\",\n          \"height\": \"6\"\n        },\n        \"requires_shipping\": true\n      },\n      \"created_at\": \"2024-01-15T10:30:00.000Z\",\n      \"updated_at\": \"2024-01-20T14:45:00.000Z\"\n    },\n    {\n      \"id\": 2,\n      \"internal_id\": \"upsell_001\",\n      \"name\": \"Extended Warranty\",\n      \"product_type\": \"upsell\",\n      \"is_active\": true,\n      \"position\": 2,\n      \"price\": \"999\",\n      \"shipping_price\": \"0\",\n      \"tax_rate\": \"0.08\",\n      \"is_tax_included\": false,\n      \"dynamic_descriptor\": \"WARRANTY\",\n      \"sale_type\": \"subscription\",\n      \"subscription_config\": {\n        \"interval\": \"monthly\",\n        \"cycles\": 12\n      },\n      \"allow_duplicates\": false,\n      \"requires_shipping_on_trial\": false,\n      \"billing_interval\": \"monthly\",\n      \"billing_cycles\": 12,\n      \"billing_schedule\": {\n        \"start_date\": \"immediate\",\n        \"trial_days\": 0\n      },\n      \"use_offer_gateway\": true,\n      \"gateway_id\": null,\n      \"payment_orchestrator_id\": null,\n      \"product\": {\n        \"id\": 2,\n        \"name\": \"Extended Warranty\",\n        \"sku\": \"WARR-001\",\n        \"description\": \"12-month extended warranty coverage\",\n        \"weight\": \"0\",\n        \"dimensions\": null,\n        \"requires_shipping\": false\n      },\n      \"created_at\": \"2024-01-15T11:00:00.000Z\",\n      \"updated_at\": \"2024-01-20T15:00:00.000Z\"\n    }\n  ],\n  \"campaign\": {\n    \"internal_id\": \"123\",\n    \"name\": \"Summer Sale Campaign\",\n    \"uuid\": \"550e8400-e29b-41d4-a716-446655440000\"\n  },\n  \"pagination\": {\n    \"total\": 2,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 2\n  }\n}\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","campaigns","1","products"],"host":["api","sparkcrm","io"],"query":[{"key":"per_page","value":"100"}],"variable":[]}},"response":[{"id":"d3ebe52a-1d94-42a0-9866-e73f4550d431","name":"Search Campaign Product(s)","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/campaigns/1/products?is_active=true","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","campaigns","1","products"],"query":[{"key":"is_active","value":"true"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.7"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 18 Jun 2025 17:47:42 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"60000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": 1,\n            \"name\": \"Smart Watch Bundle\",\n            \"product_type\": \"offer\",\n            \"is_active\": true,\n            \"position\": 0,\n            \"price\": \"50.00\",\n            \"shipping_price\": \"0.00\",\n            \"tax_rate\": \"0.00\",\n            \"is_tax_included\": true,\n            \"dynamic_descriptor\": \"\",\n            \"sale_type\": \"none\",\n            \"subscription_config\": [],\n            \"allow_duplicates\": null,\n            \"requires_shipping_on_trial\": null,\n            \"billing_interval\": null,\n            \"billing_cycles\": null,\n            \"billing_schedule\": null,\n            \"use_offer_gateway\": null,\n            \"base_product\": {\n                \"id\": 1,\n                \"name\": \"Smart Watch Pro\",\n                \"quantity\": 1,\n                \"sku\": null,\n                \"description\": \"Advanced smartwatch with health tracking features\",\n                \"weight\": null,\n                \"dimensions\": null,\n                \"requires_shipping\": true\n            },\n            \"created_at\": \"2025-03-25T20:57:55.000000Z\",\n            \"updated_at\": \"2025-03-25T20:57:55.000000Z\"\n        },\n        {\n            \"id\": 2,\n            \"name\": \"Smart LED Bulb\",\n            \"product_type\": \"offer\",\n            \"is_active\": true,\n            \"position\": 0,\n            \"price\": \"144.00\",\n            \"shipping_price\": \"0.00\",\n            \"tax_rate\": \"0.00\",\n            \"is_tax_included\": true,\n            \"dynamic_descriptor\": \"\",\n            \"sale_type\": \"none\",\n            \"subscription_config\": [],\n            \"allow_duplicates\": null,\n            \"requires_shipping_on_trial\": null,\n            \"billing_interval\": null,\n            \"billing_cycles\": null,\n            \"billing_schedule\": null,\n            \"use_offer_gateway\": null,\n            \"base_product\": {\n                \"id\": 6,\n                \"name\": \"Smart LED Bulb\",\n                \"quantity\": 1,\n                \"sku\": null,\n                \"description\": \"WiFi-enabled LED bulb with millions of colors\",\n                \"weight\": null,\n                \"dimensions\": null,\n                \"requires_shipping\": true\n            },\n            \"created_at\": \"2025-03-25T21:26:14.000000Z\",\n            \"updated_at\": \"2025-03-25T21:26:14.000000Z\"\n        }\n    ],\n    \"campaign\": {\n        \"id\": 1,\n        \"name\": \"smartwatch.com\"\n    },\n    \"pagination\": {\n        \"total\": 2,\n        \"per_page\": \"100\",\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 2\n    }\n}"}],"_postman_id":"500b4b94-b764-4e59-b043-36fa042c0f4c"},{"name":"List Products","id":"36782395-4126-1344-2421-3cc8df99d36f","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/products?per_page=15&page=1&search=tshirt&is_active=true&product_type=physical","description":"<h1 id=\"list-products\">List Products</h1>\n<p><strong>Retrieve a paginated list of products for the authenticated account.</strong></p>\n<p>Returns products belonging to the authenticated team, ordered by <code>created_at</code> descending (newest first). Supports filtering by active status and product type, plus free-text search across product name, SKU, and internal id.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:products.view_any</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>search</code></td>\n<td><em><strong>string (optional)</strong></em> Free-text search. Matches <code>name</code> (LIKE), <code>sku</code> (LIKE), and <code>internal_id</code> (exact match, only when the term is all digits). Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Filter by active state. <code>true</code> returns active products, <code>false</code> returns inactive. Omit to return both.</td>\n</tr>\n<tr>\n<td><code>product_type</code></td>\n<td><em><strong>string (optional)</strong></em> Filter by product type. One of <code>physical</code>, <code>digital</code>, <code>subscription</code>.</td>\n</tr>\n<tr>\n<td><code>per_page</code></td>\n<td><em><strong>integer (optional)</strong></em> Number of results per page. Min <code>1</code>, max <code>100</code>. Defaults to <code>15</code>.</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td><em><strong>integer (optional)</strong></em> Page number to retrieve. Min <code>1</code>. Defaults to <code>1</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code>, a <code>data[]</code> array of product summary objects, and a <code>pagination</code> object. List items use the summary (non-detailed) shape.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>data[].id</code></td>\n<td><em>integer</em> The product's account-scoped <code>internal_id</code>. Use this value as <code>{product_id}</code> in detail/update routes.</td>\n</tr>\n<tr>\n<td><code>data[].name</code></td>\n<td><em>string</em> Product name.</td>\n</tr>\n<tr>\n<td><code>data[].slug</code></td>\n<td><em>string</em> URL slug (auto-generated from name on creation when omitted).</td>\n</tr>\n<tr>\n<td><code>data[].sku</code></td>\n<td><em>string | null</em> Stock keeping unit.</td>\n</tr>\n<tr>\n<td><code>data[].barcode</code></td>\n<td><em>string | null</em> Barcode value.</td>\n</tr>\n<tr>\n<td><code>data[].product_type</code></td>\n<td><em>string | null</em> One of <code>physical</code>, <code>digital</code>, <code>subscription</code>.</td>\n</tr>\n<tr>\n<td><code>data[].fulfillment_type</code></td>\n<td><em>string | null</em> One of <code>physical</code>, <code>digital</code>, <code>email</code>, <code>manual</code>.</td>\n</tr>\n<tr>\n<td><code>data[].price</code></td>\n<td><em>string</em> Selling price, formatted to 2 decimals.</td>\n</tr>\n<tr>\n<td><code>data[].cost</code></td>\n<td><em>string | null</em> Unit cost, 2 decimals.</td>\n</tr>\n<tr>\n<td><code>data[].estimated_shipping_cost</code></td>\n<td><em>string | null</em> Estimated shipping cost, 2 decimals.</td>\n</tr>\n<tr>\n<td><code>data[].description</code></td>\n<td><em>string | null</em> Full product description.</td>\n</tr>\n<tr>\n<td><code>data[].short_description</code></td>\n<td><em>string | null</em> Short description.</td>\n</tr>\n<tr>\n<td><code>data[].requires_shipping</code></td>\n<td><em>boolean</em> Whether the product requires physical shipping.</td>\n</tr>\n<tr>\n<td><code>data[].is_active</code></td>\n<td><em>boolean</em> Whether the product is active.</td>\n</tr>\n<tr>\n<td><code>data[].is_taxable</code></td>\n<td><em>boolean</em> Whether tax applies to the product.</td>\n</tr>\n<tr>\n<td><code>data[].track_inventory</code></td>\n<td><em>boolean</em> Whether inventory is tracked for the product.</td>\n</tr>\n<tr>\n<td><code>data[].stock</code></td>\n<td><em>integer | null</em> Current stock level.</td>\n</tr>\n<tr>\n<td><code>data[].quantity</code></td>\n<td><em>integer | null</em> Quantity value.</td>\n</tr>\n<tr>\n<td><code>data[].low_stock_threshold</code></td>\n<td><em>integer | null</em> Stock level at which the product is considered low stock.</td>\n</tr>\n<tr>\n<td><code>data[].created_at</code></td>\n<td><em>string (ISO 8601)</em> Creation timestamp.</td>\n</tr>\n<tr>\n<td><code>data[].updated_at</code></td>\n<td><em>string (ISO 8601)</em> Last update timestamp.</td>\n</tr>\n<tr>\n<td><code>pagination.total</code></td>\n<td><em>integer</em> Total number of matching products.</td>\n</tr>\n<tr>\n<td><code>pagination.per_page</code></td>\n<td><em>integer</em> Results per page.</td>\n</tr>\n<tr>\n<td><code>pagination.current_page</code></td>\n<td><em>integer</em> Current page number.</td>\n</tr>\n<tr>\n<td><code>pagination.last_page</code></td>\n<td><em>integer</em> Last available page.</td>\n</tr>\n<tr>\n<td><code>pagination.from</code></td>\n<td><em>integer | null</em> Index of the first item on the page.</td>\n</tr>\n<tr>\n<td><code>pagination.to</code></td>\n<td><em>integer | null</em> Index of the last item on the page.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the necessary permissions (<code>api:products.view_any</code>).</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error (e.g. invalid <code>product_type</code>, <code>per_page</code> out of range, non-boolean <code>is_active</code>).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong></p>\n<p><code>GET /v1/products?per_page=2&amp;product_type=physical&amp;is_active=true</code></p>\n<p><strong>Response</strong> <code>200 OK</code> — see the example response.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","products"],"host":["api","sparkcrm","io"],"query":[{"description":{"content":"<p>Optional free-text search. Matches against product name (LIKE), sku (LIKE), and internal_id (exact, when the search term is all digits). Max 255 characters.</p>\n","type":"text/plain"},"key":"search","value":"tshirt"},{"description":{"content":"<p>Optional boolean filter. true returns only active products, false only inactive. Omit to return both. Accepts true/false/1/0.</p>\n","type":"text/plain"},"key":"is_active","value":"true"},{"description":{"content":"<p>Optional. Filter by product type. One of: physical, digital, subscription.</p>\n","type":"text/plain"},"key":"product_type","value":"physical"},{"description":{"content":"<p>Optional. Results per page. Integer between 1 and 100. Defaults to 15.</p>\n","type":"text/plain"},"key":"per_page","value":"15"},{"description":{"content":"<p>Optional. Page number to retrieve. Integer, min 1. Defaults to 1.</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"2f592f28-8011-7d9b-58cf-c6364d5e67c3","name":"List Products","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/products?per_page=15&page=1&search=tshirt&is_active=true&product_type=physical","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","products"],"query":[{"key":"search","description":"Optional free-text search. Matches against product name (LIKE), sku (LIKE), and internal_id (exact, when the search term is all digits). Max 255 characters.","value":"tshirt"},{"key":"is_active","description":"Optional boolean filter. true returns only active products, false only inactive. Omit to return both. Accepts true/false/1/0.","value":"true"},{"key":"product_type","description":"Optional. Filter by product type. One of: physical, digital, subscription.","value":"physical"},{"key":"per_page","description":"Optional. Results per page. Integer between 1 and 100. Defaults to 15.","value":"15"},{"key":"page","description":"Optional. Page number to retrieve. Integer, min 1. Defaults to 1.","value":"1"}]},"description":"# List Products\n\n**Retrieve a paginated list of products for the authenticated account.**\n\nReturns products belonging to the authenticated team, ordered by `created_at` descending (newest first). Supports filtering by active status and product type, plus free-text search across product name, SKU, and internal id.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:products.view_any`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `search` | _**string (optional)**_ Free-text search. Matches `name` (LIKE), `sku` (LIKE), and `internal_id` (exact match, only when the term is all digits). Max 255 characters. |\n| `is_active` | _**boolean (optional)**_ Filter by active state. `true` returns active products, `false` returns inactive. Omit to return both. |\n| `product_type` | _**string (optional)**_ Filter by product type. One of `physical`, `digital`, `subscription`. |\n| `per_page` | _**integer (optional)**_ Number of results per page. Min `1`, max `100`. Defaults to `15`. |\n| `page` | _**integer (optional)**_ Page number to retrieve. Min `1`. Defaults to `1`. |\n\n## Response Object\n\nReturns `success: true`, a `data[]` array of product summary objects, and a `pagination` object. List items use the summary (non-detailed) shape.\n\n| Field | Description |\n| --- | --- |\n| `data[].id` | _integer_ The product's account-scoped `internal_id`. Use this value as `{product_id}` in detail/update routes. |\n| `data[].name` | _string_ Product name. |\n| `data[].slug` | _string_ URL slug (auto-generated from name on creation when omitted). |\n| `data[].sku` | _string \\| null_ Stock keeping unit. |\n| `data[].barcode` | _string \\| null_ Barcode value. |\n| `data[].product_type` | _string \\| null_ One of `physical`, `digital`, `subscription`. |\n| `data[].fulfillment_type` | _string \\| null_ One of `physical`, `digital`, `email`, `manual`. |\n| `data[].price` | _string_ Selling price, formatted to 2 decimals. |\n| `data[].cost` | _string \\| null_ Unit cost, 2 decimals. |\n| `data[].estimated_shipping_cost` | _string \\| null_ Estimated shipping cost, 2 decimals. |\n| `data[].description` | _string \\| null_ Full product description. |\n| `data[].short_description` | _string \\| null_ Short description. |\n| `data[].requires_shipping` | _boolean_ Whether the product requires physical shipping. |\n| `data[].is_active` | _boolean_ Whether the product is active. |\n| `data[].is_taxable` | _boolean_ Whether tax applies to the product. |\n| `data[].track_inventory` | _boolean_ Whether inventory is tracked for the product. |\n| `data[].stock` | _integer \\| null_ Current stock level. |\n| `data[].quantity` | _integer \\| null_ Quantity value. |\n| `data[].low_stock_threshold` | _integer \\| null_ Stock level at which the product is considered low stock. |\n| `data[].created_at` | _string (ISO 8601)_ Creation timestamp. |\n| `data[].updated_at` | _string (ISO 8601)_ Last update timestamp. |\n| `pagination.total` | _integer_ Total number of matching products. |\n| `pagination.per_page` | _integer_ Results per page. |\n| `pagination.current_page` | _integer_ Current page number. |\n| `pagination.last_page` | _integer_ Last available page. |\n| `pagination.from` | _integer \\| null_ Index of the first item on the page. |\n| `pagination.to` | _integer \\| null_ Index of the last item on the page. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the necessary permissions (`api:products.view_any`). |\n| `422` | Validation error (e.g. invalid `product_type`, `per_page` out of range, non-boolean `is_active`). |\n\n## Example\n\n**Request**\n\n`GET /v1/products?per_page=2&product_type=physical&is_active=true`\n\n**Response** `200 OK` — see the example response."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 1042,\n      \"name\": \"Classic Cotton T-Shirt\",\n      \"slug\": \"classic-cotton-t-shirt\",\n      \"sku\": \"TSHIRT-CLS-001\",\n      \"barcode\": \"0123456789012\",\n      \"product_type\": \"physical\",\n      \"fulfillment_type\": \"physical\",\n      \"price\": \"29.99\",\n      \"cost\": \"8.50\",\n      \"estimated_shipping_cost\": \"4.95\",\n      \"description\": \"A soft, durable 100% cotton t-shirt available in multiple colors.\",\n      \"short_description\": \"100% cotton crew-neck tee.\",\n      \"requires_shipping\": true,\n      \"is_active\": true,\n      \"is_taxable\": true,\n      \"track_inventory\": true,\n      \"stock\": 250,\n      \"quantity\": 1,\n      \"low_stock_threshold\": 25,\n      \"created_at\": \"2026-06-10T14:22:05.000000Z\",\n      \"updated_at\": \"2026-06-15T09:01:44.000000Z\"\n    },\n    {\n      \"id\": 1041,\n      \"name\": \"Premium Hoodie\",\n      \"slug\": \"premium-hoodie\",\n      \"sku\": \"HOODIE-PRM-002\",\n      \"barcode\": null,\n      \"product_type\": \"physical\",\n      \"fulfillment_type\": \"physical\",\n      \"price\": \"59.00\",\n      \"cost\": \"18.00\",\n      \"estimated_shipping_cost\": \"6.50\",\n      \"description\": null,\n      \"short_description\": \"Fleece-lined pullover hoodie.\",\n      \"requires_shipping\": true,\n      \"is_active\": true,\n      \"is_taxable\": true,\n      \"track_inventory\": true,\n      \"stock\": 80,\n      \"quantity\": 1,\n      \"low_stock_threshold\": 10,\n      \"created_at\": \"2026-06-09T11:10:33.000000Z\",\n      \"updated_at\": \"2026-06-09T11:10:33.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 37,\n    \"per_page\": 2,\n    \"current_page\": 1,\n    \"last_page\": 19,\n    \"from\": 1,\n    \"to\": 2\n  }\n}"}],"_postman_id":"36782395-4126-1344-2421-3cc8df99d36f"},{"name":"Create Product","id":"4747a804-e1a8-47bf-9e35-18e6ad312824","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Classic Cotton T-Shirt\",\n  \"price\": 29.99,\n  \"product_type\": \"physical\",\n  \"fulfillment_type\": \"physical\",\n  \"category_id\": 7,\n  \"fulfillment_provider_id\": 3,\n  \"description\": \"A soft, durable 100% cotton t-shirt available in multiple colors.\",\n  \"short_description\": \"100% cotton crew-neck tee.\",\n  \"sku\": \"TSHIRT-CLS-001\",\n  \"barcode\": \"0123456789012\",\n  \"cost\": 8.50,\n  \"estimated_shipping_cost\": 4.95,\n  \"track_inventory\": true,\n  \"stock\": 250,\n  \"quantity\": 1,\n  \"low_stock_threshold\": 25,\n  \"weight\": 0.30,\n  \"length\": 25.00,\n  \"width\": 20.00,\n  \"height\": 2.00,\n  \"weight_unit\": \"kg\",\n  \"dimension_unit\": \"cm\",\n  \"is_taxable\": true,\n  \"tax_class\": \"standard\",\n  \"tax_code\": \"PC040000\",\n  \"requires_shipping\": true,\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/products","description":"<h1 id=\"create-product\">Create Product</h1>\n<p><strong>Create a new product for the authenticated account.</strong></p>\n<p>Creates a product owned by the authenticated team. <code>internal_id</code> and <code>slug</code> are generated automatically (the slug derives from <code>name</code> when omitted). On success the full (detailed) product object is returned with HTTP <code>201</code>.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:products.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (required)</strong></em> Product name. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td><em><strong>numeric (required)</strong></em> Selling price. Min <code>0</code>. Stored with 2-decimal precision.</td>\n</tr>\n<tr>\n<td><code>product_type</code></td>\n<td><em><strong>string (optional)</strong></em> Product type. One of <code>physical</code>, <code>digital</code>, <code>subscription</code>.</td>\n</tr>\n<tr>\n<td><code>fulfillment_type</code></td>\n<td><em><strong>string (optional)</strong></em> How the product is fulfilled. One of <code>physical</code> (physical shipping), <code>digital</code> (digital download), <code>email</code> (email delivery), <code>manual</code> (manual fulfillment).</td>\n</tr>\n<tr>\n<td><code>category_id</code></td>\n<td><em><strong>integer (optional)</strong></em> ID of a <code>product_categories</code> row. Must exist and belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><code>fulfillment_provider_id</code></td>\n<td><em><strong>integer (optional)</strong></em> ID of a <code>fulfillment_providers</code> row. Must exist and belong to the authenticated team.</td>\n</tr>\n<tr>\n<td><code>description</code></td>\n<td><em><strong>string (optional)</strong></em> Full product description. No max length.</td>\n</tr>\n<tr>\n<td><code>short_description</code></td>\n<td><em><strong>string (optional)</strong></em> Short description. Max 500 characters.</td>\n</tr>\n<tr>\n<td><code>sku</code></td>\n<td><em><strong>string (optional)</strong></em> Stock keeping unit. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>barcode</code></td>\n<td><em><strong>string (optional)</strong></em> Barcode value. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>cost</code></td>\n<td><em><strong>numeric (optional)</strong></em> Unit cost. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>estimated_shipping_cost</code></td>\n<td><em><strong>numeric (optional)</strong></em> Estimated shipping cost. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>track_inventory</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether to track inventory for this product.</td>\n</tr>\n<tr>\n<td><code>stock</code></td>\n<td><em><strong>integer (optional)</strong></em> Current stock level. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>quantity</code></td>\n<td><em><strong>integer (optional)</strong></em> Quantity. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>low_stock_threshold</code></td>\n<td><em><strong>integer (optional)</strong></em> Stock level considered low. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>weight</code></td>\n<td><em><strong>numeric (optional)</strong></em> Product weight. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>length</code></td>\n<td><em><strong>numeric (optional)</strong></em> Length dimension. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>width</code></td>\n<td><em><strong>numeric (optional)</strong></em> Width dimension. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>height</code></td>\n<td><em><strong>numeric (optional)</strong></em> Height dimension. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>weight_unit</code></td>\n<td><em><strong>string (optional)</strong></em> Unit for <code>weight</code> (e.g. <code>kg</code>, <code>lb</code>). Max 20 characters.</td>\n</tr>\n<tr>\n<td><code>dimension_unit</code></td>\n<td><em><strong>string (optional)</strong></em> Unit for dimensions (e.g. <code>cm</code>, <code>in</code>). Max 20 characters.</td>\n</tr>\n<tr>\n<td><code>is_taxable</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether tax applies to the product.</td>\n</tr>\n<tr>\n<td><code>tax_class</code></td>\n<td><em><strong>string (optional)</strong></em> Tax class identifier. Max 100 characters.</td>\n</tr>\n<tr>\n<td><code>tax_code</code></td>\n<td><em><strong>string (optional)</strong></em> Tax code. Max 100 characters.</td>\n</tr>\n<tr>\n<td><code>requires_shipping</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the product requires physical shipping.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the product is active.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code>, a <code>message</code>, and the created product under <code>data</code> using the detailed shape (includes dimensions, units, tax fields, <code>product_image</code>, and the loaded <code>category</code>). See the example response.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the necessary permissions (<code>api:products.create</code>).</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error. Returned for a missing <code>name</code>/<code>price</code>, an invalid <code>product_type</code>/<code>fulfillment_type</code> enum, a <code>category_id</code>/<code>fulfillment_provider_id</code> that does not exist for the team, or any field exceeding its max/min.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong> <code>POST /v1/products</code> with the JSON body shown in the request body tab.</p>\n<p><strong>Response</strong> <code>201 Created</code> — see the example response.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","products"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"044b1090-64bd-46ad-fd5a-28ba56bcf727","name":"Create Product","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Classic Cotton T-Shirt\",\n  \"price\": 29.99,\n  \"product_type\": \"physical\",\n  \"fulfillment_type\": \"physical\",\n  \"category_id\": 7,\n  \"fulfillment_provider_id\": 3,\n  \"description\": \"A soft, durable 100% cotton t-shirt available in multiple colors.\",\n  \"short_description\": \"100% cotton crew-neck tee.\",\n  \"sku\": \"TSHIRT-CLS-001\",\n  \"barcode\": \"0123456789012\",\n  \"cost\": 8.50,\n  \"estimated_shipping_cost\": 4.95,\n  \"track_inventory\": true,\n  \"stock\": 250,\n  \"quantity\": 1,\n  \"low_stock_threshold\": 25,\n  \"weight\": 0.30,\n  \"length\": 25.00,\n  \"width\": 20.00,\n  \"height\": 2.00,\n  \"weight_unit\": \"kg\",\n  \"dimension_unit\": \"cm\",\n  \"is_taxable\": true,\n  \"tax_class\": \"standard\",\n  \"tax_code\": \"PC040000\",\n  \"requires_shipping\": true,\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/products","description":"# Create Product\n\n**Create a new product for the authenticated account.**\n\nCreates a product owned by the authenticated team. `internal_id` and `slug` are generated automatically (the slug derives from `name` when omitted). On success the full (detailed) product object is returned with HTTP `201`.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:products.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| `name` | _**string (required)**_ Product name. Max 255 characters. |\n| `price` | _**numeric (required)**_ Selling price. Min `0`. Stored with 2-decimal precision. |\n| `product_type` | _**string (optional)**_ Product type. One of `physical`, `digital`, `subscription`. |\n| `fulfillment_type` | _**string (optional)**_ How the product is fulfilled. One of `physical` (physical shipping), `digital` (digital download), `email` (email delivery), `manual` (manual fulfillment). |\n| `category_id` | _**integer (optional)**_ ID of a `product_categories` row. Must exist and belong to the authenticated team. |\n| `fulfillment_provider_id` | _**integer (optional)**_ ID of a `fulfillment_providers` row. Must exist and belong to the authenticated team. |\n| `description` | _**string (optional)**_ Full product description. No max length. |\n| `short_description` | _**string (optional)**_ Short description. Max 500 characters. |\n| `sku` | _**string (optional)**_ Stock keeping unit. Max 255 characters. |\n| `barcode` | _**string (optional)**_ Barcode value. Max 255 characters. |\n| `cost` | _**numeric (optional)**_ Unit cost. Min `0`. |\n| `estimated_shipping_cost` | _**numeric (optional)**_ Estimated shipping cost. Min `0`. |\n| `track_inventory` | _**boolean (optional)**_ Whether to track inventory for this product. |\n| `stock` | _**integer (optional)**_ Current stock level. Min `0`. |\n| `quantity` | _**integer (optional)**_ Quantity. Min `0`. |\n| `low_stock_threshold` | _**integer (optional)**_ Stock level considered low. Min `0`. |\n| `weight` | _**numeric (optional)**_ Product weight. Min `0`. |\n| `length` | _**numeric (optional)**_ Length dimension. Min `0`. |\n| `width` | _**numeric (optional)**_ Width dimension. Min `0`. |\n| `height` | _**numeric (optional)**_ Height dimension. Min `0`. |\n| `weight_unit` | _**string (optional)**_ Unit for `weight` (e.g. `kg`, `lb`). Max 20 characters. |\n| `dimension_unit` | _**string (optional)**_ Unit for dimensions (e.g. `cm`, `in`). Max 20 characters. |\n| `is_taxable` | _**boolean (optional)**_ Whether tax applies to the product. |\n| `tax_class` | _**string (optional)**_ Tax class identifier. Max 100 characters. |\n| `tax_code` | _**string (optional)**_ Tax code. Max 100 characters. |\n| `requires_shipping` | _**boolean (optional)**_ Whether the product requires physical shipping. |\n| `is_active` | _**boolean (optional)**_ Whether the product is active. |\n\n## Response\n\nReturns `success: true`, a `message`, and the created product under `data` using the detailed shape (includes dimensions, units, tax fields, `product_image`, and the loaded `category`). See the example response.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the necessary permissions (`api:products.create`). |\n| `422` | Validation error. Returned for a missing `name`/`price`, an invalid `product_type`/`fulfillment_type` enum, a `category_id`/`fulfillment_provider_id` that does not exist for the team, or any field exceeding its max/min. |\n\n## Example\n\n**Request** `POST /v1/products` with the JSON body shown in the request body tab.\n\n**Response** `201 Created` — see the example response."},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Product created successfully\",\n  \"data\": {\n    \"id\": 1043,\n    \"name\": \"Classic Cotton T-Shirt\",\n    \"slug\": \"classic-cotton-t-shirt\",\n    \"sku\": \"TSHIRT-CLS-001\",\n    \"barcode\": \"0123456789012\",\n    \"product_type\": \"physical\",\n    \"fulfillment_type\": \"physical\",\n    \"price\": \"29.99\",\n    \"cost\": \"8.50\",\n    \"estimated_shipping_cost\": \"4.95\",\n    \"description\": \"A soft, durable 100% cotton t-shirt available in multiple colors.\",\n    \"short_description\": \"100% cotton crew-neck tee.\",\n    \"requires_shipping\": true,\n    \"is_active\": true,\n    \"is_taxable\": true,\n    \"track_inventory\": true,\n    \"stock\": 250,\n    \"quantity\": 1,\n    \"low_stock_threshold\": 25,\n    \"created_at\": \"2026-06-16T13:45:09.000000Z\",\n    \"updated_at\": \"2026-06-16T13:45:09.000000Z\",\n    \"weight\": \"0.30\",\n    \"length\": \"25.00\",\n    \"width\": \"20.00\",\n    \"height\": \"2.00\",\n    \"weight_unit\": \"kg\",\n    \"dimension_unit\": \"cm\",\n    \"tax_class\": \"standard\",\n    \"tax_code\": \"PC040000\",\n    \"product_image\": null,\n    \"category\": {\n      \"id\": 7,\n      \"name\": \"Apparel\"\n    }\n  }\n}"}],"_postman_id":"4747a804-e1a8-47bf-9e35-18e6ad312824"},{"name":"Get Product","id":"1dfe437e-dca0-815e-fb7c-6ef661586221","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/products/1042","description":"<h1 id=\"get-product\">Get Product</h1>\n<p><strong>Retrieve a single product by its internal id.</strong></p>\n<p>Returns the full (detailed) product object for the given <code>internal_id</code>, scoped to the authenticated team. The <code>category</code> relationship is eager-loaded.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:products.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>product_id</code></td>\n<td><em><strong>integer (required, path)</strong></em> The product's account-scoped <code>internal_id</code> (the <code>id</code> returned by List/Create), not the database primary key.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and the product under <code>data</code> using the detailed shape.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td><em>integer</em> The product's <code>internal_id</code>.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td><em>string</em> Product name.</td>\n</tr>\n<tr>\n<td><code>slug</code></td>\n<td><em>string</em> URL slug.</td>\n</tr>\n<tr>\n<td><code>sku</code></td>\n<td><em>string | null</em> Stock keeping unit.</td>\n</tr>\n<tr>\n<td><code>barcode</code></td>\n<td><em>string | null</em> Barcode value.</td>\n</tr>\n<tr>\n<td><code>product_type</code></td>\n<td><em>string | null</em> One of <code>physical</code>, <code>digital</code>, <code>subscription</code>.</td>\n</tr>\n<tr>\n<td><code>fulfillment_type</code></td>\n<td><em>string | null</em> One of <code>physical</code>, <code>digital</code>, <code>email</code>, <code>manual</code>.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td><em>string</em> Selling price, 2 decimals.</td>\n</tr>\n<tr>\n<td><code>cost</code></td>\n<td><em>string | null</em> Unit cost, 2 decimals.</td>\n</tr>\n<tr>\n<td><code>estimated_shipping_cost</code></td>\n<td><em>string | null</em> Estimated shipping cost, 2 decimals.</td>\n</tr>\n<tr>\n<td><code>description</code></td>\n<td><em>string | null</em> Full description.</td>\n</tr>\n<tr>\n<td><code>short_description</code></td>\n<td><em>string | null</em> Short description.</td>\n</tr>\n<tr>\n<td><code>requires_shipping</code></td>\n<td><em>boolean</em> Whether physical shipping is required.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em>boolean</em> Whether the product is active.</td>\n</tr>\n<tr>\n<td><code>is_taxable</code></td>\n<td><em>boolean</em> Whether tax applies.</td>\n</tr>\n<tr>\n<td><code>track_inventory</code></td>\n<td><em>boolean</em> Whether inventory is tracked.</td>\n</tr>\n<tr>\n<td><code>stock</code></td>\n<td><em>integer | null</em> Current stock level.</td>\n</tr>\n<tr>\n<td><code>quantity</code></td>\n<td><em>integer | null</em> Quantity value.</td>\n</tr>\n<tr>\n<td><code>low_stock_threshold</code></td>\n<td><em>integer | null</em> Low-stock threshold.</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td><em>string (ISO 8601)</em> Creation timestamp.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td><em>string (ISO 8601)</em> Last update timestamp.</td>\n</tr>\n<tr>\n<td><code>weight</code></td>\n<td><em>string | null</em> Weight, 2 decimals. (detailed)</td>\n</tr>\n<tr>\n<td><code>length</code></td>\n<td><em>string | null</em> Length, 2 decimals. (detailed)</td>\n</tr>\n<tr>\n<td><code>width</code></td>\n<td><em>string | null</em> Width, 2 decimals. (detailed)</td>\n</tr>\n<tr>\n<td><code>height</code></td>\n<td><em>string | null</em> Height, 2 decimals. (detailed)</td>\n</tr>\n<tr>\n<td><code>weight_unit</code></td>\n<td><em>string | null</em> Unit for weight. (detailed)</td>\n</tr>\n<tr>\n<td><code>dimension_unit</code></td>\n<td><em>string | null</em> Unit for dimensions. (detailed)</td>\n</tr>\n<tr>\n<td><code>tax_class</code></td>\n<td><em>string | null</em> Tax class. (detailed)</td>\n</tr>\n<tr>\n<td><code>tax_code</code></td>\n<td><em>string | null</em> Tax code. (detailed)</td>\n</tr>\n<tr>\n<td><code>product_image</code></td>\n<td><em>object | null</em> Stored image metadata (<code>url</code>, <code>original_name</code>, <code>path</code>, <code>uploaded_at</code>, <code>uploaded_by</code>). (detailed)</td>\n</tr>\n<tr>\n<td><code>category</code></td>\n<td><em>object | null</em> The product category <code>{ id, name }</code> when a <code>category_id</code> is set; otherwise <code>null</code>. (detailed)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the necessary permissions (<code>api:products.view</code>).</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>No product with the given <code>internal_id</code> exists for the authenticated team.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong> <code>GET /v1/products/1042</code></p>\n<p><strong>Response</strong> <code>200 OK</code> — see the example response.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","products","1042"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"7eae831a-9365-1db6-9839-303f08411a00","name":"Get Product","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/products/1042","description":"# Get Product\n\n**Retrieve a single product by its internal id.**\n\nReturns the full (detailed) product object for the given `internal_id`, scoped to the authenticated team. The `category` relationship is eager-loaded.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:products.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `product_id` | _**integer (required, path)**_ The product's account-scoped `internal_id` (the `id` returned by List/Create), not the database primary key. |\n\n## Response Object\n\nReturns `success: true` and the product under `data` using the detailed shape.\n\n| Field | Description |\n| --- | --- |\n| `id` | _integer_ The product's `internal_id`. |\n| `name` | _string_ Product name. |\n| `slug` | _string_ URL slug. |\n| `sku` | _string \\| null_ Stock keeping unit. |\n| `barcode` | _string \\| null_ Barcode value. |\n| `product_type` | _string \\| null_ One of `physical`, `digital`, `subscription`. |\n| `fulfillment_type` | _string \\| null_ One of `physical`, `digital`, `email`, `manual`. |\n| `price` | _string_ Selling price, 2 decimals. |\n| `cost` | _string \\| null_ Unit cost, 2 decimals. |\n| `estimated_shipping_cost` | _string \\| null_ Estimated shipping cost, 2 decimals. |\n| `description` | _string \\| null_ Full description. |\n| `short_description` | _string \\| null_ Short description. |\n| `requires_shipping` | _boolean_ Whether physical shipping is required. |\n| `is_active` | _boolean_ Whether the product is active. |\n| `is_taxable` | _boolean_ Whether tax applies. |\n| `track_inventory` | _boolean_ Whether inventory is tracked. |\n| `stock` | _integer \\| null_ Current stock level. |\n| `quantity` | _integer \\| null_ Quantity value. |\n| `low_stock_threshold` | _integer \\| null_ Low-stock threshold. |\n| `created_at` | _string (ISO 8601)_ Creation timestamp. |\n| `updated_at` | _string (ISO 8601)_ Last update timestamp. |\n| `weight` | _string \\| null_ Weight, 2 decimals. (detailed) |\n| `length` | _string \\| null_ Length, 2 decimals. (detailed) |\n| `width` | _string \\| null_ Width, 2 decimals. (detailed) |\n| `height` | _string \\| null_ Height, 2 decimals. (detailed) |\n| `weight_unit` | _string \\| null_ Unit for weight. (detailed) |\n| `dimension_unit` | _string \\| null_ Unit for dimensions. (detailed) |\n| `tax_class` | _string \\| null_ Tax class. (detailed) |\n| `tax_code` | _string \\| null_ Tax code. (detailed) |\n| `product_image` | _object \\| null_ Stored image metadata (`url`, `original_name`, `path`, `uploaded_at`, `uploaded_by`). (detailed) |\n| `category` | _object \\| null_ The product category `{ id, name }` when a `category_id` is set; otherwise `null`. (detailed) |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the necessary permissions (`api:products.view`). |\n| `404` | No product with the given `internal_id` exists for the authenticated team. |\n\n## Example\n\n**Request** `GET /v1/products/1042`\n\n**Response** `200 OK` — see the example response."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"id\": 1042,\n    \"name\": \"Classic Cotton T-Shirt\",\n    \"slug\": \"classic-cotton-t-shirt\",\n    \"sku\": \"TSHIRT-CLS-001\",\n    \"barcode\": \"0123456789012\",\n    \"product_type\": \"physical\",\n    \"fulfillment_type\": \"physical\",\n    \"price\": \"29.99\",\n    \"cost\": \"8.50\",\n    \"estimated_shipping_cost\": \"4.95\",\n    \"description\": \"A soft, durable 100% cotton t-shirt available in multiple colors.\",\n    \"short_description\": \"100% cotton crew-neck tee.\",\n    \"requires_shipping\": true,\n    \"is_active\": true,\n    \"is_taxable\": true,\n    \"track_inventory\": true,\n    \"stock\": 250,\n    \"quantity\": 1,\n    \"low_stock_threshold\": 25,\n    \"created_at\": \"2026-06-10T14:22:05.000000Z\",\n    \"updated_at\": \"2026-06-15T09:01:44.000000Z\",\n    \"weight\": \"0.30\",\n    \"length\": \"25.00\",\n    \"width\": \"20.00\",\n    \"height\": \"2.00\",\n    \"weight_unit\": \"kg\",\n    \"dimension_unit\": \"cm\",\n    \"tax_class\": \"standard\",\n    \"tax_code\": \"PC040000\",\n    \"product_image\": {\n      \"url\": \"https://cdn.sparkcrm.io/products/tshirt-cls-001.jpg\",\n      \"original_name\": \"tshirt.jpg\",\n      \"path\": \"products/tshirt-cls-001.jpg\",\n      \"uploaded_at\": \"2026-06-10T14:25:00+00:00\",\n      \"uploaded_by\": \"Acme Store\"\n    },\n    \"category\": {\n      \"id\": 7,\n      \"name\": \"Apparel\"\n    }\n  }\n}"}],"_postman_id":"1dfe437e-dca0-815e-fb7c-6ef661586221"},{"name":"Update Product","id":"0255d375-9dba-49c8-da6a-edaee795762f","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Classic Cotton T-Shirt (Updated)\",\n  \"price\": 34.99,\n  \"product_type\": \"physical\",\n  \"fulfillment_type\": \"physical\",\n  \"category_id\": 7,\n  \"fulfillment_provider_id\": 3,\n  \"short_description\": \"Now in heavier 200gsm cotton.\",\n  \"stock\": 180,\n  \"low_stock_threshold\": 20,\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/products/1042","description":"<h1 id=\"update-product\">Update Product</h1>\n<p><strong>Partially update a product.</strong></p>\n<p>Updates an existing product identified by its <code>internal_id</code>, scoped to the authenticated team. This is a partial update: every field is optional and only the fields you send are validated and saved. On success the full (detailed) product object is returned.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:products.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional. When a field is present it must pass the rule shown below (the <code>name</code> and <code>price</code> fields are required-if-present, i.e. they may not be sent as empty/null).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (optional)</strong></em> Product name. If sent, must be non-empty. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>price</code></td>\n<td><em><strong>numeric (optional)</strong></em> Selling price. If sent, must be non-empty. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>product_type</code></td>\n<td><em><strong>string (optional)</strong></em> One of <code>physical</code>, <code>digital</code>, <code>subscription</code>.</td>\n</tr>\n<tr>\n<td><code>fulfillment_type</code></td>\n<td><em><strong>string (optional)</strong></em> One of <code>physical</code>, <code>digital</code>, <code>email</code>, <code>manual</code>.</td>\n</tr>\n<tr>\n<td><code>category_id</code></td>\n<td><em><strong>integer (optional)</strong></em> ID of a <code>product_categories</code> row that belongs to the team.</td>\n</tr>\n<tr>\n<td><code>fulfillment_provider_id</code></td>\n<td><em><strong>integer (optional)</strong></em> ID of a <code>fulfillment_providers</code> row that belongs to the team.</td>\n</tr>\n<tr>\n<td><code>description</code></td>\n<td><em><strong>string (optional)</strong></em> Full description.</td>\n</tr>\n<tr>\n<td><code>short_description</code></td>\n<td><em><strong>string (optional)</strong></em> Short description. Max 500 characters.</td>\n</tr>\n<tr>\n<td><code>sku</code></td>\n<td><em><strong>string (optional)</strong></em> SKU. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>barcode</code></td>\n<td><em><strong>string (optional)</strong></em> Barcode. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>cost</code></td>\n<td><em><strong>numeric (optional)</strong></em> Unit cost. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>estimated_shipping_cost</code></td>\n<td><em><strong>numeric (optional)</strong></em> Estimated shipping cost. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>track_inventory</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether to track inventory.</td>\n</tr>\n<tr>\n<td><code>stock</code></td>\n<td><em><strong>integer (optional)</strong></em> Current stock level. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>quantity</code></td>\n<td><em><strong>integer (optional)</strong></em> Quantity. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>low_stock_threshold</code></td>\n<td><em><strong>integer (optional)</strong></em> Low-stock threshold. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>weight</code></td>\n<td><em><strong>numeric (optional)</strong></em> Weight. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>length</code></td>\n<td><em><strong>numeric (optional)</strong></em> Length. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>width</code></td>\n<td><em><strong>numeric (optional)</strong></em> Width. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>height</code></td>\n<td><em><strong>numeric (optional)</strong></em> Height. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>weight_unit</code></td>\n<td><em><strong>string (optional)</strong></em> Unit for weight. Max 20 characters.</td>\n</tr>\n<tr>\n<td><code>dimension_unit</code></td>\n<td><em><strong>string (optional)</strong></em> Unit for dimensions. Max 20 characters.</td>\n</tr>\n<tr>\n<td><code>is_taxable</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether tax applies.</td>\n</tr>\n<tr>\n<td><code>tax_class</code></td>\n<td><em><strong>string (optional)</strong></em> Tax class. Max 100 characters.</td>\n</tr>\n<tr>\n<td><code>tax_code</code></td>\n<td><em><strong>string (optional)</strong></em> Tax code. Max 100 characters.</td>\n</tr>\n<tr>\n<td><code>requires_shipping</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether physical shipping is required.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the product is active.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code>, a <code>message</code>, and the updated product under <code>data</code> using the detailed shape (with the loaded <code>category</code>). See the example response.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the necessary permissions (<code>api:products.update</code>).</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>No product with the given <code>internal_id</code> exists for the authenticated team.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error (invalid enum value, a <code>category_id</code>/<code>fulfillment_provider_id</code> not owned by the team, an empty <code>name</code>/<code>price</code>, or a field exceeding its constraints).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong> <code>PATCH /v1/products/1042</code> with a partial JSON body.</p>\n<p><strong>Response</strong> <code>200 OK</code> — see the example response.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","products","1042"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"371e9d1e-2f81-d7b7-2a25-753f0fa1b2bb","name":"Update Product","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Classic Cotton T-Shirt (Updated)\",\n  \"price\": 34.99,\n  \"product_type\": \"physical\",\n  \"fulfillment_type\": \"physical\",\n  \"category_id\": 7,\n  \"fulfillment_provider_id\": 3,\n  \"short_description\": \"Now in heavier 200gsm cotton.\",\n  \"stock\": 180,\n  \"low_stock_threshold\": 20,\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/products/1042","description":"# Update Product\n\n**Partially update a product.**\n\nUpdates an existing product identified by its `internal_id`, scoped to the authenticated team. This is a partial update: every field is optional and only the fields you send are validated and saved. On success the full (detailed) product object is returned.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:products.update`\n\n## Request Body\n\nAll fields are optional. When a field is present it must pass the rule shown below (the `name` and `price` fields are required-if-present, i.e. they may not be sent as empty/null).\n\n| Request Field | Description |\n| --- | --- |\n| `name` | _**string (optional)**_ Product name. If sent, must be non-empty. Max 255 characters. |\n| `price` | _**numeric (optional)**_ Selling price. If sent, must be non-empty. Min `0`. |\n| `product_type` | _**string (optional)**_ One of `physical`, `digital`, `subscription`. |\n| `fulfillment_type` | _**string (optional)**_ One of `physical`, `digital`, `email`, `manual`. |\n| `category_id` | _**integer (optional)**_ ID of a `product_categories` row that belongs to the team. |\n| `fulfillment_provider_id` | _**integer (optional)**_ ID of a `fulfillment_providers` row that belongs to the team. |\n| `description` | _**string (optional)**_ Full description. |\n| `short_description` | _**string (optional)**_ Short description. Max 500 characters. |\n| `sku` | _**string (optional)**_ SKU. Max 255 characters. |\n| `barcode` | _**string (optional)**_ Barcode. Max 255 characters. |\n| `cost` | _**numeric (optional)**_ Unit cost. Min `0`. |\n| `estimated_shipping_cost` | _**numeric (optional)**_ Estimated shipping cost. Min `0`. |\n| `track_inventory` | _**boolean (optional)**_ Whether to track inventory. |\n| `stock` | _**integer (optional)**_ Current stock level. Min `0`. |\n| `quantity` | _**integer (optional)**_ Quantity. Min `0`. |\n| `low_stock_threshold` | _**integer (optional)**_ Low-stock threshold. Min `0`. |\n| `weight` | _**numeric (optional)**_ Weight. Min `0`. |\n| `length` | _**numeric (optional)**_ Length. Min `0`. |\n| `width` | _**numeric (optional)**_ Width. Min `0`. |\n| `height` | _**numeric (optional)**_ Height. Min `0`. |\n| `weight_unit` | _**string (optional)**_ Unit for weight. Max 20 characters. |\n| `dimension_unit` | _**string (optional)**_ Unit for dimensions. Max 20 characters. |\n| `is_taxable` | _**boolean (optional)**_ Whether tax applies. |\n| `tax_class` | _**string (optional)**_ Tax class. Max 100 characters. |\n| `tax_code` | _**string (optional)**_ Tax code. Max 100 characters. |\n| `requires_shipping` | _**boolean (optional)**_ Whether physical shipping is required. |\n| `is_active` | _**boolean (optional)**_ Whether the product is active. |\n\n## Response\n\nReturns `success: true`, a `message`, and the updated product under `data` using the detailed shape (with the loaded `category`). See the example response.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the necessary permissions (`api:products.update`). |\n| `404` | No product with the given `internal_id` exists for the authenticated team. |\n| `422` | Validation error (invalid enum value, a `category_id`/`fulfillment_provider_id` not owned by the team, an empty `name`/`price`, or a field exceeding its constraints). |\n\n## Example\n\n**Request** `PATCH /v1/products/1042` with a partial JSON body.\n\n**Response** `200 OK` — see the example response."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Product updated successfully\",\n  \"data\": {\n    \"id\": 1042,\n    \"name\": \"Classic Cotton T-Shirt (Updated)\",\n    \"slug\": \"classic-cotton-t-shirt\",\n    \"sku\": \"TSHIRT-CLS-001\",\n    \"barcode\": \"0123456789012\",\n    \"product_type\": \"physical\",\n    \"fulfillment_type\": \"physical\",\n    \"price\": \"34.99\",\n    \"cost\": \"8.50\",\n    \"estimated_shipping_cost\": \"4.95\",\n    \"description\": \"A soft, durable 100% cotton t-shirt available in multiple colors.\",\n    \"short_description\": \"Now in heavier 200gsm cotton.\",\n    \"requires_shipping\": true,\n    \"is_active\": true,\n    \"is_taxable\": true,\n    \"track_inventory\": true,\n    \"stock\": 180,\n    \"quantity\": 1,\n    \"low_stock_threshold\": 20,\n    \"created_at\": \"2026-06-10T14:22:05.000000Z\",\n    \"updated_at\": \"2026-06-16T13:52:18.000000Z\",\n    \"weight\": \"0.30\",\n    \"length\": \"25.00\",\n    \"width\": \"20.00\",\n    \"height\": \"2.00\",\n    \"weight_unit\": \"kg\",\n    \"dimension_unit\": \"cm\",\n    \"tax_class\": \"standard\",\n    \"tax_code\": \"PC040000\",\n    \"product_image\": null,\n    \"category\": {\n      \"id\": 7,\n      \"name\": \"Apparel\"\n    }\n  }\n}"}],"_postman_id":"0255d375-9dba-49c8-da6a-edaee795762f"}],"id":"cf40e40d-638b-4e81-ad46-d4892e92db7a","_postman_id":"cf40e40d-638b-4e81-ad46-d4892e92db7a","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Transactions","item":[{"name":"Notes","item":[{"name":"Get Transaction Notes","id":"4f411147-a680-4c70-8d0d-04212ce5d32b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/transactions/{transactionNumber}/notes","description":"<h1 id=\"get-transaction-notes\">Get Transaction Notes</h1>\n<p>Retrieve notes for a specific transaction that match the specified search criteria.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Filter notes by type. Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>search</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Search notes by title or content. Performs partial matching using SQL LIKE operations. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><strong><em>integer (optional)</em></strong>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of transaction note objects matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>transaction</strong></td>\n<td><strong>object</strong>  <br />Transaction information</td>\n</tr>\n<tr>\n<td><strong>transaction.transaction_number</strong></td>\n<td><strong>string</strong>  <br />Transaction's unique identifier</td>\n</tr>\n<tr>\n<td><strong>transaction.status</strong></td>\n<td><strong>string</strong>  <br />Current transaction status</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of notes matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of notes displayed per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","transactions","{transactionNumber}","notes"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"5337d93d-7669-41ea-81e3-91ede253ee27","name":"Get Transaction Notes","originalRequest":{"method":"GET","header":[],"url":"https://sparkcrm.test/v1/transactions/TXN-250815-000538/notes"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:16:41 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"48000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": 1,\n            \"title\": \"transaction note\",\n            \"content\": \"this is a new transaction note for shipping\",\n            \"type\": \"shipping\",\n            \"created_by\": \"2\",\n            \"created_at\": \"2025-09-17T03:16:30.000000Z\",\n            \"updated_at\": \"2025-09-17T03:16:30.000000Z\"\n        }\n    ],\n    \"transaction\": {\n        \"transaction_number\": \"TXN-250815-000538\",\n        \"status\": \"completed\"\n    },\n    \"pagination\": {\n        \"total\": 1,\n        \"per_page\": 15,\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 1\n    }\n}"}],"_postman_id":"4f411147-a680-4c70-8d0d-04212ce5d32b"},{"name":"Create Transaction Note","id":"8c5b517f-9598-48a6-b387-8f1649014a97","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"url":"https://api.sparkcrm.io/v1/transactions/{transactionNumber}/notes","description":"<h1 id=\"create-transaction-note\">Create Transaction Note</h1>\n<p>Create a new note for a specific transaction.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>title</strong></td>\n<td><strong><em>string (required)</em></strong>  <br />Note title. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>content</strong></td>\n<td><strong><em>string (required)</em></strong>  <br />Note content. Maximum 5000 characters.</td>\n</tr>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note type/category. Maximum 50 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The created note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","transactions","{transactionNumber}","notes"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"3a260595-d050-47b2-bc6b-9951a476f698","name":"Create Transaction Note","originalRequest":{"method":"POST","header":[],"url":{"raw":"https://sparkcrm.test/v1/transactions/TXN-250815-000538/notes?title=transaction note&content=this is a new transaction note for shipping&type=shipping","protocol":"https","host":["sparkcrm","test"],"path":["v1","transactions","TXN-250815-000538","notes"],"query":[{"key":"title","value":"transaction note","type":"text"},{"key":"content","value":"this is a new transaction note for shipping","type":"text"},{"key":"type","value":"shipping","type":"text"}]}},"status":"Created","code":201,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:16:30 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note added successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"title\": \"transaction note\",\n        \"content\": \"this is a new transaction note for shipping\",\n        \"type\": \"shipping\",\n        \"created_by\": 2,\n        \"created_at\": \"2025-09-17T03:16:30.000000Z\",\n        \"updated_at\": \"2025-09-17T03:16:30.000000Z\"\n    }\n}"}],"_postman_id":"8c5b517f-9598-48a6-b387-8f1649014a97"},{"name":"Update Transaction Note","id":"123af95f-da57-4b1a-b996-fb0fa7bf4c65","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PUT","header":[],"url":"https://api.sparkcrm.io/v1/transactions/{transactionNumber}/notes/{noteId}","description":"<h1 id=\"update-transaction-note\">Update Transaction Note</h1>\n<p>Update an existing note for a specific transaction.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>title</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note title. Maximum 255 characters. Only required if updating the title.</td>\n</tr>\n<tr>\n<td><strong>content</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note content. Maximum 5000 characters. Only required if updating the content.</td>\n</tr>\n<tr>\n<td><strong>type</strong></td>\n<td><strong><em>string (optional)</em></strong>  <br />Note type/category. Maximum 50 characters. Can be set to null.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Note:</strong> At least one field must be provided to update the note. All fields use \"sometimes\" validation, meaning they're only validated if present in the request.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The updated note object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Unique identifier for the note</td>\n</tr>\n<tr>\n<td><strong>data.title</strong></td>\n<td><strong>string</strong>  <br />Note title</td>\n</tr>\n<tr>\n<td><strong>data.content</strong></td>\n<td><strong>string</strong>  <br />Note content</td>\n</tr>\n<tr>\n<td><strong>data.type</strong></td>\n<td><strong>string</strong>  <br />Note type/category</td>\n</tr>\n<tr>\n<td><strong>data.created_by</strong></td>\n<td><strong>integer</strong>  <br />ID of the user who created the note</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />Date and time when the note was last updated (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","transactions","{transactionNumber}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"403289f9-46c3-41cc-9f4a-0fe929df1a25","name":"Update Transaction Note","originalRequest":{"method":"PUT","header":[],"url":{"raw":"https://sparkcrm.test/v1/transactions/TXN-250815-000538/notes/1?content=updated transaction note","protocol":"https","host":["sparkcrm","test"],"path":["v1","transactions","TXN-250815-000538","notes","1"],"query":[{"key":"content","value":"updated transaction note","type":"text"}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:17:37 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"99"},{"key":"X-RateLimit-Reset","value":"59000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note updated successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"title\": \"transaction note\",\n        \"content\": \"updated transaction note\",\n        \"type\": \"shipping\",\n        \"created_by\": \"2\",\n        \"created_at\": \"2025-09-17T03:16:30.000000Z\",\n        \"updated_at\": \"2025-09-17T03:17:37.000000Z\"\n    }\n}"}],"_postman_id":"123af95f-da57-4b1a-b996-fb0fa7bf4c65"},{"name":"Delete Transaction Note","id":"76316082-a38a-4957-9407-5f5e18ba93c2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/transactions/{transactionNumber}/notes/{noteId}","description":"<h1 id=\"delete-transaction-note\">Delete Transaction Note</h1>\n<p>Delete a specific note for a transaction by note ID.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<h2 id=\"request-object\">Request Object</h2>\n<p>No request body parameters. The transaction number and note ID are provided in the URL path.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Success message confirming the note deletion</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","transactions","{transactionNumber}","notes","{noteId}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"c3d00235-9204-48f7-b112-3a01924b054f","name":"Delete Transaction Note","originalRequest":{"method":"DELETE","header":[],"url":"https://sparkcrm.test/v1/transactions/TXN-250815-000538/notes/1"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"Server","value":"nginx/1.25.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Vary","value":"Accept-Encoding"},{"key":"X-Powered-By","value":"PHP/8.4.12"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Wed, 17 Sep 2025 03:17:49 GMT"},{"key":"X-RateLimit-Limit","value":"100"},{"key":"X-RateLimit-Remaining","value":"98"},{"key":"X-RateLimit-Reset","value":"47000"},{"key":"Content-Encoding","value":"gzip"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Note deleted successfully\"\n}"}],"_postman_id":"76316082-a38a-4957-9407-5f5e18ba93c2"}],"id":"9ef43870-33c3-4033-a9f6-1a4bc5018231","_postman_id":"9ef43870-33c3-4033-a9f6-1a4bc5018231","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}}],"id":"b2f6558c-80d9-4672-b185-aa4304ac0e55","_postman_id":"b2f6558c-80d9-4672-b185-aa4304ac0e55","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Gateways","item":[{"name":"Get Gateways (list/search)","id":"c3b950a6-0bcb-55d2-53ba-3b99b7043b93","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/gateways","description":"<h1 id=\"get-gateways-listsearch\">Get Gateways (list/search)</h1>\n<p><strong>List &amp; Search for Gateways</strong></p>\n<p>Retrieve a paginated list of gateways available to the authenticated account. Supports free-text search and filtering by status.</p>\n<h2 id=\"example--search-for-active-gateways\">Example — Search for Active Gateways</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/gateways?status=active\n</code></pre><p>Returns a paginated list of all gateways currently in <code>active</code> status for the authenticated team. Combine with <code>per_page</code>, <code>page</code>, or <code>search</code> to narrow results.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:gateways.view_any</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>search</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Search across gateway name and internal id. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>status</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Filter by gateway status. Options: <code>active</code>, <code>inactive</code>, <code>pending</code>, <code>error</code>, <code>suspended</code>.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td><strong>page</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of gateway objects matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Gateway identifier (team's internal id)</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Gateway display name</td>\n</tr>\n<tr>\n<td><strong>data.gateway_type</strong></td>\n<td><strong>string</strong>  <br />Gateway integration type (e.g. <code>nmi</code>, <code>stripe</code>, <code>authorize_net</code>)</td>\n</tr>\n<tr>\n<td><strong>data.status</strong></td>\n<td><strong>string</strong>  <br />Current gateway status</td>\n</tr>\n<tr>\n<td><strong>data.monthly_processing_limit</strong></td>\n<td><strong>number</strong>  <br />Monthly processing limit in dollars</td>\n</tr>\n<tr>\n<td><strong>data.monthly_fee</strong></td>\n<td><strong>number</strong>  <br />Flat monthly fee</td>\n</tr>\n<tr>\n<td><strong>data.discount_rate</strong></td>\n<td><strong>number</strong>  <br />Discount rate percent (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.transaction_fee</strong></td>\n<td><strong>number</strong>  <br />Per-transaction fee</td>\n</tr>\n<tr>\n<td><strong>data.reserve_rate</strong></td>\n<td><strong>number</strong>  <br />Reserve rate percent (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.reserve_term_days</strong></td>\n<td><strong>integer</strong>  <br />Reserve holding period in days</td>\n</tr>\n<tr>\n<td><strong>data.accepted_card_brands</strong></td>\n<td><strong>array</strong>  <br />List of accepted card brands</td>\n</tr>\n<tr>\n<td><strong>data.accepts_prepaid_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether prepaid cards are accepted</td>\n</tr>\n<tr>\n<td><strong>data.accepts_virtual_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether virtual cards are accepted</td>\n</tr>\n<tr>\n<td><strong>data.accepts_international_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether international cards are accepted</td>\n</tr>\n<tr>\n<td><strong>data.use_dynamic_descriptors</strong></td>\n<td><strong>boolean</strong>  <br />Whether to use dynamic statement descriptors</td>\n</tr>\n<tr>\n<td><strong>data.accepted_currencies</strong></td>\n<td><strong>array</strong>  <br />List of accepted currency codes</td>\n</tr>\n<tr>\n<td><strong>data.accepted_countries</strong></td>\n<td><strong>array</strong>  <br />List of accepted ISO country codes</td>\n</tr>\n<tr>\n<td><strong>data.statement_descriptor</strong></td>\n<td><strong>string</strong>  <br />Default statement descriptor</td>\n</tr>\n<tr>\n<td><strong>data.statement_descriptor_phone</strong></td>\n<td><strong>string</strong>  <br />Statement descriptor phone number</td>\n</tr>\n<tr>\n<td><strong>data.support_phone</strong></td>\n<td><strong>string</strong>  <br />Customer support phone</td>\n</tr>\n<tr>\n<td><strong>data.support_email</strong></td>\n<td><strong>string</strong>  <br />Customer support email</td>\n</tr>\n<tr>\n<td><strong>data.support_url</strong></td>\n<td><strong>string</strong>  <br />Customer support URL</td>\n</tr>\n<tr>\n<td><strong>data.usage_percentage</strong></td>\n<td><strong>number</strong>  <br />Percent of monthly limit used</td>\n</tr>\n<tr>\n<td><strong>data.usage_status</strong></td>\n<td><strong>string</strong>  <br />Usage status indicator</td>\n</tr>\n<tr>\n<td><strong>data.last_successful_transaction_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp of the last successful transaction</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the gateway was created</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the gateway was last updated</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of gateways matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of gateways displayed per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","gateways"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"description":{"content":"<p>Page number for paginated results</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[],"_postman_id":"c3b950a6-0bcb-55d2-53ba-3b99b7043b93"},{"name":"Get Gateway","id":"d306a8fa-8afb-28b3-53e1-dc9d36563ee9","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/gateways/{{gatewayId}}","description":"<h1 id=\"get-gateway\">Get Gateway</h1>\n<p><strong>Retrieve a Single Gateway</strong></p>\n<p>Retrieve a single gateway by its identifier (the team's internal gateway id). Database ids are never exposed.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/gateways/1\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:gateways.view</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>gatewayId</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal gateway id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />Gateway object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Gateway identifier (team's internal id)</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Gateway display name</td>\n</tr>\n<tr>\n<td><strong>data.gateway_type</strong></td>\n<td><strong>string</strong>  <br />Gateway integration type</td>\n</tr>\n<tr>\n<td><strong>data.status</strong></td>\n<td><strong>string</strong>  <br />Current gateway status</td>\n</tr>\n<tr>\n<td><strong>data.monthly_processing_limit</strong></td>\n<td><strong>number</strong>  <br />Monthly processing limit in dollars</td>\n</tr>\n<tr>\n<td><strong>data.monthly_fee</strong></td>\n<td><strong>number</strong>  <br />Flat monthly fee</td>\n</tr>\n<tr>\n<td><strong>data.discount_rate</strong></td>\n<td><strong>number</strong>  <br />Discount rate percent (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.transaction_fee</strong></td>\n<td><strong>number</strong>  <br />Per-transaction fee</td>\n</tr>\n<tr>\n<td><strong>data.reserve_rate</strong></td>\n<td><strong>number</strong>  <br />Reserve rate percent (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.reserve_term_days</strong></td>\n<td><strong>integer</strong>  <br />Reserve holding period in days</td>\n</tr>\n<tr>\n<td><strong>data.accepted_card_brands</strong></td>\n<td><strong>array</strong>  <br />List of accepted card brands</td>\n</tr>\n<tr>\n<td><strong>data.accepts_prepaid_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether prepaid cards are accepted</td>\n</tr>\n<tr>\n<td><strong>data.accepts_virtual_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether virtual cards are accepted</td>\n</tr>\n<tr>\n<td><strong>data.accepts_international_cards</strong></td>\n<td><strong>boolean</strong>  <br />Whether international cards are accepted</td>\n</tr>\n<tr>\n<td><strong>data.use_dynamic_descriptors</strong></td>\n<td><strong>boolean</strong>  <br />Whether to use dynamic statement descriptors</td>\n</tr>\n<tr>\n<td><strong>data.accepted_currencies</strong></td>\n<td><strong>array</strong>  <br />List of accepted currency codes</td>\n</tr>\n<tr>\n<td><strong>data.accepted_countries</strong></td>\n<td><strong>array</strong>  <br />List of accepted ISO country codes</td>\n</tr>\n<tr>\n<td><strong>data.statement_descriptor</strong></td>\n<td><strong>string</strong>  <br />Default statement descriptor</td>\n</tr>\n<tr>\n<td><strong>data.statement_descriptor_phone</strong></td>\n<td><strong>string</strong>  <br />Statement descriptor phone number</td>\n</tr>\n<tr>\n<td><strong>data.support_phone</strong></td>\n<td><strong>string</strong>  <br />Customer support phone</td>\n</tr>\n<tr>\n<td><strong>data.support_email</strong></td>\n<td><strong>string</strong>  <br />Customer support email</td>\n</tr>\n<tr>\n<td><strong>data.support_url</strong></td>\n<td><strong>string</strong>  <br />Customer support URL</td>\n</tr>\n<tr>\n<td><strong>data.usage_percentage</strong></td>\n<td><strong>number</strong>  <br />Percent of monthly limit used</td>\n</tr>\n<tr>\n<td><strong>data.usage_status</strong></td>\n<td><strong>string</strong>  <br />Usage status indicator</td>\n</tr>\n<tr>\n<td><strong>data.last_successful_transaction_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp of the last successful transaction</td>\n</tr>\n<tr>\n<td><strong>data.last_connection_test_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp of the last connection test</td>\n</tr>\n<tr>\n<td><strong>data.last_connection_test_successful</strong></td>\n<td><strong>boolean</strong>  <br />Whether the most recent connection test succeeded</td>\n</tr>\n<tr>\n<td><strong>data.bin_blacklist_id</strong></td>\n<td><strong>integer</strong>  <br />Associated BIN blacklist id, if any</td>\n</tr>\n<tr>\n<td><strong>data.decline_salvage_profile_id</strong></td>\n<td><strong>integer</strong>  <br />Associated decline salvage profile id, if any</td>\n</tr>\n<tr>\n<td><strong>data.category</strong></td>\n<td><strong>object</strong>  <br />Linked gateway category (if any)</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the gateway was created</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the gateway was last updated</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>404</strong></td>\n<td>Gateway not found</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","gateways","{{gatewayId}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"d306a8fa-8afb-28b3-53e1-dc9d36563ee9"},{"name":"Create Gateway","id":"0b1083be-ec23-8673-bb71-7346e3075f0b","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"My NMI Gateway\",\n  \"gateway_type\": \"nmi\",\n  \"status\": \"active\",\n  \"credentials\": {\n    \"security_key\": \"xxx-xxx-xxx\"\n  },\n  \"monthly_processing_limit\": 1000000,\n  \"monthly_fee\": 25.00,\n  \"discount_rate\": 2.9,\n  \"transaction_fee\": 0.30,\n  \"reserve_rate\": 0,\n  \"reserve_term_days\": 0,\n  \"accepted_card_brands\": [\"visa\", \"mastercard\", \"amex\", \"discover\"],\n  \"accepts_prepaid_cards\": false,\n  \"accepts_virtual_cards\": false,\n  \"accepts_international_cards\": true,\n  \"use_dynamic_descriptors\": false,\n  \"accepted_currencies\": [\"USD\"],\n  \"accepted_countries\": [\"US\", \"CA\"],\n  \"statement_descriptor\": \"MYBRAND\",\n  \"statement_descriptor_phone\": \"555-555-5555\",\n  \"support_phone\": \"555-555-1234\",\n  \"support_email\": \"support@example.com\",\n  \"support_url\": \"https://example.com/support\"\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/gateways","description":"<h1 id=\"create-gateway\">Create Gateway</h1>\n<p><strong>Create a New Gateway</strong></p>\n<p>Create a new gateway configuration for the authenticated account. Returns the detailed gateway object on success.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:gateways.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Gateway name. Must be unique within the team. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>gateway_type</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Gateway integration type. Options: <code>nmi</code>, <code>stripe</code>, <code>authorize_net</code>, <code>finix</code>, <code>convesio_pay</code>, <code>paynetworx</code>, <code>highwire</code>, <code>bulletproof</code>, <code>sandbox</code>, <code>big_dogs</code>.</td>\n</tr>\n<tr>\n<td><strong>status</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Gateway status. Defaults to <code>pending</code>. Options: <code>active</code>, <code>inactive</code>, <code>pending</code>, <code>error</code>, <code>suspended</code>.</td>\n</tr>\n<tr>\n<td><strong>credentials</strong></td>\n<td><em><strong>object (required)</strong></em>  <br />Gateway credentials. Shape varies by <code>gateway_type</code>.</td>\n</tr>\n<tr>\n<td><strong>monthly_processing_limit</strong></td>\n<td><em><strong>number (required)</strong></em>  <br />Monthly processing limit in dollars. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>monthly_fee</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Flat monthly fee. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>discount_rate</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Discount rate percent. Range 0–100.</td>\n</tr>\n<tr>\n<td><strong>transaction_fee</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Per-transaction fee. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>reserve_rate</strong></td>\n<td><em><strong>number (optional)</strong></em>  <br />Reserve rate percent. Range 0–100.</td>\n</tr>\n<tr>\n<td><strong>reserve_term_days</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Reserve holding period in days. Minimum 0.</td>\n</tr>\n<tr>\n<td><strong>accepted_card_brands</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of accepted card brands.</td>\n</tr>\n<tr>\n<td><strong>accepts_prepaid_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepts_virtual_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepts_international_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>use_dynamic_descriptors</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepted_currencies</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of accepted currency codes.</td>\n</tr>\n<tr>\n<td><strong>accepted_countries</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of accepted ISO country codes.</td>\n</tr>\n<tr>\n<td><strong>statement_descriptor</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>statement_descriptor_phone</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>support_phone</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>support_email</strong></td>\n<td><em><strong>email (optional)</strong></em>  <br />Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>support_url</strong></td>\n<td><em><strong>url (optional)</strong></em>  <br />Maximum 500 characters.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p><code>201 Created</code> — returns the full detailed gateway object identical to the <code>Get Gateway</code> response, plus:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Gateway created successfully\"\n}\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","gateways"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"0b1083be-ec23-8673-bb71-7346e3075f0b"},{"name":"Update Gateway","id":"9d38fe0c-c1b4-12eb-99fb-3d0145e0f15b","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Updated Gateway Name\",\n  \"status\": \"active\",\n  \"monthly_processing_limit\": 1500000\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/gateways/{{gatewayId}}","description":"<h1 id=\"update-gateway\">Update Gateway</h1>\n<p><strong>Partially Update a Gateway</strong></p>\n<p>Update mutable fields on a gateway. All fields are optional; only validated fields will be saved. The identifier in the URL is the team's internal gateway id.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:gateways.update</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>gatewayId</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal gateway id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional. Only the fields included will be updated.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Gateway name. Must be unique within the team.</td>\n</tr>\n<tr>\n<td><strong>gateway_type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Gateway integration type.</td>\n</tr>\n<tr>\n<td><strong>status</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Gateway status. Options: <code>active</code>, <code>inactive</code>, <code>pending</code>, <code>error</code>, <code>suspended</code>.</td>\n</tr>\n<tr>\n<td><strong>credentials</strong></td>\n<td><em><strong>object (optional)</strong></em>  <br />Gateway credentials.</td>\n</tr>\n<tr>\n<td><strong>monthly_processing_limit</strong></td>\n<td><em><strong>number (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>monthly_fee</strong></td>\n<td><em><strong>number (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>discount_rate</strong></td>\n<td><em><strong>number (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>transaction_fee</strong></td>\n<td><em><strong>number (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>reserve_rate</strong></td>\n<td><em><strong>number (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>reserve_term_days</strong></td>\n<td><em><strong>integer (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepted_card_brands</strong></td>\n<td><em><strong>array (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepts_prepaid_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepts_virtual_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepts_international_cards</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>use_dynamic_descriptors</strong></td>\n<td><em><strong>boolean (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepted_currencies</strong></td>\n<td><em><strong>array (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>accepted_countries</strong></td>\n<td><em><strong>array (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>statement_descriptor</strong></td>\n<td><em><strong>string (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>statement_descriptor_phone</strong></td>\n<td><em><strong>string (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>support_phone</strong></td>\n<td><em><strong>string (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>support_email</strong></td>\n<td><em><strong>email (optional)</strong></em></td>\n</tr>\n<tr>\n<td><strong>support_url</strong></td>\n<td><em><strong>url (optional)</strong></em></td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p><code>200 OK</code> — returns the updated detailed gateway object plus:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Gateway updated successfully\"\n}\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>404</strong></td>\n<td>Gateway not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","gateways","{{gatewayId}}"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"9d38fe0c-c1b4-12eb-99fb-3d0145e0f15b"},{"name":"Get Gateway Metrics","id":"97c90ba8-26f2-015d-4f4d-024b9b008523","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/gateways/{{gatewayId}}/metrics","description":"<h1 id=\"get-gateway-metrics\">Get Gateway Metrics</h1>\n<p><strong>Aggregated Performance Metrics for a Gateway</strong></p>\n<p>Returns aggregated transaction performance metrics for a single gateway over a date range. If no date filters are provided, defaults to the current calendar month.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/gateways/1/metrics?start_date=2026-05-01&amp;end_date=2026-05-31\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:gateways.metrics</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>gatewayId</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal gateway id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"query-parameters\">Query Parameters</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Query Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>start_date</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Inclusive start date in <code>YYYY-MM-DD</code> format. Defaults to the first day of the current month.</td>\n</tr>\n<tr>\n<td><strong>end_date</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Inclusive end date in <code>YYYY-MM-DD</code> format. Must be greater than or equal to <code>start_date</code>. Defaults to the last day of the current month. Maximum range: 366 days.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"gateway_id\": 1,\n    \"date_range\": {\n      \"start_date\": \"2026-05-01\",\n      \"end_date\": \"2026-05-31\"\n    },\n    \"metrics\": {\n      \"monthly_limit\": 1000000,\n      \"attempts_count\": 1200,\n      \"attempts_amount\": 250000.00,\n      \"approved_count\": 800,\n      \"approved_amount\": 180000.00,\n      \"declined_count\": 400,\n      \"declined_amount\": 70000.00,\n      \"voids_count\": 50,\n      \"voids_amount\": 10000.00,\n      \"refunds_count\": 30,\n      \"refunds_amount\": 8000.00,\n      \"chargebacks_count\": 10,\n      \"chargebacks_amount\": 5000.00\n    }\n  }\n}\n</code></pre>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data.gateway_id</strong></td>\n<td><strong>integer</strong>  <br />Gateway identifier (team's internal id)</td>\n</tr>\n<tr>\n<td><strong>data.date_range.start_date</strong></td>\n<td><strong>string</strong>  <br />Effective start date used for aggregation</td>\n</tr>\n<tr>\n<td><strong>data.date_range.end_date</strong></td>\n<td><strong>string</strong>  <br />Effective end date used for aggregation</td>\n</tr>\n<tr>\n<td><strong>data.metrics.monthly_limit</strong></td>\n<td><strong>number</strong>  <br />Gateway's configured monthly processing limit</td>\n</tr>\n<tr>\n<td><strong>data.metrics.attempts_count</strong></td>\n<td><strong>integer</strong>  <br />Total number of transaction attempts in range</td>\n</tr>\n<tr>\n<td><strong>data.metrics.attempts_amount</strong></td>\n<td><strong>number</strong>  <br />Total amount across all transaction attempts</td>\n</tr>\n<tr>\n<td><strong>data.metrics.approved_count</strong></td>\n<td><strong>integer</strong>  <br />Count of approved transactions (completed + authorized)</td>\n</tr>\n<tr>\n<td><strong>data.metrics.approved_amount</strong></td>\n<td><strong>number</strong>  <br />Total amount of approved transactions</td>\n</tr>\n<tr>\n<td><strong>data.metrics.declined_count</strong></td>\n<td><strong>integer</strong>  <br />Count of declined transactions (declined + failed + error)</td>\n</tr>\n<tr>\n<td><strong>data.metrics.declined_amount</strong></td>\n<td><strong>number</strong>  <br />Total amount of declined transactions</td>\n</tr>\n<tr>\n<td><strong>data.metrics.voids_count</strong></td>\n<td><strong>integer</strong>  <br />Count of voided transactions</td>\n</tr>\n<tr>\n<td><strong>data.metrics.voids_amount</strong></td>\n<td><strong>number</strong>  <br />Total amount of voided transactions</td>\n</tr>\n<tr>\n<td><strong>data.metrics.refunds_count</strong></td>\n<td><strong>integer</strong>  <br />Count of refunded transactions (full, partial, alert, RDR)</td>\n</tr>\n<tr>\n<td><strong>data.metrics.refunds_amount</strong></td>\n<td><strong>number</strong>  <br />Total amount of refunded transactions</td>\n</tr>\n<tr>\n<td><strong>data.metrics.chargebacks_count</strong></td>\n<td><strong>integer</strong>  <br />Count of chargebacks</td>\n</tr>\n<tr>\n<td><strong>data.metrics.chargebacks_amount</strong></td>\n<td><strong>number</strong>  <br />Total amount of chargebacks</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>404</strong></td>\n<td>Gateway not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (invalid date format, <code>end_date</code> before <code>start_date</code>, or range exceeds 366 days)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","gateways","{{gatewayId}}","metrics"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[],"_postman_id":"97c90ba8-26f2-015d-4f4d-024b9b008523"}],"id":"9dc99af5-3ae3-feb4-591f-8ec3f22e8b95","_postman_id":"9dc99af5-3ae3-feb4-591f-8ec3f22e8b95","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Affiliates","item":[{"name":"List Affiliates","id":"c7a6a032-a588-9d94-d7c9-f90a4b60f1d5","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/affiliates?search=AFF&is_active=1&per_page=15&page=1","description":"<h1 id=\"list-affiliates\">List Affiliates</h1>\n<p><strong>List &amp; search affiliates for the authenticated account.</strong></p>\n<p>Returns a paginated, account-scoped list of affiliates ordered by <code>created_at</code> descending. Supports filtering by active status and a partial search across the affiliate <code>name</code> and <code>custom_id</code>. Each item in this list view returns the summary affiliate object; the sub-affiliate identifier fields and detailed throttle fields are only returned by the <strong>Get Affiliate</strong>, <strong>Create Affiliate</strong>, and <strong>Update Affiliate</strong> endpoints.</p>\n<h2 id=\"example--search-active-affiliates\">Example — Search Active Affiliates</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/affiliates?is_active=1&amp;search=AFF&amp;per_page=15\n</code></pre><p>Returns active affiliates whose name or custom id contains <code>AFF</code>, 15 per page.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:affiliates.view_any</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>search</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Partial match against the affiliate's <code>name</code> OR <code>custom_id</code> (<code>LIKE %search%</code>). Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Filter by active status. Accepts <code>1</code>, <code>0</code>, <code>true</code>, <code>false</code>. Omit to return both active and inactive affiliates.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15.</td>\n</tr>\n<tr>\n<td>page</td>\n<td><em>integer (optional)</em>  <br />Page number to retrieve when results span multiple pages. Used together with <code>per_page</code>. Minimum: 1. Default: 1.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of affiliate objects matching the search criteria (summary view)</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>string</strong>  <br />The affiliate's <code>custom_id</code> (used as the public identifier). Same value as <code>custom_id</code></td>\n</tr>\n<tr>\n<td><strong>data.custom_id</strong></td>\n<td><strong>string</strong>  <br />Account-defined unique identifier for the affiliate</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Display name of the affiliate</td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the affiliate is currently active</td>\n</tr>\n<tr>\n<td><strong>data.throttle_rate</strong></td>\n<td><strong>integer/null</strong>  <br />Throttle rate (0–100). For the <code>percentage</code> algorithm this is the percent of orders scrubbed; for the <code>ratio</code> algorithm it is the N value (scrub 1 sale after N orders)</td>\n</tr>\n<tr>\n<td><strong>data.throttle_type</strong></td>\n<td><strong>string/null</strong>  <br />What is counted for throttling. Values: <code>revenue</code>, <code>sales</code>. Default: <code>sales</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_by</strong></td>\n<td><strong>string/null</strong>  <br />Scope the throttle applies to. Values: <code>affiliate</code>, <code>sub_affiliate</code>. Default: <code>affiliate</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether throttling is currently enabled for this affiliate. Default: <code>false</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_algorithm</strong></td>\n<td><strong>string/null</strong>  <br />Throttling algorithm. Values: <code>percentage</code>, <code>ratio</code>. Default: <code>percentage</code></td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string/null</strong>  <br />Date/time the affiliate was created (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string/null</strong>  <br />Date/time the affiliate was last updated (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Pagination metadata for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of affiliates matching the criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of affiliates per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td><code>{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }</code></td>\n<td>Token lacks the <code>api:affiliates.view_any</code> (or legacy <code>api:view_any</code>) permission</td>\n</tr>\n<tr>\n<td>422</td>\n<td><code>{ \"success\": false, \"message\": \"Validation error\", \"errors\": { ... } }</code></td>\n<td>One or more query parameters failed validation (e.g. <code>per_page</code> above 100)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","affiliates"],"host":["api","sparkcrm","io"],"query":[{"description":{"content":"<p>Partial match against the affiliate's name OR custom_id (LIKE %search%). Maximum 255 characters.</p>\n","type":"text/plain"},"key":"search","value":"AFF"},{"description":{"content":"<p>Filter by active status. Boolean — accepts 1, 0, true, false. Omit to return both active and inactive affiliates.</p>\n","type":"text/plain"},"key":"is_active","value":"1"},{"description":{"content":"<p>Number of results per page. Minimum: 1, Maximum: 100. Default: 15.</p>\n","type":"text/plain"},"key":"per_page","value":"15"},{"disabled":true,"description":{"content":"<p>Page number to retrieve when results span multiple pages. Minimum: 1. Default: 1.</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"35903d77-7c51-ab7d-3f93-f341c810ebe1","name":"List Affiliates","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/affiliates?search=AFF&is_active=1&per_page=15&page=1","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","affiliates"],"query":[{"description":"Partial match against the affiliate's name OR custom_id (LIKE %search%). Maximum 255 characters.","key":"search","value":"AFF"},{"description":"Filter by active status. Boolean — accepts 1, 0, true, false. Omit to return both active and inactive affiliates.","key":"is_active","value":"1"},{"description":"Number of results per page. Minimum: 1, Maximum: 100. Default: 15.","key":"per_page","value":"15"},{"description":"Page number to retrieve when results span multiple pages. Minimum: 1. Default: 1.","key":"page","value":"1","disabled":true}]},"description":"# List Affiliates\n\n**List & search affiliates for the authenticated account.**\n\nReturns a paginated, account-scoped list of affiliates ordered by `created_at` descending. Supports filtering by active status and a partial search across the affiliate `name` and `custom_id`. Each item in this list view returns the summary affiliate object; the sub-affiliate identifier fields and detailed throttle fields are only returned by the **Get Affiliate**, **Create Affiliate**, and **Update Affiliate** endpoints.\n\n## Example — Search Active Affiliates\n\n```\nGET https://api.sparkcrm.io/v1/affiliates?is_active=1&search=AFF&per_page=15\n```\n\nReturns active affiliates whose name or custom id contains `AFF`, 15 per page.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:affiliates.view_any`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| **search** | _**string (optional)**_  <br>Partial match against the affiliate's `name` OR `custom_id` (`LIKE %search%`). Maximum 255 characters. |\n| **is_active** | _**boolean (optional)**_  <br>Filter by active status. Accepts `1`, `0`, `true`, `false`. Omit to return both active and inactive affiliates. |\n| **per_page** | _**integer (optional)**_  <br>Number of results per page. Minimum: 1, Maximum: 100. Default: 15. |\n| page | _integer (optional)_  <br>Page number to retrieve when results span multiple pages. Used together with `per_page`. Minimum: 1. Default: 1. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **data** | **array**  <br>Array of affiliate objects matching the search criteria (summary view) |\n| **data.id** | **string**  <br>The affiliate's `custom_id` (used as the public identifier). Same value as `custom_id` |\n| **data.custom_id** | **string**  <br>Account-defined unique identifier for the affiliate |\n| **data.name** | **string**  <br>Display name of the affiliate |\n| **data.is_active** | **boolean**  <br>Whether the affiliate is currently active |\n| **data.throttle_rate** | **integer/null**  <br>Throttle rate (0–100). For the `percentage` algorithm this is the percent of orders scrubbed; for the `ratio` algorithm it is the N value (scrub 1 sale after N orders) |\n| **data.throttle_type** | **string/null**  <br>What is counted for throttling. Values: `revenue`, `sales`. Default: `sales` |\n| **data.throttle_by** | **string/null**  <br>Scope the throttle applies to. Values: `affiliate`, `sub_affiliate`. Default: `affiliate` |\n| **data.throttle_active** | **boolean**  <br>Whether throttling is currently enabled for this affiliate. Default: `false` |\n| **data.throttle_algorithm** | **string/null**  <br>Throttling algorithm. Values: `percentage`, `ratio`. Default: `percentage` |\n| **data.created_at** | **string/null**  <br>Date/time the affiliate was created (ISO 8601 format) |\n| **data.updated_at** | **string/null**  <br>Date/time the affiliate was last updated (ISO 8601 format) |\n| **pagination** | **object**  <br>Pagination metadata for the response |\n| **pagination.total** | **integer**  <br>Total number of affiliates matching the criteria |\n| **pagination.per_page** | **integer**  <br>Number of affiliates per page |\n| **pagination.current_page** | **integer**  <br>Current page number |\n| **pagination.last_page** | **integer**  <br>Total number of pages available |\n| **pagination.from** | **integer/null**  <br>Starting record number for the current page |\n| **pagination.to** | **integer/null**  <br>Ending record number for the current page |\n\n## Errors\n\n| Status | Body | Description |\n| --- | --- | --- |\n| 403 | `{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }` | Token lacks the `api:affiliates.view_any` (or legacy `api:view_any`) permission |\n| 422 | `{ \"success\": false, \"message\": \"Validation error\", \"errors\": { ... } }` | One or more query parameters failed validation (e.g. `per_page` above 100) |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": [\n        {\n            \"id\": \"AFF-1001\",\n            \"custom_id\": \"AFF-1001\",\n            \"name\": \"Summer Promo Partner\",\n            \"is_active\": true,\n            \"throttle_rate\": 20,\n            \"throttle_type\": \"sales\",\n            \"throttle_by\": \"affiliate\",\n            \"throttle_active\": true,\n            \"throttle_algorithm\": \"percentage\",\n            \"created_at\": \"2026-06-10T18:22:41.000000Z\",\n            \"updated_at\": \"2026-06-14T09:05:12.000000Z\"\n        },\n        {\n            \"id\": \"AFF-1002\",\n            \"custom_id\": \"AFF-1002\",\n            \"name\": \"Newsletter Affiliate\",\n            \"is_active\": false,\n            \"throttle_rate\": 0,\n            \"throttle_type\": \"sales\",\n            \"throttle_by\": \"affiliate\",\n            \"throttle_active\": false,\n            \"throttle_algorithm\": \"percentage\",\n            \"created_at\": \"2026-05-28T13:10:03.000000Z\",\n            \"updated_at\": \"2026-05-28T13:10:03.000000Z\"\n        }\n    ],\n    \"pagination\": {\n        \"total\": 2,\n        \"per_page\": 15,\n        \"current_page\": 1,\n        \"last_page\": 1,\n        \"from\": 1,\n        \"to\": 2\n    }\n}"}],"_postman_id":"c7a6a032-a588-9d94-d7c9-f90a4b60f1d5"},{"name":"Create Affiliate","id":"ab236b05-86c4-c3ef-0128-3ac49bc02426","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"name\": \"Summer Promo Partner\",\n    \"custom_id\": \"AFF-1001\",\n    \"is_active\": true,\n    \"sub_affiliate_field\": \"sub_affiliate_id_1\",\n    \"sub_affiliate_id_1\": \"sub-a\",\n    \"sub_affiliate_id_2\": \"sub-b\",\n    \"throttle_active\": true,\n    \"throttle_rate\": 20,\n    \"throttle_type\": \"sales\",\n    \"throttle_by\": \"affiliate\",\n    \"throttle_algorithm\": \"percentage\",\n    \"throttle_ratio\": 5,\n    \"throttle_sub_affiliate_id\": \"sub-a\",\n    \"minimum_sale_threshold\": 50\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/affiliates","description":"<h1 id=\"create-affiliate\">Create Affiliate</h1>\n<p><strong>Create a new affiliate for the authenticated account.</strong></p>\n<p>Creates an account-scoped affiliate. <code>name</code> and <code>custom_id</code> are required; <code>custom_id</code> must be unique within your account (the uniqueness check ignores soft-deleted affiliates). All throttle and sub-affiliate fields are optional and fall back to their model defaults when omitted. The response returns the <strong>detailed</strong> affiliate object including the sub-affiliate identifier fields and full throttle configuration.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:affiliates.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Display name of the affiliate. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>custom_id</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Account-defined unique identifier for the affiliate. Maximum 255 characters. Must be unique within your account (soft-deleted affiliates are ignored in the uniqueness check).</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether the affiliate is active. Accepts <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code>. Default: <code>true</code> (model default).</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_field</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Which sub-affiliate id field is treated as the affiliate's primary sub-affiliate value. Allowed values: <code>sub_affiliate_id_1</code>, <code>sub_affiliate_id_2</code>, <code>sub_affiliate_id_3</code>, <code>sub_affiliate_id_4</code>, <code>sub_affiliate_id_5</code>. Default: <code>sub_affiliate_id_1</code>.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_1</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 1. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_2</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 2. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_3</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 3. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_4</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 4. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_5</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 5. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>throttle_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Enable/disable throttling for this affiliate. Accepts <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code>. Default: <code>false</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_rate</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Throttle rate. Minimum: 0, Maximum: 100. For the <code>percentage</code> algorithm this is the percent of orders scrubbed.</td>\n</tr>\n<tr>\n<td><strong>throttle_type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />What is counted for throttling. Allowed values: <code>revenue</code>, <code>sales</code>. Default: <code>sales</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_by</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Scope the throttle applies to. Allowed values: <code>affiliate</code>, <code>sub_affiliate</code>. Default: <code>affiliate</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_algorithm</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Throttling algorithm. Allowed values: <code>percentage</code> (probabilistic — each order has an independent X% chance of being throttled) or <code>ratio</code> (deterministic — scrub 1 order after every N orders; counter resets daily at midnight in team timezone). Default: <code>percentage</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_ratio</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />The N value used by the <code>ratio</code> algorithm (scrub 1 sale after this many orders). Minimum: 0.</td>\n</tr>\n<tr>\n<td><strong>throttle_sub_affiliate_id</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />The specific sub-affiliate id the throttle targets when <code>throttle_by</code> is <code>sub_affiliate</code>. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>minimum_sale_threshold</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum sale amount that must be met before throttling applies. Minimum: 0. Default: 0.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Human-readable result message (<code>Affiliate created successfully</code>)</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The created affiliate (detailed view)</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>string</strong>  <br />The affiliate's <code>custom_id</code> (public identifier). Same value as <code>custom_id</code></td>\n</tr>\n<tr>\n<td><strong>data.custom_id</strong></td>\n<td><strong>string</strong>  <br />Account-defined unique identifier</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Display name of the affiliate</td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the affiliate is active</td>\n</tr>\n<tr>\n<td><strong>data.throttle_rate</strong></td>\n<td><strong>integer/null</strong>  <br />Throttle rate (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.throttle_type</strong></td>\n<td><strong>string/null</strong>  <br /><code>revenue</code> or <code>sales</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_by</strong></td>\n<td><strong>string/null</strong>  <br /><code>affiliate</code> or <code>sub_affiliate</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether throttling is enabled</td>\n</tr>\n<tr>\n<td><strong>data.throttle_algorithm</strong></td>\n<td><strong>string/null</strong>  <br /><code>percentage</code> or <code>ratio</code></td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_field</strong></td>\n<td><strong>string</strong>  <br />Which sub-affiliate id slot is the primary value (<code>sub_affiliate_id_1</code>–<code>sub_affiliate_id_5</code>)</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_1</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 1</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_2</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 2</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_3</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 3</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_4</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 4</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_5</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 5</td>\n</tr>\n<tr>\n<td><strong>data.throttle_sub_affiliate_id</strong></td>\n<td><strong>string/null</strong>  <br />Targeted sub-affiliate id when <code>throttle_by</code> is <code>sub_affiliate</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_ratio</strong></td>\n<td><strong>integer/null</strong>  <br />N value for the <code>ratio</code> algorithm</td>\n</tr>\n<tr>\n<td><strong>data.minimum_sale_threshold</strong></td>\n<td><strong>integer/null</strong>  <br />Minimum sale amount before throttling applies</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string/null</strong>  <br />Creation timestamp (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string/null</strong>  <br />Last update timestamp (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td><code>{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }</code></td>\n<td>Token lacks the <code>api:affiliates.create</code> (or legacy <code>api:create</code>) permission</td>\n</tr>\n<tr>\n<td>422</td>\n<td><code>{ \"success\": false, \"message\": \"Validation error\", \"errors\": { ... } }</code></td>\n<td>Validation failed — e.g. missing <code>name</code>/<code>custom_id</code>, duplicate <code>custom_id</code>, invalid enum value, or <code>throttle_rate</code> outside 0–100</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","affiliates"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"ffe1bef3-a4d5-fbd7-c5b8-537e5190894c","name":"Create Affiliate","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"name\": \"Summer Promo Partner\",\n    \"custom_id\": \"AFF-1001\",\n    \"is_active\": true,\n    \"sub_affiliate_field\": \"sub_affiliate_id_1\",\n    \"sub_affiliate_id_1\": \"sub-a\",\n    \"sub_affiliate_id_2\": \"sub-b\",\n    \"throttle_active\": true,\n    \"throttle_rate\": 20,\n    \"throttle_type\": \"sales\",\n    \"throttle_by\": \"affiliate\",\n    \"throttle_algorithm\": \"percentage\",\n    \"throttle_ratio\": 5,\n    \"throttle_sub_affiliate_id\": \"sub-a\",\n    \"minimum_sale_threshold\": 50\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/affiliates","description":"# Create Affiliate\n\n**Create a new affiliate for the authenticated account.**\n\nCreates an account-scoped affiliate. `name` and `custom_id` are required; `custom_id` must be unique within your account (the uniqueness check ignores soft-deleted affiliates). All throttle and sub-affiliate fields are optional and fall back to their model defaults when omitted. The response returns the **detailed** affiliate object including the sub-affiliate identifier fields and full throttle configuration.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:affiliates.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| **name** | _**string (required)**_  <br>Display name of the affiliate. Maximum 255 characters. |\n| **custom_id** | _**string (required)**_  <br>Account-defined unique identifier for the affiliate. Maximum 255 characters. Must be unique within your account (soft-deleted affiliates are ignored in the uniqueness check). |\n| **is_active** | _**boolean (optional)**_  <br>Whether the affiliate is active. Accepts `true`, `false`, `1`, `0`. Default: `true` (model default). |\n| **sub_affiliate_field** | _**string (optional)**_  <br>Which sub-affiliate id field is treated as the affiliate's primary sub-affiliate value. Allowed values: `sub_affiliate_id_1`, `sub_affiliate_id_2`, `sub_affiliate_id_3`, `sub_affiliate_id_4`, `sub_affiliate_id_5`. Default: `sub_affiliate_id_1`. |\n| **sub_affiliate_id_1** | _**string (optional)**_  <br>Sub-affiliate identifier slot 1. Maximum 255 characters. |\n| **sub_affiliate_id_2** | _**string (optional)**_  <br>Sub-affiliate identifier slot 2. Maximum 255 characters. |\n| **sub_affiliate_id_3** | _**string (optional)**_  <br>Sub-affiliate identifier slot 3. Maximum 255 characters. |\n| **sub_affiliate_id_4** | _**string (optional)**_  <br>Sub-affiliate identifier slot 4. Maximum 255 characters. |\n| **sub_affiliate_id_5** | _**string (optional)**_  <br>Sub-affiliate identifier slot 5. Maximum 255 characters. |\n| **throttle_active** | _**boolean (optional)**_  <br>Enable/disable throttling for this affiliate. Accepts `true`, `false`, `1`, `0`. Default: `false`. |\n| **throttle_rate** | _**integer (optional)**_  <br>Throttle rate. Minimum: 0, Maximum: 100. For the `percentage` algorithm this is the percent of orders scrubbed. |\n| **throttle_type** | _**string (optional)**_  <br>What is counted for throttling. Allowed values: `revenue`, `sales`. Default: `sales`. |\n| **throttle_by** | _**string (optional)**_  <br>Scope the throttle applies to. Allowed values: `affiliate`, `sub_affiliate`. Default: `affiliate`. |\n| **throttle_algorithm** | _**string (optional)**_  <br>Throttling algorithm. Allowed values: `percentage` (probabilistic — each order has an independent X% chance of being throttled) or `ratio` (deterministic — scrub 1 order after every N orders; counter resets daily at midnight in team timezone). Default: `percentage`. |\n| **throttle_ratio** | _**integer (optional)**_  <br>The N value used by the `ratio` algorithm (scrub 1 sale after this many orders). Minimum: 0. |\n| **throttle_sub_affiliate_id** | _**string (optional)**_  <br>The specific sub-affiliate id the throttle targets when `throttle_by` is `sub_affiliate`. Maximum 255 characters. |\n| **minimum_sale_threshold** | _**integer (optional)**_  <br>Minimum sale amount that must be met before throttling applies. Minimum: 0. Default: 0. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **message** | **string**  <br>Human-readable result message (`Affiliate created successfully`) |\n| **data** | **object**  <br>The created affiliate (detailed view) |\n| **data.id** | **string**  <br>The affiliate's `custom_id` (public identifier). Same value as `custom_id` |\n| **data.custom_id** | **string**  <br>Account-defined unique identifier |\n| **data.name** | **string**  <br>Display name of the affiliate |\n| **data.is_active** | **boolean**  <br>Whether the affiliate is active |\n| **data.throttle_rate** | **integer/null**  <br>Throttle rate (0–100) |\n| **data.throttle_type** | **string/null**  <br>`revenue` or `sales` |\n| **data.throttle_by** | **string/null**  <br>`affiliate` or `sub_affiliate` |\n| **data.throttle_active** | **boolean**  <br>Whether throttling is enabled |\n| **data.throttle_algorithm** | **string/null**  <br>`percentage` or `ratio` |\n| **data.sub_affiliate_field** | **string**  <br>Which sub-affiliate id slot is the primary value (`sub_affiliate_id_1`–`sub_affiliate_id_5`) |\n| **data.sub_affiliate_id_1** | **string/null**  <br>Sub-affiliate identifier slot 1 |\n| **data.sub_affiliate_id_2** | **string/null**  <br>Sub-affiliate identifier slot 2 |\n| **data.sub_affiliate_id_3** | **string/null**  <br>Sub-affiliate identifier slot 3 |\n| **data.sub_affiliate_id_4** | **string/null**  <br>Sub-affiliate identifier slot 4 |\n| **data.sub_affiliate_id_5** | **string/null**  <br>Sub-affiliate identifier slot 5 |\n| **data.throttle_sub_affiliate_id** | **string/null**  <br>Targeted sub-affiliate id when `throttle_by` is `sub_affiliate` |\n| **data.throttle_ratio** | **integer/null**  <br>N value for the `ratio` algorithm |\n| **data.minimum_sale_threshold** | **integer/null**  <br>Minimum sale amount before throttling applies |\n| **data.created_at** | **string/null**  <br>Creation timestamp (ISO 8601 format) |\n| **data.updated_at** | **string/null**  <br>Last update timestamp (ISO 8601 format) |\n\n## Errors\n\n| Status | Body | Description |\n| --- | --- | --- |\n| 403 | `{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }` | Token lacks the `api:affiliates.create` (or legacy `api:create`) permission |\n| 422 | `{ \"success\": false, \"message\": \"Validation error\", \"errors\": { ... } }` | Validation failed — e.g. missing `name`/`custom_id`, duplicate `custom_id`, invalid enum value, or `throttle_rate` outside 0–100 |"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Affiliate created successfully\",\n    \"data\": {\n        \"id\": \"AFF-1001\",\n        \"custom_id\": \"AFF-1001\",\n        \"name\": \"Summer Promo Partner\",\n        \"is_active\": true,\n        \"throttle_rate\": 20,\n        \"throttle_type\": \"sales\",\n        \"throttle_by\": \"affiliate\",\n        \"throttle_active\": true,\n        \"throttle_algorithm\": \"percentage\",\n        \"sub_affiliate_field\": \"sub_affiliate_id_1\",\n        \"sub_affiliate_id_1\": \"sub-a\",\n        \"sub_affiliate_id_2\": \"sub-b\",\n        \"sub_affiliate_id_3\": null,\n        \"sub_affiliate_id_4\": null,\n        \"sub_affiliate_id_5\": null,\n        \"throttle_sub_affiliate_id\": \"sub-a\",\n        \"throttle_ratio\": 5,\n        \"minimum_sale_threshold\": 50,\n        \"created_at\": \"2026-06-16T15:42:09.000000Z\",\n        \"updated_at\": \"2026-06-16T15:42:09.000000Z\"\n    }\n}"}],"_postman_id":"ab236b05-86c4-c3ef-0128-3ac49bc02426"},{"name":"Get Affiliate","id":"c727832c-068e-d1de-273c-ae25505b8ffc","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/affiliates/AFF-1001","description":"<h1 id=\"get-affiliate\">Get Affiliate</h1>\n<p><strong>Retrieve a single affiliate by its custom id (account-scoped).</strong></p>\n<p>Looks up an affiliate by its <code>custom_id</code> within the authenticated account and returns the <strong>detailed</strong> affiliate object — including the sub-affiliate identifier fields and full throttle configuration that are omitted from the list view. Returns <code>404</code> if no affiliate with that <code>custom_id</code> exists for your account.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:affiliates.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>custom_id</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />The affiliate's <code>custom_id</code> (path parameter). Account-scoped — only affiliates belonging to your account are matched.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The affiliate (detailed view)</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>string</strong>  <br />The affiliate's <code>custom_id</code> (public identifier). Same value as <code>custom_id</code></td>\n</tr>\n<tr>\n<td><strong>data.custom_id</strong></td>\n<td><strong>string</strong>  <br />Account-defined unique identifier</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Display name of the affiliate</td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the affiliate is active</td>\n</tr>\n<tr>\n<td><strong>data.throttle_rate</strong></td>\n<td><strong>integer/null</strong>  <br />Throttle rate (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.throttle_type</strong></td>\n<td><strong>string/null</strong>  <br /><code>revenue</code> or <code>sales</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_by</strong></td>\n<td><strong>string/null</strong>  <br /><code>affiliate</code> or <code>sub_affiliate</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether throttling is enabled</td>\n</tr>\n<tr>\n<td><strong>data.throttle_algorithm</strong></td>\n<td><strong>string/null</strong>  <br /><code>percentage</code> or <code>ratio</code></td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_field</strong></td>\n<td><strong>string</strong>  <br />Which sub-affiliate id slot is the primary value (<code>sub_affiliate_id_1</code>–<code>sub_affiliate_id_5</code>)</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_1</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 1</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_2</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 2</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_3</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 3</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_4</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 4</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_5</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 5</td>\n</tr>\n<tr>\n<td><strong>data.throttle_sub_affiliate_id</strong></td>\n<td><strong>string/null</strong>  <br />Targeted sub-affiliate id when <code>throttle_by</code> is <code>sub_affiliate</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_ratio</strong></td>\n<td><strong>integer/null</strong>  <br />N value for the <code>ratio</code> algorithm</td>\n</tr>\n<tr>\n<td><strong>data.minimum_sale_threshold</strong></td>\n<td><strong>integer/null</strong>  <br />Minimum sale amount before throttling applies</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string/null</strong>  <br />Creation timestamp (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string/null</strong>  <br />Last update timestamp (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td><code>{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }</code></td>\n<td>Token lacks the <code>api:affiliates.view</code> (or legacy <code>api:view_any</code>) permission</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>{ \"success\": false, \"message\": \"Affiliate not found\" }</code></td>\n<td>No affiliate with the given <code>custom_id</code> exists for your account</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","affiliates","AFF-1001"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"c22b5f23-fadc-93f8-ab1e-d38991a40339","name":"Get Affiliate","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/affiliates/AFF-1001","description":"# Get Affiliate\n\n**Retrieve a single affiliate by its custom id (account-scoped).**\n\nLooks up an affiliate by its `custom_id` within the authenticated account and returns the **detailed** affiliate object — including the sub-affiliate identifier fields and full throttle configuration that are omitted from the list view. Returns `404` if no affiliate with that `custom_id` exists for your account.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:affiliates.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| **custom_id** | _**string (required)**_  <br>The affiliate's `custom_id` (path parameter). Account-scoped — only affiliates belonging to your account are matched. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **data** | **object**  <br>The affiliate (detailed view) |\n| **data.id** | **string**  <br>The affiliate's `custom_id` (public identifier). Same value as `custom_id` |\n| **data.custom_id** | **string**  <br>Account-defined unique identifier |\n| **data.name** | **string**  <br>Display name of the affiliate |\n| **data.is_active** | **boolean**  <br>Whether the affiliate is active |\n| **data.throttle_rate** | **integer/null**  <br>Throttle rate (0–100) |\n| **data.throttle_type** | **string/null**  <br>`revenue` or `sales` |\n| **data.throttle_by** | **string/null**  <br>`affiliate` or `sub_affiliate` |\n| **data.throttle_active** | **boolean**  <br>Whether throttling is enabled |\n| **data.throttle_algorithm** | **string/null**  <br>`percentage` or `ratio` |\n| **data.sub_affiliate_field** | **string**  <br>Which sub-affiliate id slot is the primary value (`sub_affiliate_id_1`–`sub_affiliate_id_5`) |\n| **data.sub_affiliate_id_1** | **string/null**  <br>Sub-affiliate identifier slot 1 |\n| **data.sub_affiliate_id_2** | **string/null**  <br>Sub-affiliate identifier slot 2 |\n| **data.sub_affiliate_id_3** | **string/null**  <br>Sub-affiliate identifier slot 3 |\n| **data.sub_affiliate_id_4** | **string/null**  <br>Sub-affiliate identifier slot 4 |\n| **data.sub_affiliate_id_5** | **string/null**  <br>Sub-affiliate identifier slot 5 |\n| **data.throttle_sub_affiliate_id** | **string/null**  <br>Targeted sub-affiliate id when `throttle_by` is `sub_affiliate` |\n| **data.throttle_ratio** | **integer/null**  <br>N value for the `ratio` algorithm |\n| **data.minimum_sale_threshold** | **integer/null**  <br>Minimum sale amount before throttling applies |\n| **data.created_at** | **string/null**  <br>Creation timestamp (ISO 8601 format) |\n| **data.updated_at** | **string/null**  <br>Last update timestamp (ISO 8601 format) |\n\n## Errors\n\n| Status | Body | Description |\n| --- | --- | --- |\n| 403 | `{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }` | Token lacks the `api:affiliates.view` (or legacy `api:view_any`) permission |\n| 404 | `{ \"success\": false, \"message\": \"Affiliate not found\" }` | No affiliate with the given `custom_id` exists for your account |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"data\": {\n        \"id\": \"AFF-1001\",\n        \"custom_id\": \"AFF-1001\",\n        \"name\": \"Summer Promo Partner\",\n        \"is_active\": true,\n        \"throttle_rate\": 20,\n        \"throttle_type\": \"sales\",\n        \"throttle_by\": \"affiliate\",\n        \"throttle_active\": true,\n        \"throttle_algorithm\": \"percentage\",\n        \"sub_affiliate_field\": \"sub_affiliate_id_1\",\n        \"sub_affiliate_id_1\": \"sub-a\",\n        \"sub_affiliate_id_2\": \"sub-b\",\n        \"sub_affiliate_id_3\": null,\n        \"sub_affiliate_id_4\": null,\n        \"sub_affiliate_id_5\": null,\n        \"throttle_sub_affiliate_id\": \"sub-a\",\n        \"throttle_ratio\": 5,\n        \"minimum_sale_threshold\": 50,\n        \"created_at\": \"2026-06-10T18:22:41.000000Z\",\n        \"updated_at\": \"2026-06-14T09:05:12.000000Z\"\n    }\n}"}],"_postman_id":"c727832c-068e-d1de-273c-ae25505b8ffc"},{"name":"Update Affiliate","id":"1da29420-095e-032c-6017-82c2d90aad00","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n    \"name\": \"Summer Promo Partner (Updated)\",\n    \"is_active\": false,\n    \"throttle_active\": true,\n    \"throttle_algorithm\": \"ratio\",\n    \"throttle_ratio\": 8,\n    \"throttle_by\": \"sub_affiliate\",\n    \"throttle_sub_affiliate_id\": \"sub-b\",\n    \"sub_affiliate_field\": \"sub_affiliate_id_2\",\n    \"minimum_sale_threshold\": 100\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/affiliates/AFF-1001","description":"<h1 id=\"update-affiliate\">Update Affiliate</h1>\n<p><strong>Partially update an affiliate by its custom id (account-scoped).</strong></p>\n<p>Partial update — every field is optional and only the fields you send are validated and saved (<code>sometimes</code> rules). Omitted fields are left unchanged. The affiliate is matched by <code>custom_id</code> within your account. If you change <code>custom_id</code>, the new value must remain unique within your account (the current affiliate is excluded from the uniqueness check). The response returns the <strong>detailed</strong> affiliate object reflecting the saved changes.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:affiliates.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional; only the fields present in the request are validated and updated.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>custom_id</strong> (path)</td>\n<td><em><strong>string (required)</strong></em>  <br />The current <code>custom_id</code> of the affiliate to update (path parameter).</td>\n</tr>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Display name of the affiliate. When sent it is required (non-empty). Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>custom_id</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />New unique identifier for the affiliate. When sent it is required (non-empty). Maximum 255 characters. Must be unique within your account, excluding this affiliate and soft-deleted records.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether the affiliate is active. Accepts <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code>.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_field</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Primary sub-affiliate id slot. Allowed values: <code>sub_affiliate_id_1</code>, <code>sub_affiliate_id_2</code>, <code>sub_affiliate_id_3</code>, <code>sub_affiliate_id_4</code>, <code>sub_affiliate_id_5</code>.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_1</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 1. Maximum 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_2</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 2. Maximum 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_3</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 3. Maximum 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_4</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 4. Maximum 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><strong>sub_affiliate_id_5</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Sub-affiliate identifier slot 5. Maximum 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><strong>throttle_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Enable/disable throttling. Accepts <code>true</code>, <code>false</code>, <code>1</code>, <code>0</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_rate</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Throttle rate. Minimum: 0, Maximum: 100. Nullable.</td>\n</tr>\n<tr>\n<td><strong>throttle_type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />What is counted. Allowed values: <code>revenue</code>, <code>sales</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_by</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Throttle scope. Allowed values: <code>affiliate</code>, <code>sub_affiliate</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_algorithm</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Throttling algorithm. Allowed values: <code>percentage</code>, <code>ratio</code>.</td>\n</tr>\n<tr>\n<td><strong>throttle_ratio</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />N value for the <code>ratio</code> algorithm. Minimum: 0. Nullable.</td>\n</tr>\n<tr>\n<td><strong>throttle_sub_affiliate_id</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Targeted sub-affiliate id when <code>throttle_by</code> is <code>sub_affiliate</code>. Maximum 255 characters. Nullable.</td>\n</tr>\n<tr>\n<td><strong>minimum_sale_threshold</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Minimum sale amount before throttling applies. Minimum: 0. Nullable.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Human-readable result message (<code>Affiliate updated successfully</code>)</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />The updated affiliate (detailed view — same shape as <strong>Get Affiliate</strong> / <strong>Create Affiliate</strong>)</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>string</strong>  <br />The affiliate's <code>custom_id</code> (public identifier). Same value as <code>custom_id</code></td>\n</tr>\n<tr>\n<td><strong>data.custom_id</strong></td>\n<td><strong>string</strong>  <br />Account-defined unique identifier</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Display name of the affiliate</td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the affiliate is active</td>\n</tr>\n<tr>\n<td><strong>data.throttle_rate</strong></td>\n<td><strong>integer/null</strong>  <br />Throttle rate (0–100)</td>\n</tr>\n<tr>\n<td><strong>data.throttle_type</strong></td>\n<td><strong>string/null</strong>  <br /><code>revenue</code> or <code>sales</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_by</strong></td>\n<td><strong>string/null</strong>  <br /><code>affiliate</code> or <code>sub_affiliate</code></td>\n</tr>\n<tr>\n<td><strong>data.throttle_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether throttling is enabled</td>\n</tr>\n<tr>\n<td><strong>data.throttle_algorithm</strong></td>\n<td><strong>string/null</strong>  <br /><code>percentage</code> or <code>ratio</code></td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_field</strong></td>\n<td><strong>string</strong>  <br />Primary sub-affiliate id slot</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_1</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 1</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_2</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 2</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_3</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 3</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_4</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 4</td>\n</tr>\n<tr>\n<td><strong>data.sub_affiliate_id_5</strong></td>\n<td><strong>string/null</strong>  <br />Sub-affiliate identifier slot 5</td>\n</tr>\n<tr>\n<td><strong>data.throttle_sub_affiliate_id</strong></td>\n<td><strong>string/null</strong>  <br />Targeted sub-affiliate id</td>\n</tr>\n<tr>\n<td><strong>data.throttle_ratio</strong></td>\n<td><strong>integer/null</strong>  <br />N value for the <code>ratio</code> algorithm</td>\n</tr>\n<tr>\n<td><strong>data.minimum_sale_threshold</strong></td>\n<td><strong>integer/null</strong>  <br />Minimum sale amount before throttling applies</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string/null</strong>  <br />Creation timestamp (ISO 8601 format)</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string/null</strong>  <br />Last update timestamp (ISO 8601 format)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td><code>{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }</code></td>\n<td>Token lacks the <code>api:affiliates.update</code> (or legacy <code>api:update</code>) permission</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>{ \"success\": false, \"message\": \"Affiliate not found\" }</code></td>\n<td>No affiliate with the given <code>custom_id</code> exists for your account</td>\n</tr>\n<tr>\n<td>422</td>\n<td><code>{ \"success\": false, \"message\": \"Validation error\", \"errors\": { ... } }</code></td>\n<td>Validation failed — e.g. duplicate <code>custom_id</code>, invalid enum value, or <code>throttle_rate</code> outside 0–100</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","affiliates","AFF-1001"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"64bffea0-3e73-e2f3-68af-18343fac023c","name":"Update Affiliate","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n    \"name\": \"Summer Promo Partner (Updated)\",\n    \"is_active\": false,\n    \"throttle_active\": true,\n    \"throttle_algorithm\": \"ratio\",\n    \"throttle_ratio\": 8,\n    \"throttle_by\": \"sub_affiliate\",\n    \"throttle_sub_affiliate_id\": \"sub-b\",\n    \"sub_affiliate_field\": \"sub_affiliate_id_2\",\n    \"minimum_sale_threshold\": 100\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/affiliates/AFF-1001","description":"# Update Affiliate\n\n**Partially update an affiliate by its custom id (account-scoped).**\n\nPartial update — every field is optional and only the fields you send are validated and saved (`sometimes` rules). Omitted fields are left unchanged. The affiliate is matched by `custom_id` within your account. If you change `custom_id`, the new value must remain unique within your account (the current affiliate is excluded from the uniqueness check). The response returns the **detailed** affiliate object reflecting the saved changes.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:affiliates.update`\n\n## Request Body\n\nAll fields are optional; only the fields present in the request are validated and updated.\n\n| Request Field | Description |\n| --- | --- |\n| **custom_id** (path) | _**string (required)**_  <br>The current `custom_id` of the affiliate to update (path parameter). |\n| **name** | _**string (optional)**_  <br>Display name of the affiliate. When sent it is required (non-empty). Maximum 255 characters. |\n| **custom_id** | _**string (optional)**_  <br>New unique identifier for the affiliate. When sent it is required (non-empty). Maximum 255 characters. Must be unique within your account, excluding this affiliate and soft-deleted records. |\n| **is_active** | _**boolean (optional)**_  <br>Whether the affiliate is active. Accepts `true`, `false`, `1`, `0`. |\n| **sub_affiliate_field** | _**string (optional)**_  <br>Primary sub-affiliate id slot. Allowed values: `sub_affiliate_id_1`, `sub_affiliate_id_2`, `sub_affiliate_id_3`, `sub_affiliate_id_4`, `sub_affiliate_id_5`. |\n| **sub_affiliate_id_1** | _**string (optional)**_  <br>Sub-affiliate identifier slot 1. Maximum 255 characters. Nullable. |\n| **sub_affiliate_id_2** | _**string (optional)**_  <br>Sub-affiliate identifier slot 2. Maximum 255 characters. Nullable. |\n| **sub_affiliate_id_3** | _**string (optional)**_  <br>Sub-affiliate identifier slot 3. Maximum 255 characters. Nullable. |\n| **sub_affiliate_id_4** | _**string (optional)**_  <br>Sub-affiliate identifier slot 4. Maximum 255 characters. Nullable. |\n| **sub_affiliate_id_5** | _**string (optional)**_  <br>Sub-affiliate identifier slot 5. Maximum 255 characters. Nullable. |\n| **throttle_active** | _**boolean (optional)**_  <br>Enable/disable throttling. Accepts `true`, `false`, `1`, `0`. |\n| **throttle_rate** | _**integer (optional)**_  <br>Throttle rate. Minimum: 0, Maximum: 100. Nullable. |\n| **throttle_type** | _**string (optional)**_  <br>What is counted. Allowed values: `revenue`, `sales`. |\n| **throttle_by** | _**string (optional)**_  <br>Throttle scope. Allowed values: `affiliate`, `sub_affiliate`. |\n| **throttle_algorithm** | _**string (optional)**_  <br>Throttling algorithm. Allowed values: `percentage`, `ratio`. |\n| **throttle_ratio** | _**integer (optional)**_  <br>N value for the `ratio` algorithm. Minimum: 0. Nullable. |\n| **throttle_sub_affiliate_id** | _**string (optional)**_  <br>Targeted sub-affiliate id when `throttle_by` is `sub_affiliate`. Maximum 255 characters. Nullable. |\n| **minimum_sale_threshold** | _**integer (optional)**_  <br>Minimum sale amount before throttling applies. Minimum: 0. Nullable. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **message** | **string**  <br>Human-readable result message (`Affiliate updated successfully`) |\n| **data** | **object**  <br>The updated affiliate (detailed view — same shape as **Get Affiliate** / **Create Affiliate**) |\n| **data.id** | **string**  <br>The affiliate's `custom_id` (public identifier). Same value as `custom_id` |\n| **data.custom_id** | **string**  <br>Account-defined unique identifier |\n| **data.name** | **string**  <br>Display name of the affiliate |\n| **data.is_active** | **boolean**  <br>Whether the affiliate is active |\n| **data.throttle_rate** | **integer/null**  <br>Throttle rate (0–100) |\n| **data.throttle_type** | **string/null**  <br>`revenue` or `sales` |\n| **data.throttle_by** | **string/null**  <br>`affiliate` or `sub_affiliate` |\n| **data.throttle_active** | **boolean**  <br>Whether throttling is enabled |\n| **data.throttle_algorithm** | **string/null**  <br>`percentage` or `ratio` |\n| **data.sub_affiliate_field** | **string**  <br>Primary sub-affiliate id slot |\n| **data.sub_affiliate_id_1** | **string/null**  <br>Sub-affiliate identifier slot 1 |\n| **data.sub_affiliate_id_2** | **string/null**  <br>Sub-affiliate identifier slot 2 |\n| **data.sub_affiliate_id_3** | **string/null**  <br>Sub-affiliate identifier slot 3 |\n| **data.sub_affiliate_id_4** | **string/null**  <br>Sub-affiliate identifier slot 4 |\n| **data.sub_affiliate_id_5** | **string/null**  <br>Sub-affiliate identifier slot 5 |\n| **data.throttle_sub_affiliate_id** | **string/null**  <br>Targeted sub-affiliate id |\n| **data.throttle_ratio** | **integer/null**  <br>N value for the `ratio` algorithm |\n| **data.minimum_sale_threshold** | **integer/null**  <br>Minimum sale amount before throttling applies |\n| **data.created_at** | **string/null**  <br>Creation timestamp (ISO 8601 format) |\n| **data.updated_at** | **string/null**  <br>Last update timestamp (ISO 8601 format) |\n\n## Errors\n\n| Status | Body | Description |\n| --- | --- | --- |\n| 403 | `{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }` | Token lacks the `api:affiliates.update` (or legacy `api:update`) permission |\n| 404 | `{ \"success\": false, \"message\": \"Affiliate not found\" }` | No affiliate with the given `custom_id` exists for your account |\n| 422 | `{ \"success\": false, \"message\": \"Validation error\", \"errors\": { ... } }` | Validation failed — e.g. duplicate `custom_id`, invalid enum value, or `throttle_rate` outside 0–100 |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Affiliate updated successfully\",\n    \"data\": {\n        \"id\": \"AFF-1001\",\n        \"custom_id\": \"AFF-1001\",\n        \"name\": \"Summer Promo Partner (Updated)\",\n        \"is_active\": false,\n        \"throttle_rate\": 20,\n        \"throttle_type\": \"sales\",\n        \"throttle_by\": \"sub_affiliate\",\n        \"throttle_active\": true,\n        \"throttle_algorithm\": \"ratio\",\n        \"sub_affiliate_field\": \"sub_affiliate_id_2\",\n        \"sub_affiliate_id_1\": \"sub-a\",\n        \"sub_affiliate_id_2\": \"sub-b\",\n        \"sub_affiliate_id_3\": null,\n        \"sub_affiliate_id_4\": null,\n        \"sub_affiliate_id_5\": null,\n        \"throttle_sub_affiliate_id\": \"sub-b\",\n        \"throttle_ratio\": 8,\n        \"minimum_sale_threshold\": 100,\n        \"created_at\": \"2026-06-10T18:22:41.000000Z\",\n        \"updated_at\": \"2026-06-16T15:48:30.000000Z\"\n    }\n}"}],"_postman_id":"1da29420-095e-032c-6017-82c2d90aad00"},{"name":"Delete Affiliate","id":"e94aa239-e049-a0be-d05b-a1de6f36bcae","request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/affiliates/AFF-1001","description":"<h1 id=\"delete-affiliate\">Delete Affiliate</h1>\n<p><strong>Soft delete an affiliate by its custom id (account-scoped).</strong></p>\n<p>Soft-deletes the affiliate matched by <code>custom_id</code> within the authenticated account. The record is retained in the database with a <code>deleted_at</code> timestamp (not permanently removed), so the freed <code>custom_id</code> may be reused by a new affiliate. Returns <code>404</code> if no affiliate with that <code>custom_id</code> exists for your account.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:affiliates.delete</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>custom_id</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />The affiliate's <code>custom_id</code> (path parameter). Account-scoped — only affiliates belonging to your account are matched.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>message</strong></td>\n<td><strong>string</strong>  <br />Human-readable result message (<code>Affiliate deleted successfully</code>)</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td><code>{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }</code></td>\n<td>Token lacks the <code>api:affiliates.delete</code> (or legacy <code>api:delete</code>) permission</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>{ \"success\": false, \"message\": \"Affiliate not found\" }</code></td>\n<td>No affiliate with the given <code>custom_id</code> exists for your account</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","affiliates","AFF-1001"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"ba310e37-d471-9406-04f5-4c1e681fe919","name":"Delete Affiliate","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/affiliates/AFF-1001","description":"# Delete Affiliate\n\n**Soft delete an affiliate by its custom id (account-scoped).**\n\nSoft-deletes the affiliate matched by `custom_id` within the authenticated account. The record is retained in the database with a `deleted_at` timestamp (not permanently removed), so the freed `custom_id` may be reused by a new affiliate. Returns `404` if no affiliate with that `custom_id` exists for your account.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:affiliates.delete`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| **custom_id** | _**string (required)**_  <br>The affiliate's `custom_id` (path parameter). Account-scoped — only affiliates belonging to your account are matched. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **message** | **string**  <br>Human-readable result message (`Affiliate deleted successfully`) |\n\n## Errors\n\n| Status | Body | Description |\n| --- | --- | --- |\n| 403 | `{ \"success\": false, \"message\": \"Unauthorized. Token lacks the necessary permissions.\" }` | Token lacks the `api:affiliates.delete` (or legacy `api:delete`) permission |\n| 404 | `{ \"success\": false, \"message\": \"Affiliate not found\" }` | No affiliate with the given `custom_id` exists for your account |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"message\": \"Affiliate deleted successfully\"\n}"}],"_postman_id":"e94aa239-e049-a0be-d05b-a1de6f36bcae"}],"id":"d8bf20a4-ea41-3272-3418-be3ea184a683","_postman_id":"d8bf20a4-ea41-3272-3418-be3ea184a683","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Auto Responders","item":[{"name":"List Auto Responders","id":"4cf01389-94a3-1222-0f64-c5d43ac3fcfb","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/auto-responders?is_active=true&per_page=15&page=1","description":"<h1 id=\"list-auto-responders\">List Auto Responders</h1>\n<p><strong>Retrieve every automated email responder configured across all of your campaigns.</strong></p>\n<p>Returns a paginated list of auto responders belonging to the authenticated account. Auto responders are account-scoped through their parent campaign, so this endpoint aggregates responders from every campaign on the team. Results are ordered by creation date, newest first. This endpoint is read-only.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:auto_responders.view_any</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Filter by active state. When present, only responders matching the given state are returned. Accepts <code>true</code>/<code>false</code> (also <code>1</code>/<code>0</code>). Omit to return all responders regardless of state.</td>\n</tr>\n<tr>\n<td><code>per_page</code></td>\n<td><em><strong>integer (optional)</strong></em> Number of results per page. Min <code>1</code>, max <code>100</code>. Defaults to <code>15</code>.</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td><em><strong>integer (optional)</strong></em> Page number to retrieve. Min <code>1</code>. Defaults to <code>1</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code>, a <code>data</code> array of auto responder objects, and a <code>pagination</code> object.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>data[].id</code></td>\n<td>The auto responder's UUID.</td>\n</tr>\n<tr>\n<td><code>data[].campaign_id</code></td>\n<td>Internal numeric ID of the parent campaign.</td>\n</tr>\n<tr>\n<td><code>data[].name</code></td>\n<td>Human-readable name of the auto responder.</td>\n</tr>\n<tr>\n<td><code>data[].is_active</code></td>\n<td>Boolean indicating whether the responder is enabled.</td>\n</tr>\n<tr>\n<td><code>data[].trigger_types</code></td>\n<td>Array of trigger event strings that fire this responder (e.g. <code>order_confirmation</code>, <code>order_shipped</code>).</td>\n</tr>\n<tr>\n<td><code>data[].trigger_conditions</code></td>\n<td>Object of additional conditions controlling when the responder fires (e.g. <code>days_before_billing</code>). May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>data[].delay_minutes</code></td>\n<td>Integer number of minutes to wait after the trigger event before sending.</td>\n</tr>\n<tr>\n<td><code>data[].email_template_id</code></td>\n<td>Internal ID of the email template used for the message. May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>data[].smtp_provider_id</code></td>\n<td>Internal ID of the SMTP provider used to send. May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>data[].excluded_products</code></td>\n<td>Array of product IDs excluded from this responder. May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>data[].created_at</code></td>\n<td>ISO 8601 timestamp of creation.</td>\n</tr>\n<tr>\n<td><code>data[].updated_at</code></td>\n<td>ISO 8601 timestamp of last update.</td>\n</tr>\n<tr>\n<td><code>pagination.total</code></td>\n<td>Total number of matching responders.</td>\n</tr>\n<tr>\n<td><code>pagination.per_page</code></td>\n<td>Results per page.</td>\n</tr>\n<tr>\n<td><code>pagination.current_page</code></td>\n<td>Current page number.</td>\n</tr>\n<tr>\n<td><code>pagination.last_page</code></td>\n<td>Last available page number.</td>\n</tr>\n<tr>\n<td><code>pagination.from</code></td>\n<td>Index of the first item on the current page (<code>null</code> if empty).</td>\n</tr>\n<tr>\n<td><code>pagination.to</code></td>\n<td>Index of the last item on the current page (<code>null</code> if empty).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Missing the <code>api:auto_responders.view_any</code> permission.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error (e.g. <code>per_page</code> out of range, non-boolean <code>is_active</code>).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /v1/auto-responders?is_active=true&amp;per_page=15&amp;page=1\nAuthorization: Bearer &lt;token&gt;\n</code></pre><p><strong>Response</strong> <code>200 OK</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": \"9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\",\n      \"campaign_id\": 1042,\n      \"name\": \"Order Confirmation Email\",\n      \"is_active\": true,\n      \"trigger_types\": [\"order_confirmation\"],\n      \"trigger_conditions\": null,\n      \"delay_minutes\": 0,\n      \"email_template_id\": 318,\n      \"smtp_provider_id\": 12,\n      \"excluded_products\": [],\n      \"created_at\": \"2026-05-14T16:22:08.000000Z\",\n      \"updated_at\": \"2026-06-02T09:41:55.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 1,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 1\n  }\n}\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","auto-responders"],"host":["api","sparkcrm","io"],"query":[{"description":{"content":"<p>Optional boolean filter. When present, returns only responders with the given active state. Accepts true/false (also 1/0). Omit to return both active and inactive responders.</p>\n","type":"text/plain"},"key":"is_active","value":"true"},{"description":{"content":"<p>Optional integer. Results per page. Min 1, max 100. Defaults to 15 when omitted.</p>\n","type":"text/plain"},"key":"per_page","value":"15"},{"description":{"content":"<p>Optional integer. Page number to retrieve. Min 1. Defaults to 1.</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"505c1a25-671b-b1f6-60fe-f8e072cdbc77","name":"List Auto Responders","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/auto-responders?is_active=true&per_page=15&page=1","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","auto-responders"],"query":[{"description":"Optional boolean filter. When present, returns only responders with the given active state. Accepts true/false (also 1/0). Omit to return both active and inactive responders.","value":"true","key":"is_active"},{"description":"Optional integer. Results per page. Min 1, max 100. Defaults to 15 when omitted.","value":"15","key":"per_page"},{"description":"Optional integer. Page number to retrieve. Min 1. Defaults to 1.","value":"1","key":"page"}]},"description":"# List Auto Responders\n\n**Retrieve every automated email responder configured across all of your campaigns.**\n\nReturns a paginated list of auto responders belonging to the authenticated account. Auto responders are account-scoped through their parent campaign, so this endpoint aggregates responders from every campaign on the team. Results are ordered by creation date, newest first. This endpoint is read-only.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:auto_responders.view_any`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `is_active` | _**boolean (optional)**_ Filter by active state. When present, only responders matching the given state are returned. Accepts `true`/`false` (also `1`/`0`). Omit to return all responders regardless of state. |\n| `per_page` | _**integer (optional)**_ Number of results per page. Min `1`, max `100`. Defaults to `15`. |\n| `page` | _**integer (optional)**_ Page number to retrieve. Min `1`. Defaults to `1`. |\n\n## Response Object\n\nReturns `success: true`, a `data` array of auto responder objects, and a `pagination` object.\n\n| Field | Description |\n| --- | --- |\n| `data[].id` | The auto responder's UUID. |\n| `data[].campaign_id` | Internal numeric ID of the parent campaign. |\n| `data[].name` | Human-readable name of the auto responder. |\n| `data[].is_active` | Boolean indicating whether the responder is enabled. |\n| `data[].trigger_types` | Array of trigger event strings that fire this responder (e.g. `order_confirmation`, `order_shipped`). |\n| `data[].trigger_conditions` | Object of additional conditions controlling when the responder fires (e.g. `days_before_billing`). May be `null`. |\n| `data[].delay_minutes` | Integer number of minutes to wait after the trigger event before sending. |\n| `data[].email_template_id` | Internal ID of the email template used for the message. May be `null`. |\n| `data[].smtp_provider_id` | Internal ID of the SMTP provider used to send. May be `null`. |\n| `data[].excluded_products` | Array of product IDs excluded from this responder. May be `null`. |\n| `data[].created_at` | ISO 8601 timestamp of creation. |\n| `data[].updated_at` | ISO 8601 timestamp of last update. |\n| `pagination.total` | Total number of matching responders. |\n| `pagination.per_page` | Results per page. |\n| `pagination.current_page` | Current page number. |\n| `pagination.last_page` | Last available page number. |\n| `pagination.from` | Index of the first item on the current page (`null` if empty). |\n| `pagination.to` | Index of the last item on the current page (`null` if empty). |\n\n## Errors\n\n| Code | Meaning |\n| --- | --- |\n| `403` | Missing the `api:auto_responders.view_any` permission. |\n| `422` | Validation error (e.g. `per_page` out of range, non-boolean `is_active`). |\n\n## Example\n\n**Request**\n\n```\nGET /v1/auto-responders?is_active=true&per_page=15&page=1\nAuthorization: Bearer <token>\n```\n\n**Response** `200 OK`\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": \"9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\",\n      \"campaign_id\": 1042,\n      \"name\": \"Order Confirmation Email\",\n      \"is_active\": true,\n      \"trigger_types\": [\"order_confirmation\"],\n      \"trigger_conditions\": null,\n      \"delay_minutes\": 0,\n      \"email_template_id\": 318,\n      \"smtp_provider_id\": 12,\n      \"excluded_products\": [],\n      \"created_at\": \"2026-05-14T16:22:08.000000Z\",\n      \"updated_at\": \"2026-06-02T09:41:55.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 1,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 1\n  }\n}\n```"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": \"9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\",\n      \"campaign_id\": 1042,\n      \"name\": \"Order Confirmation Email\",\n      \"is_active\": true,\n      \"trigger_types\": [\"order_confirmation\"],\n      \"trigger_conditions\": null,\n      \"delay_minutes\": 0,\n      \"email_template_id\": 318,\n      \"smtp_provider_id\": 12,\n      \"excluded_products\": [],\n      \"created_at\": \"2026-05-14T16:22:08.000000Z\",\n      \"updated_at\": \"2026-06-02T09:41:55.000000Z\"\n    },\n    {\n      \"id\": \"3a7d9e62-1b4f-4c8d-9f02-6e8a1c3b5d77\",\n      \"campaign_id\": 1042,\n      \"name\": \"Subscription Reminder\",\n      \"is_active\": false,\n      \"trigger_types\": [\"subscription_reminder\"],\n      \"trigger_conditions\": {\n        \"days_before_billing\": 3\n      },\n      \"delay_minutes\": 60,\n      \"email_template_id\": 412,\n      \"smtp_provider_id\": 12,\n      \"excluded_products\": [205, 318],\n      \"created_at\": \"2026-04-30T11:05:42.000000Z\",\n      \"updated_at\": \"2026-05-21T14:18:30.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 2,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 2\n  }\n}"}],"_postman_id":"4cf01389-94a3-1222-0f64-c5d43ac3fcfb"},{"name":"Get Auto Responder","id":"383405d5-2983-b331-0728-5ae4f8e33c91","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/auto-responders/9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc","description":"<h1 id=\"get-auto-responder\">Get Auto Responder</h1>\n<p><strong>Retrieve a single automated email responder by its UUID.</strong></p>\n<p>Returns the full detail of one auto responder identified by its UUID. The responder is account-scoped through its parent campaign; requesting a UUID that does not belong to the authenticated team returns a 404. This endpoint is read-only.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:auto_responders.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>auto_responder_id</code></td>\n<td><em><strong>string (required)</strong></em> URL path parameter. The UUID of the auto responder to retrieve. Must match the pattern <code>[a-zA-Z0-9\\-]+</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> object describing the auto responder.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>The auto responder's UUID.</td>\n</tr>\n<tr>\n<td><code>campaign_id</code></td>\n<td>Internal numeric ID of the parent campaign.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>Human-readable name of the auto responder.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td>Boolean indicating whether the responder is enabled.</td>\n</tr>\n<tr>\n<td><code>trigger_types</code></td>\n<td>Array of trigger event strings that fire this responder. Possible values: <code>order_confirmation</code>, <code>tracking_issued</code>, <code>carrier_accepted</code>, <code>order_shipped</code>, <code>shipment_in_transit</code>, <code>shipment_out_for_delivery</code>, <code>shipment_delivered</code>, <code>order_refunded</code>, <code>order_canceled</code>, <code>order_voided</code>, <code>subscription_reminder</code>, <code>subscription_renewed</code>.</td>\n</tr>\n<tr>\n<td><code>trigger_conditions</code></td>\n<td>Object of additional conditions controlling when the responder fires (e.g. <code>days_before_billing</code> for subscription reminders). May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>delay_minutes</code></td>\n<td>Integer number of minutes to wait after the trigger event before sending.</td>\n</tr>\n<tr>\n<td><code>email_template_id</code></td>\n<td>Internal ID of the email template used for the message. May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>smtp_provider_id</code></td>\n<td>Internal ID of the SMTP provider used to send. May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>excluded_products</code></td>\n<td>Array of product IDs excluded from this responder. May be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td>ISO 8601 timestamp of creation.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td>ISO 8601 timestamp of last update.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Missing the <code>api:auto_responders.view</code> permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>Auto responder not found, or it does not belong to the authenticated account.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><strong>Request</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /v1/auto-responders/9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\nAuthorization: Bearer &lt;token&gt;\n</code></pre><p><strong>Response</strong> <code>200 OK</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {\n    \"id\": \"9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\",\n    \"campaign_id\": 1042,\n    \"name\": \"Order Confirmation Email\",\n    \"is_active\": true,\n    \"trigger_types\": [\"order_confirmation\"],\n    \"trigger_conditions\": null,\n    \"delay_minutes\": 0,\n    \"email_template_id\": 318,\n    \"smtp_provider_id\": 12,\n    \"excluded_products\": [],\n    \"created_at\": \"2026-05-14T16:22:08.000000Z\",\n    \"updated_at\": \"2026-06-02T09:41:55.000000Z\"\n  }\n}\n</code></pre>\n<p><strong>Response</strong> <code>404 Not Found</code></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": false,\n  \"message\": \"Auto responder not found\"\n}\n</code></pre>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","auto-responders","9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"edfd4793-512a-b786-2be5-1f260d3c3223","name":"Get Auto Responder","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/auto-responders/9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc","description":"# Get Auto Responder\n\n**Retrieve a single automated email responder by its UUID.**\n\nReturns the full detail of one auto responder identified by its UUID. The responder is account-scoped through its parent campaign; requesting a UUID that does not belong to the authenticated team returns a 404. This endpoint is read-only.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:auto_responders.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `auto_responder_id` | _**string (required)**_ URL path parameter. The UUID of the auto responder to retrieve. Must match the pattern `[a-zA-Z0-9\\-]+`. |\n\n## Response Object\n\nReturns `success: true` and a `data` object describing the auto responder.\n\n| Field | Description |\n| --- | --- |\n| `id` | The auto responder's UUID. |\n| `campaign_id` | Internal numeric ID of the parent campaign. |\n| `name` | Human-readable name of the auto responder. |\n| `is_active` | Boolean indicating whether the responder is enabled. |\n| `trigger_types` | Array of trigger event strings that fire this responder. Possible values: `order_confirmation`, `tracking_issued`, `carrier_accepted`, `order_shipped`, `shipment_in_transit`, `shipment_out_for_delivery`, `shipment_delivered`, `order_refunded`, `order_canceled`, `order_voided`, `subscription_reminder`, `subscription_renewed`. |\n| `trigger_conditions` | Object of additional conditions controlling when the responder fires (e.g. `days_before_billing` for subscription reminders). May be `null`. |\n| `delay_minutes` | Integer number of minutes to wait after the trigger event before sending. |\n| `email_template_id` | Internal ID of the email template used for the message. May be `null`. |\n| `smtp_provider_id` | Internal ID of the SMTP provider used to send. May be `null`. |\n| `excluded_products` | Array of product IDs excluded from this responder. May be `null`. |\n| `created_at` | ISO 8601 timestamp of creation. |\n| `updated_at` | ISO 8601 timestamp of last update. |\n\n## Errors\n\n| Code | Meaning |\n| --- | --- |\n| `403` | Missing the `api:auto_responders.view` permission. |\n| `404` | Auto responder not found, or it does not belong to the authenticated account. |\n\n## Example\n\n**Request**\n\n```\nGET /v1/auto-responders/9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\nAuthorization: Bearer <token>\n```\n\n**Response** `200 OK`\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": \"9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\",\n    \"campaign_id\": 1042,\n    \"name\": \"Order Confirmation Email\",\n    \"is_active\": true,\n    \"trigger_types\": [\"order_confirmation\"],\n    \"trigger_conditions\": null,\n    \"delay_minutes\": 0,\n    \"email_template_id\": 318,\n    \"smtp_provider_id\": 12,\n    \"excluded_products\": [],\n    \"created_at\": \"2026-05-14T16:22:08.000000Z\",\n    \"updated_at\": \"2026-06-02T09:41:55.000000Z\"\n  }\n}\n```\n\n**Response** `404 Not Found`\n\n```json\n{\n  \"success\": false,\n  \"message\": \"Auto responder not found\"\n}\n```"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"id\": \"9b2f4c10-7e3a-4d6b-8a91-2c5f0e1d4abc\",\n    \"campaign_id\": 1042,\n    \"name\": \"Order Confirmation Email\",\n    \"is_active\": true,\n    \"trigger_types\": [\"order_confirmation\"],\n    \"trigger_conditions\": null,\n    \"delay_minutes\": 0,\n    \"email_template_id\": 318,\n    \"smtp_provider_id\": 12,\n    \"excluded_products\": [],\n    \"created_at\": \"2026-05-14T16:22:08.000000Z\",\n    \"updated_at\": \"2026-06-02T09:41:55.000000Z\"\n  }\n}"}],"_postman_id":"383405d5-2983-b331-0728-5ae4f8e33c91"}],"id":"50ccef1a-d9e8-e0b7-4735-3bb3fc9710bb","_postman_id":"50ccef1a-d9e8-e0b7-4735-3bb3fc9710bb","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Payment Routers","item":[{"name":"Gateways","item":[{"name":"List Router Gateways","id":"7b8be5b2-a204-506d-3bad-074e2ada6649","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways","description":"<h1 id=\"list-router-gateways\">List Router Gateways</h1>\n<p><strong>Returns every gateway assigned to a payment router, ordered by routing priority.</strong></p>\n<p>Fetches the gateway assignments attached to a single payment router (orchestrator). Each item in the response represents one gateway-to-router link together with its routing pivot settings (priority, weight, caps, decline/fail limits) and live counters. Results are always sorted ascending by <code>priority</code>. The router is resolved by its <code>internal_id</code> (the <code>{router_id}</code> path segment), scoped to the authenticated team.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.gateways.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>router_id</td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The payment router's <code>internal_id</code>. Must match <code>[0-9]+</code>. If no router with this id exists for the authenticated team, a <code>404 Payment router not found</code> is returned.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no query parameters and returns the full (non-paginated) list of gateway assignments for the router.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> array. Each element is an <code>OrchestratorGatewayResource</code>:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>gateway_id</td>\n<td>integer. The assigned gateway's <code>internal_id</code> (team-facing id). Present only when the gateway relation is loaded.</td>\n</tr>\n<tr>\n<td>gateway_name</td>\n<td>string. The gateway's display name.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td>boolean. Whether this assignment is active in the router.</td>\n</tr>\n<tr>\n<td>priority</td>\n<td>integer|null. Routing priority (lower is evaluated first); list is ordered ascending by this value.</td>\n</tr>\n<tr>\n<td>weight</td>\n<td>decimal(2)|null. Weighted-distribution weight for the gateway.</td>\n</tr>\n<tr>\n<td>monthly_cap</td>\n<td>decimal(2)|null. Optional monthly processing cap for the gateway within this router.</td>\n</tr>\n<tr>\n<td>supported_currencies</td>\n<td>array|null. ISO currency codes this assignment is restricted to.</td>\n</tr>\n<tr>\n<td>decline_limit</td>\n<td>integer|null. Decline threshold before the assignment auto-disables.</td>\n</tr>\n<tr>\n<td>fail_limit</td>\n<td>integer|null. Hard-failure threshold before the assignment auto-disables.</td>\n</tr>\n<tr>\n<td>current_decline_count</td>\n<td>integer. Running decline counter.</td>\n</tr>\n<tr>\n<td>current_fail_count</td>\n<td>integer. Running failure counter.</td>\n</tr>\n<tr>\n<td>disabled_at</td>\n<td>ISO 8601 datetime|null. When the assignment was auto-disabled, if applicable.</td>\n</tr>\n<tr>\n<td>last_processed_at</td>\n<td>ISO 8601 datetime|null. Last time a transaction was routed through this assignment.</td>\n</tr>\n<tr>\n<td>created_at</td>\n<td>ISO 8601 datetime. When the assignment was created.</td>\n</tr>\n<tr>\n<td>updated_at</td>\n<td>ISO 8601 datetime. When the assignment was last updated.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Missing <code>api:payment_routers.gateways.view</code> (or <code>api:view_any</code>) permission on the token.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found for this account.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET /v1/payment-routers/123/gateways</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","gateways"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"bf234984-c2c5-7f23-a84b-847df2fdb7c9","name":"List Router Gateways","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways","description":"# List Router Gateways\n\n**Returns every gateway assigned to a payment router, ordered by routing priority.**\n\nFetches the gateway assignments attached to a single payment router (orchestrator). Each item in the response represents one gateway-to-router link together with its routing pivot settings (priority, weight, caps, decline/fail limits) and live counters. Results are always sorted ascending by `priority`. The router is resolved by its `internal_id` (the `{router_id}` path segment), scoped to the authenticated team.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.gateways.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| router_id | _**integer (required)**_ Path parameter. The payment router's `internal_id`. Must match `[0-9]+`. If no router with this id exists for the authenticated team, a `404 Payment router not found` is returned. |\n\nThis endpoint takes no query parameters and returns the full (non-paginated) list of gateway assignments for the router.\n\n## Response Object\n\nReturns `success: true` and a `data` array. Each element is an `OrchestratorGatewayResource`:\n\n| Field | Description |\n| --- | --- |\n| gateway_id | integer. The assigned gateway's `internal_id` (team-facing id). Present only when the gateway relation is loaded. |\n| gateway_name | string. The gateway's display name. |\n| is_active | boolean. Whether this assignment is active in the router. |\n| priority | integer\\|null. Routing priority (lower is evaluated first); list is ordered ascending by this value. |\n| weight | decimal(2)\\|null. Weighted-distribution weight for the gateway. |\n| monthly_cap | decimal(2)\\|null. Optional monthly processing cap for the gateway within this router. |\n| supported_currencies | array\\|null. ISO currency codes this assignment is restricted to. |\n| decline_limit | integer\\|null. Decline threshold before the assignment auto-disables. |\n| fail_limit | integer\\|null. Hard-failure threshold before the assignment auto-disables. |\n| current_decline_count | integer. Running decline counter. |\n| current_fail_count | integer. Running failure counter. |\n| disabled_at | ISO 8601 datetime\\|null. When the assignment was auto-disabled, if applicable. |\n| last_processed_at | ISO 8601 datetime\\|null. Last time a transaction was routed through this assignment. |\n| created_at | ISO 8601 datetime. When the assignment was created. |\n| updated_at | ISO 8601 datetime. When the assignment was last updated. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Missing `api:payment_routers.gateways.view` (or `api:view_any`) permission on the token. |\n| 404 | Payment router not found for this account. |\n\n## Example\n\n`GET /v1/payment-routers/123/gateways`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"gateway_id\": 7,\n      \"gateway_name\": \"NMI - Primary\",\n      \"is_active\": true,\n      \"priority\": 1,\n      \"weight\": \"60.00\",\n      \"monthly_cap\": \"50000.00\",\n      \"supported_currencies\": [\"USD\", \"CAD\"],\n      \"decline_limit\": 25,\n      \"fail_limit\": 10,\n      \"current_decline_count\": 3,\n      \"current_fail_count\": 0,\n      \"disabled_at\": null,\n      \"last_processed_at\": \"2026-06-15T18:42:11.000000Z\",\n      \"created_at\": \"2026-05-01T12:00:00.000000Z\",\n      \"updated_at\": \"2026-06-15T18:42:11.000000Z\"\n    },\n    {\n      \"gateway_id\": 12,\n      \"gateway_name\": \"Authorize.Net - Backup\",\n      \"is_active\": true,\n      \"priority\": 2,\n      \"weight\": \"40.00\",\n      \"monthly_cap\": null,\n      \"supported_currencies\": null,\n      \"decline_limit\": null,\n      \"fail_limit\": null,\n      \"current_decline_count\": 0,\n      \"current_fail_count\": 0,\n      \"disabled_at\": null,\n      \"last_processed_at\": null,\n      \"created_at\": \"2026-05-03T09:15:00.000000Z\",\n      \"updated_at\": \"2026-05-03T09:15:00.000000Z\"\n    }\n  ]\n}"}],"_postman_id":"7b8be5b2-a204-506d-3bad-074e2ada6649"},{"name":"Add Router Gateway","id":"fa9dc5bd-a4a1-92dc-cac6-46e3c9a9d744","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"gateway_id\": 7,\n  \"is_active\": true,\n  \"priority\": 1,\n  \"weight\": 60,\n  \"monthly_cap\": 50000,\n  \"supported_currencies\": [\"USD\", \"CAD\"],\n  \"decline_limit\": 25,\n  \"fail_limit\": 10\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways","description":"<h1 id=\"add-router-gateway\">Add Router Gateway</h1>\n<p><strong>Attaches an existing team gateway to a payment router with its routing settings.</strong></p>\n<p>Creates a new gateway assignment on the router identified by <code>{router_id}</code>. The <code>gateway_id</code> in the body is the gateway's <code>internal_id</code> (the team-facing id), which is resolved to the gateway record for the authenticated team. A gateway can only be attached to a given router once; attempting to attach a gateway that is already assigned returns a <code>422</code> validation error. On success the new assignment is returned with status <code>201</code>.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.gateways.attach</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>gateway_id</td>\n<td><em><strong>integer (required)</strong></em> The gateway's <code>internal_id</code> to attach. Must exist as a gateway for the authenticated team, otherwise a <code>422</code> is returned (<code>The selected gateway does not exist for this account.</code>). Must not already be assigned to this router.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><em><strong>boolean (optional)</strong></em> Whether the assignment is active. <code>nullable</code>.</td>\n</tr>\n<tr>\n<td>priority</td>\n<td><em><strong>integer (optional)</strong></em> Routing priority; lower values are evaluated first. <code>nullable</code>, <code>min:0</code>.</td>\n</tr>\n<tr>\n<td>weight</td>\n<td><em><strong>integer (optional)</strong></em> Weighted-distribution weight. <code>nullable</code>, <code>min:0</code>. (Stored as decimal(2).)</td>\n</tr>\n<tr>\n<td>monthly_cap</td>\n<td><em><strong>numeric (optional)</strong></em> Monthly processing cap amount. <code>nullable</code>, <code>min:0</code>. (Stored as decimal(2).)</td>\n</tr>\n<tr>\n<td>supported_currencies</td>\n<td><em><strong>array (optional)</strong></em> List of ISO currency codes this assignment is restricted to. <code>nullable</code>.</td>\n</tr>\n<tr>\n<td>decline_limit</td>\n<td><em><strong>integer (optional)</strong></em> Decline threshold before auto-disable. <code>nullable</code>, <code>min:0</code>.</td>\n</tr>\n<tr>\n<td>fail_limit</td>\n<td><em><strong>integer (optional)</strong></em> Hard-failure threshold before auto-disable. <code>nullable</code>, <code>min:0</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Path parameter <code>router_id</code> (<em><strong>integer, required</strong></em>) is the router's <code>internal_id</code>.</p>\n<h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code>, a <code>message</code>, and the created assignment under <code>data</code> as an <code>OrchestratorGatewayResource</code> (same field shape as the list endpoint). <code>gateway_id</code> is echoed back as the gateway's <code>internal_id</code>.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Missing <code>api:payment_routers.gateways.attach</code> (or <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found for this account.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation error — invalid field, <code>gateway_id</code> does not exist for this account, or the gateway is already assigned to the router.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>POST /v1/payment-routers/123/gateways</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","gateways"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"377f5033-2f6b-278e-fbf4-3bd89696f2e5","name":"Add Router Gateway","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"gateway_id\": 7,\n  \"is_active\": true,\n  \"priority\": 1,\n  \"weight\": 60,\n  \"monthly_cap\": 50000,\n  \"supported_currencies\": [\"USD\", \"CAD\"],\n  \"decline_limit\": 25,\n  \"fail_limit\": 10\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways","description":"# Add Router Gateway\n\n**Attaches an existing team gateway to a payment router with its routing settings.**\n\nCreates a new gateway assignment on the router identified by `{router_id}`. The `gateway_id` in the body is the gateway's `internal_id` (the team-facing id), which is resolved to the gateway record for the authenticated team. A gateway can only be attached to a given router once; attempting to attach a gateway that is already assigned returns a `422` validation error. On success the new assignment is returned with status `201`.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.gateways.attach`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| gateway_id | _**integer (required)**_ The gateway's `internal_id` to attach. Must exist as a gateway for the authenticated team, otherwise a `422` is returned (`The selected gateway does not exist for this account.`). Must not already be assigned to this router. |\n| is_active | _**boolean (optional)**_ Whether the assignment is active. `nullable`. |\n| priority | _**integer (optional)**_ Routing priority; lower values are evaluated first. `nullable`, `min:0`. |\n| weight | _**integer (optional)**_ Weighted-distribution weight. `nullable`, `min:0`. (Stored as decimal(2).) |\n| monthly_cap | _**numeric (optional)**_ Monthly processing cap amount. `nullable`, `min:0`. (Stored as decimal(2).) |\n| supported_currencies | _**array (optional)**_ List of ISO currency codes this assignment is restricted to. `nullable`. |\n| decline_limit | _**integer (optional)**_ Decline threshold before auto-disable. `nullable`, `min:0`. |\n| fail_limit | _**integer (optional)**_ Hard-failure threshold before auto-disable. `nullable`, `min:0`. |\n\nPath parameter `router_id` (_**integer, required**_) is the router's `internal_id`.\n\n## Response\n\nReturns `success: true`, a `message`, and the created assignment under `data` as an `OrchestratorGatewayResource` (same field shape as the list endpoint). `gateway_id` is echoed back as the gateway's `internal_id`.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Missing `api:payment_routers.gateways.attach` (or `api:update`) permission. |\n| 404 | Payment router not found for this account. |\n| 422 | Validation error — invalid field, `gateway_id` does not exist for this account, or the gateway is already assigned to the router. |\n\n## Example\n\n`POST /v1/payment-routers/123/gateways`"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Gateway attached to router successfully\",\n  \"data\": {\n    \"gateway_id\": 7,\n    \"gateway_name\": \"NMI - Primary\",\n    \"is_active\": true,\n    \"priority\": 1,\n    \"weight\": \"60.00\",\n    \"monthly_cap\": \"50000.00\",\n    \"supported_currencies\": [\"USD\", \"CAD\"],\n    \"decline_limit\": 25,\n    \"fail_limit\": 10,\n    \"current_decline_count\": 0,\n    \"current_fail_count\": 0,\n    \"disabled_at\": null,\n    \"last_processed_at\": null,\n    \"created_at\": \"2026-06-16T14:05:22.000000Z\",\n    \"updated_at\": \"2026-06-16T14:05:22.000000Z\"\n  }\n}"}],"_postman_id":"fa9dc5bd-a4a1-92dc-cac6-46e3c9a9d744"},{"name":"Update Router Gateway","id":"4a1f5928-f5d9-06b0-5c28-dc3fbb014093","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"is_active\": false,\n  \"priority\": 3,\n  \"weight\": 25,\n  \"monthly_cap\": 75000,\n  \"supported_currencies\": [\"USD\"],\n  \"decline_limit\": 40,\n  \"fail_limit\": 15\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways/7","description":"<h1 id=\"update-router-gateway\">Update Router Gateway</h1>\n<p><strong>Updates the routing settings of a gateway already assigned to a payment router.</strong></p>\n<p>Partially updates an existing gateway assignment on the router identified by <code>{router_id}</code>. The <code>{gateway_id}</code> path segment is the gateway's <code>internal_id</code>, resolved to the assignment for the authenticated team. All body fields are optional (<code>sometimes</code>) — only the fields you send are updated. The gateway itself cannot be changed here; to swap gateways, detach and attach.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.gateways.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields use <code>sometimes</code>, so only supplied fields are modified.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>is_active</td>\n<td><em><strong>boolean (optional)</strong></em> <code>sometimes</code>. Activate or deactivate the assignment.</td>\n</tr>\n<tr>\n<td>priority</td>\n<td><em><strong>integer (optional)</strong></em> <code>sometimes</code>, <code>nullable</code>, <code>min:0</code>. Routing priority (lower first).</td>\n</tr>\n<tr>\n<td>weight</td>\n<td><em><strong>integer (optional)</strong></em> <code>sometimes</code>, <code>nullable</code>, <code>min:0</code>. Weighted-distribution weight. (Stored as decimal(2).)</td>\n</tr>\n<tr>\n<td>monthly_cap</td>\n<td><em><strong>numeric (optional)</strong></em> <code>sometimes</code>, <code>nullable</code>, <code>min:0</code>. Monthly processing cap amount. (Stored as decimal(2).)</td>\n</tr>\n<tr>\n<td>supported_currencies</td>\n<td><em><strong>array (optional)</strong></em> <code>sometimes</code>, <code>nullable</code>. List of ISO currency codes to restrict to.</td>\n</tr>\n<tr>\n<td>decline_limit</td>\n<td><em><strong>integer (optional)</strong></em> <code>sometimes</code>, <code>nullable</code>, <code>min:0</code>. Decline threshold before auto-disable.</td>\n</tr>\n<tr>\n<td>fail_limit</td>\n<td><em><strong>integer (optional)</strong></em> <code>sometimes</code>, <code>nullable</code>, <code>min:0</code>. Hard-failure threshold before auto-disable.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Path parameters: <code>router_id</code> (<em><strong>integer, required</strong></em>) — router <code>internal_id</code>; <code>gateway_id</code> (<em><strong>integer, required</strong></em>) — gateway <code>internal_id</code>.</p>\n<h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code>, a <code>message</code>, and the refreshed assignment under <code>data</code> as an <code>OrchestratorGatewayResource</code> (same field shape as the list endpoint).</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Missing <code>api:payment_routers.gateways.update</code> (or <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found, or the gateway is not assigned to this router.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation error on one of the supplied fields.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>PATCH /v1/payment-routers/123/gateways/7</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","gateways","7"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"145c086f-34cd-df5c-255a-bb5c2fc43c62","name":"Update Router Gateway","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"is_active\": false,\n  \"priority\": 3,\n  \"weight\": 25,\n  \"monthly_cap\": 75000,\n  \"supported_currencies\": [\"USD\"],\n  \"decline_limit\": 40,\n  \"fail_limit\": 15\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways/7","description":"# Update Router Gateway\n\n**Updates the routing settings of a gateway already assigned to a payment router.**\n\nPartially updates an existing gateway assignment on the router identified by `{router_id}`. The `{gateway_id}` path segment is the gateway's `internal_id`, resolved to the assignment for the authenticated team. All body fields are optional (`sometimes`) — only the fields you send are updated. The gateway itself cannot be changed here; to swap gateways, detach and attach.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.gateways.update`\n\n## Request Body\n\nAll fields use `sometimes`, so only supplied fields are modified.\n\n| Request Field | Description |\n| --- | --- |\n| is_active | _**boolean (optional)**_ `sometimes`. Activate or deactivate the assignment. |\n| priority | _**integer (optional)**_ `sometimes`, `nullable`, `min:0`. Routing priority (lower first). |\n| weight | _**integer (optional)**_ `sometimes`, `nullable`, `min:0`. Weighted-distribution weight. (Stored as decimal(2).) |\n| monthly_cap | _**numeric (optional)**_ `sometimes`, `nullable`, `min:0`. Monthly processing cap amount. (Stored as decimal(2).) |\n| supported_currencies | _**array (optional)**_ `sometimes`, `nullable`. List of ISO currency codes to restrict to. |\n| decline_limit | _**integer (optional)**_ `sometimes`, `nullable`, `min:0`. Decline threshold before auto-disable. |\n| fail_limit | _**integer (optional)**_ `sometimes`, `nullable`, `min:0`. Hard-failure threshold before auto-disable. |\n\nPath parameters: `router_id` (_**integer, required**_) — router `internal_id`; `gateway_id` (_**integer, required**_) — gateway `internal_id`.\n\n## Response\n\nReturns `success: true`, a `message`, and the refreshed assignment under `data` as an `OrchestratorGatewayResource` (same field shape as the list endpoint).\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Missing `api:payment_routers.gateways.update` (or `api:update`) permission. |\n| 404 | Payment router not found, or the gateway is not assigned to this router. |\n| 422 | Validation error on one of the supplied fields. |\n\n## Example\n\n`PATCH /v1/payment-routers/123/gateways/7`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Gateway assignment updated successfully\",\n  \"data\": {\n    \"gateway_id\": 7,\n    \"gateway_name\": \"NMI - Primary\",\n    \"is_active\": false,\n    \"priority\": 3,\n    \"weight\": \"25.00\",\n    \"monthly_cap\": \"75000.00\",\n    \"supported_currencies\": [\"USD\"],\n    \"decline_limit\": 40,\n    \"fail_limit\": 15,\n    \"current_decline_count\": 3,\n    \"current_fail_count\": 0,\n    \"disabled_at\": null,\n    \"last_processed_at\": \"2026-06-15T18:42:11.000000Z\",\n    \"created_at\": \"2026-05-01T12:00:00.000000Z\",\n    \"updated_at\": \"2026-06-16T14:10:48.000000Z\"\n  }\n}"}],"_postman_id":"4a1f5928-f5d9-06b0-5c28-dc3fbb014093"},{"name":"Remove Router Gateway","id":"c8a08d5e-6fbc-3500-849a-822fe455cf5b","request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways/7","description":"<h1 id=\"remove-router-gateway\">Remove Router Gateway</h1>\n<p><strong>Detaches a gateway from a payment router.</strong></p>\n<p>Removes the gateway assignment identified by <code>{gateway_id}</code> (the gateway's <code>internal_id</code>) from the router identified by <code>{router_id}</code>, for the authenticated team. The gateway record itself is not deleted — only its link to this router. Returns a simple success message; no resource body is included.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.gateways.detach</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>router_id</td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The payment router's <code>internal_id</code>. Must match <code>[0-9]+</code>.</td>\n</tr>\n<tr>\n<td>gateway_id</td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The assigned gateway's <code>internal_id</code>. Must match <code>[0-9]+</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code> and a confirmation <code>message</code>. No <code>data</code> payload is returned.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Missing <code>api:payment_routers.gateways.detach</code> (or <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found, or the gateway is not assigned to this router.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>DELETE /v1/payment-routers/123/gateways/7</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","gateways","7"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"c1405337-a5ac-564a-858a-345d3d41fbc1","name":"Remove Router Gateway","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/gateways/7","description":"# Remove Router Gateway\n\n**Detaches a gateway from a payment router.**\n\nRemoves the gateway assignment identified by `{gateway_id}` (the gateway's `internal_id`) from the router identified by `{router_id}`, for the authenticated team. The gateway record itself is not deleted — only its link to this router. Returns a simple success message; no resource body is included.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.gateways.detach`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| router_id | _**integer (required)**_ Path parameter. The payment router's `internal_id`. Must match `[0-9]+`. |\n| gateway_id | _**integer (required)**_ Path parameter. The assigned gateway's `internal_id`. Must match `[0-9]+`. |\n\n## Response\n\nReturns `success: true` and a confirmation `message`. No `data` payload is returned.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Missing `api:payment_routers.gateways.detach` (or `api:update`) permission. |\n| 404 | Payment router not found, or the gateway is not assigned to this router. |\n\n## Example\n\n`DELETE /v1/payment-routers/123/gateways/7`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Gateway detached from router successfully\"\n}"}],"_postman_id":"c8a08d5e-6fbc-3500-849a-822fe455cf5b"}],"id":"ff40c026-0bcd-a2f5-7ea5-bc1fd8bb893a","_postman_id":"ff40c026-0bcd-a2f5-7ea5-bc1fd8bb893a","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Rules","item":[{"name":"List Routing Rules","id":"c74153ac-4039-193a-1a50-28835a1c2cd6","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules","description":"<h1 id=\"list-routing-rules\">List Routing Rules</h1>\n<p><strong>Retrieve every routing rule configured for a payment router.</strong></p>\n<p>Returns all routing rules belonging to the specified payment router, ordered ascending by <code>priority</code>. Each rule includes its match <code>conditions</code> and the <code>target_gateway_id</code> (the gateway's <code>internal_id</code>) that traffic is routed to when the conditions match. The payment router is resolved by its <code>internal_id</code> (the <code>{router_id}</code> path segment) and is scoped to the authenticated team.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.rules.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>router_id</td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The payment router's <code>internal_id</code>. Must match <code>[0-9]+</code>. Resolved within the authenticated team; a router that does not belong to the team returns <code>404 Payment router not found</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><p>This endpoint takes no query parameters and is not paginated; the full ordered collection is returned.</p>\n<h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and a <code>data</code> array. Each element is a routing rule object:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>id</td>\n<td>The rule's <code>internal_id</code>.</td>\n</tr>\n<tr>\n<td>name</td>\n<td>The rule name.</td>\n</tr>\n<tr>\n<td>priority</td>\n<td>Integer priority used to order rules (lower runs first). May be <code>null</code>.</td>\n</tr>\n<tr>\n<td>conditions</td>\n<td>Array of condition objects, each <code>{ field, operator, value }</code>.</td>\n</tr>\n<tr>\n<td>target_gateway_id</td>\n<td>The target gateway's <code>internal_id</code> (only present when the rule has a target gateway and it is loaded).</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td>Boolean. Whether the rule is active.</td>\n</tr>\n<tr>\n<td>created_at</td>\n<td>ISO 8601 timestamp.</td>\n</tr>\n<tr>\n<td>updated_at</td>\n<td>ISO 8601 timestamp.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:payment_routers.rules.view</code> (or legacy <code>api:view_any</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found for this account.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET /v1/payment-routers/123/rules</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","rules"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"62cbebde-cd30-2091-2c1a-22888bb640fd","name":"List Routing Rules","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules","description":"# List Routing Rules\n\n**Retrieve every routing rule configured for a payment router.**\n\nReturns all routing rules belonging to the specified payment router, ordered ascending by `priority`. Each rule includes its match `conditions` and the `target_gateway_id` (the gateway's `internal_id`) that traffic is routed to when the conditions match. The payment router is resolved by its `internal_id` (the `{router_id}` path segment) and is scoped to the authenticated team.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.rules.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| router_id | _**integer (required)**_ Path parameter. The payment router's `internal_id`. Must match `[0-9]+`. Resolved within the authenticated team; a router that does not belong to the team returns `404 Payment router not found`. |\n\nThis endpoint takes no query parameters and is not paginated; the full ordered collection is returned.\n\n## Response Object\n\nReturns `success: true` and a `data` array. Each element is a routing rule object:\n\n| Field | Description |\n| --- | --- |\n| id | The rule's `internal_id`. |\n| name | The rule name. |\n| priority | Integer priority used to order rules (lower runs first). May be `null`. |\n| conditions | Array of condition objects, each `{ field, operator, value }`. |\n| target_gateway_id | The target gateway's `internal_id` (only present when the rule has a target gateway and it is loaded). |\n| is_active | Boolean. Whether the rule is active. |\n| created_at | ISO 8601 timestamp. |\n| updated_at | ISO 8601 timestamp. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:payment_routers.rules.view` (or legacy `api:view_any`) permission. |\n| 404 | Payment router not found for this account. |\n\n## Example\n\n`GET /v1/payment-routers/123/rules`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"High value orders to primary gateway\",\n      \"priority\": 0,\n      \"conditions\": [\n        { \"field\": \"amount\", \"operator\": \">=\", \"value\": \"100\" },\n        { \"field\": \"currency\", \"operator\": \"=\", \"value\": \"USD\" }\n      ],\n      \"target_gateway_id\": 45,\n      \"is_active\": true,\n      \"created_at\": \"2026-06-01T14:23:11.000000Z\",\n      \"updated_at\": \"2026-06-10T09:02:44.000000Z\"\n    },\n    {\n      \"id\": 2,\n      \"name\": \"EU traffic\",\n      \"priority\": 10,\n      \"conditions\": [\n        { \"field\": \"country\", \"operator\": \"in\", \"value\": \"DE,FR,ES\" }\n      ],\n      \"target_gateway_id\": 52,\n      \"is_active\": false,\n      \"created_at\": \"2026-06-02T08:11:00.000000Z\",\n      \"updated_at\": \"2026-06-02T08:11:00.000000Z\"\n    }\n  ]\n}"}],"_postman_id":"c74153ac-4039-193a-1a50-28835a1c2cd6"},{"name":"Create Routing Rule","id":"8044e714-7ebc-ada1-3097-84ba32f59958","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"High value orders to primary gateway\",\n  \"priority\": 0,\n  \"conditions\": [\n    { \"field\": \"amount\", \"operator\": \">=\", \"value\": \"100\" },\n    { \"field\": \"currency\", \"operator\": \"=\", \"value\": \"USD\" }\n  ],\n  \"target_gateway_id\": 45,\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules","description":"<h1 id=\"create-routing-rule\">Create Routing Rule</h1>\n<p><strong>Add a new routing rule to a payment router.</strong></p>\n<p>Creates a routing rule under the payment router identified by the <code>{router_id}</code> path segment (the router's <code>internal_id</code>, scoped to the authenticated team). A rule consists of a set of <code>conditions</code> that are all matched (AND logic) against an incoming transaction, and a <code>target_gateway_id</code> that traffic is routed to when every condition matches.</p>\n<p>The <code>target_gateway_id</code> you send is the gateway's <code>internal_id</code>; it is resolved to a gateway owned by the authenticated team. If no such gateway exists for the account, a <code>422</code> validation error is returned.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.rules.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>name</td>\n<td><em><strong>string (required)</strong></em> Rule name. Max 255 characters.</td>\n</tr>\n<tr>\n<td>priority</td>\n<td><em><strong>integer (optional)</strong></em> Nullable. Minimum <code>0</code>. Lower values are evaluated first when ordering rules.</td>\n</tr>\n<tr>\n<td>conditions</td>\n<td><em><strong>array (required)</strong></em> At least 1 element (<code>min:1</code>). Each element is a condition object (see below). All conditions must match (AND logic).</td>\n</tr>\n<tr>\n<td>conditions[].field</td>\n<td><em><strong>string (required)</strong></em> The transaction field to evaluate (e.g. <code>amount</code>, <code>currency</code>, <code>country</code>). Max 255 characters.</td>\n</tr>\n<tr>\n<td>conditions[].operator</td>\n<td><em><strong>string (required)</strong></em> Comparison operator. Allowed values: <code>=</code>, <code>!=</code>, <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code>, <code>in</code>, <code>starts_with</code>, <code>between</code>. For <code>in</code> the value is a comma-separated list; for <code>between</code> the value is two comma-separated bounds (<code>min,max</code>).</td>\n</tr>\n<tr>\n<td>conditions[].value</td>\n<td><em><strong>mixed (required)</strong></em> Must be present (<code>present</code>); may be a string, number, or empty string. Compared against the field value using the operator.</td>\n</tr>\n<tr>\n<td>target_gateway_id</td>\n<td><em><strong>integer (optional)</strong></em> Nullable. The target gateway's <code>internal_id</code>. Must belong to the authenticated team or a <code>422</code> is returned.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><em><strong>boolean (optional)</strong></em> Nullable. Whether the rule is active. Defaults to the model/database default when omitted.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>On success returns <code>201</code> with <code>success: true</code>, a <code>message</code>, and the created rule under <code>data</code> using the routing rule object shape (see List Routing Rules → Response Object). <code>target_gateway_id</code> in the response is the gateway's <code>internal_id</code>.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:payment_routers.rules.create</code> (or legacy <code>api:create</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found for this account.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation error (missing/invalid <code>name</code>, empty <code>conditions</code>, invalid <code>operator</code>, missing <code>conditions[].value</code>, or <code>target_gateway_id</code> does not exist for this account).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>POST /v1/payment-routers/123/rules</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","rules"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"8f28b33f-6b37-6e42-a492-5701a20aa2e8","name":"Create Routing Rule","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"High value orders to primary gateway\",\n  \"priority\": 0,\n  \"conditions\": [\n    { \"field\": \"amount\", \"operator\": \">=\", \"value\": \"100\" },\n    { \"field\": \"currency\", \"operator\": \"=\", \"value\": \"USD\" }\n  ],\n  \"target_gateway_id\": 45,\n  \"is_active\": true\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules","description":"# Create Routing Rule\n\n**Add a new routing rule to a payment router.**\n\nCreates a routing rule under the payment router identified by the `{router_id}` path segment (the router's `internal_id`, scoped to the authenticated team). A rule consists of a set of `conditions` that are all matched (AND logic) against an incoming transaction, and a `target_gateway_id` that traffic is routed to when every condition matches.\n\nThe `target_gateway_id` you send is the gateway's `internal_id`; it is resolved to a gateway owned by the authenticated team. If no such gateway exists for the account, a `422` validation error is returned.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.rules.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| name | _**string (required)**_ Rule name. Max 255 characters. |\n| priority | _**integer (optional)**_ Nullable. Minimum `0`. Lower values are evaluated first when ordering rules. |\n| conditions | _**array (required)**_ At least 1 element (`min:1`). Each element is a condition object (see below). All conditions must match (AND logic). |\n| conditions[].field | _**string (required)**_ The transaction field to evaluate (e.g. `amount`, `currency`, `country`). Max 255 characters. |\n| conditions[].operator | _**string (required)**_ Comparison operator. Allowed values: `=`, `!=`, `>`, `<`, `>=`, `<=`, `in`, `starts_with`, `between`. For `in` the value is a comma-separated list; for `between` the value is two comma-separated bounds (`min,max`). |\n| conditions[].value | _**mixed (required)**_ Must be present (`present`); may be a string, number, or empty string. Compared against the field value using the operator. |\n| target_gateway_id | _**integer (optional)**_ Nullable. The target gateway's `internal_id`. Must belong to the authenticated team or a `422` is returned. |\n| is_active | _**boolean (optional)**_ Nullable. Whether the rule is active. Defaults to the model/database default when omitted. |\n\n## Response\n\nOn success returns `201` with `success: true`, a `message`, and the created rule under `data` using the routing rule object shape (see List Routing Rules → Response Object). `target_gateway_id` in the response is the gateway's `internal_id`.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:payment_routers.rules.create` (or legacy `api:create`) permission. |\n| 404 | Payment router not found for this account. |\n| 422 | Validation error (missing/invalid `name`, empty `conditions`, invalid `operator`, missing `conditions[].value`, or `target_gateway_id` does not exist for this account). |\n\n## Example\n\n`POST /v1/payment-routers/123/rules`"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Routing rule created successfully\",\n  \"data\": {\n    \"id\": 7,\n    \"name\": \"High value orders to primary gateway\",\n    \"priority\": 0,\n    \"conditions\": [\n      { \"field\": \"amount\", \"operator\": \">=\", \"value\": \"100\" },\n      { \"field\": \"currency\", \"operator\": \"=\", \"value\": \"USD\" }\n    ],\n    \"target_gateway_id\": 45,\n    \"is_active\": true,\n    \"created_at\": \"2026-06-16T17:45:02.000000Z\",\n    \"updated_at\": \"2026-06-16T17:45:02.000000Z\"\n  }\n}"}],"_postman_id":"8044e714-7ebc-ada1-3097-84ba32f59958"},{"name":"Update Routing Rule","id":"592acd32-7c0e-e044-1d53-7741f315ec9f","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"High value orders (updated)\",\n  \"priority\": 5,\n  \"conditions\": [\n    { \"field\": \"amount\", \"operator\": \"between\", \"value\": \"100,500\" }\n  ],\n  \"target_gateway_id\": 52,\n  \"is_active\": false\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules/7","description":"<h1 id=\"update-routing-rule\">Update Routing Rule</h1>\n<p><strong>Modify an existing routing rule on a payment router.</strong></p>\n<p>Updates the routing rule identified by <code>{rule_id}</code> (the rule's <code>internal_id</code>) within the payment router identified by <code>{router_id}</code> (the router's <code>internal_id</code>). Both are scoped to the authenticated team. All fields are optional on update (<code>sometimes</code>) — only the fields you send are validated and applied. When <code>conditions</code> is supplied it fully replaces the existing conditions array.</p>\n<p>When <code>target_gateway_id</code> is supplied, it is treated as the gateway's <code>internal_id</code> and resolved to a gateway owned by the authenticated team; an unknown value returns a <code>422</code>.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.rules.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional (<code>sometimes</code>). When present they must satisfy the rules below.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>name</td>\n<td><em><strong>string (optional)</strong></em> When present, required and non-empty. Max 255 characters.</td>\n</tr>\n<tr>\n<td>priority</td>\n<td><em><strong>integer (optional)</strong></em> Nullable. Minimum <code>0</code>.</td>\n</tr>\n<tr>\n<td>conditions</td>\n<td><em><strong>array (optional)</strong></em> When present, required with at least 1 element (<code>min:1</code>). Replaces the rule's existing conditions. Each element is <code>{ field, operator, value }</code>.</td>\n</tr>\n<tr>\n<td>conditions[].field</td>\n<td><em><strong>string (required within each condition)</strong></em> Max 255 characters.</td>\n</tr>\n<tr>\n<td>conditions[].operator</td>\n<td><em><strong>string (required within each condition)</strong></em> One of: <code>=</code>, <code>!=</code>, <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code>, <code>in</code>, <code>starts_with</code>, <code>between</code>.</td>\n</tr>\n<tr>\n<td>conditions[].value</td>\n<td><em><strong>mixed (required within each condition)</strong></em> Must be present (<code>present</code>).</td>\n</tr>\n<tr>\n<td>target_gateway_id</td>\n<td><em><strong>integer (optional)</strong></em> Nullable. The target gateway's <code>internal_id</code>. Must belong to the authenticated team or a <code>422</code> is returned.</td>\n</tr>\n<tr>\n<td>is_active</td>\n<td><em><strong>boolean (optional)</strong></em> When present, must be a boolean.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>On success returns <code>200</code> with <code>success: true</code>, a <code>message</code>, and the updated rule under <code>data</code> using the routing rule object shape (see List Routing Rules → Response Object).</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:payment_routers.rules.update</code> (or legacy <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found, or routing rule not found within that router.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation error (invalid <code>operator</code>, empty <code>conditions</code>, missing <code>conditions[].value</code>, or <code>target_gateway_id</code> does not exist for this account).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>PATCH /v1/payment-routers/123/rules/7</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","rules","7"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"5faea674-7685-9616-7269-e7aa999422a0","name":"Update Routing Rule","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"High value orders (updated)\",\n  \"priority\": 5,\n  \"conditions\": [\n    { \"field\": \"amount\", \"operator\": \"between\", \"value\": \"100,500\" }\n  ],\n  \"target_gateway_id\": 52,\n  \"is_active\": false\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules/7","description":"# Update Routing Rule\n\n**Modify an existing routing rule on a payment router.**\n\nUpdates the routing rule identified by `{rule_id}` (the rule's `internal_id`) within the payment router identified by `{router_id}` (the router's `internal_id`). Both are scoped to the authenticated team. All fields are optional on update (`sometimes`) — only the fields you send are validated and applied. When `conditions` is supplied it fully replaces the existing conditions array.\n\nWhen `target_gateway_id` is supplied, it is treated as the gateway's `internal_id` and resolved to a gateway owned by the authenticated team; an unknown value returns a `422`.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.rules.update`\n\n## Request Body\n\nAll fields are optional (`sometimes`). When present they must satisfy the rules below.\n\n| Request Field | Description |\n| --- | --- |\n| name | _**string (optional)**_ When present, required and non-empty. Max 255 characters. |\n| priority | _**integer (optional)**_ Nullable. Minimum `0`. |\n| conditions | _**array (optional)**_ When present, required with at least 1 element (`min:1`). Replaces the rule's existing conditions. Each element is `{ field, operator, value }`. |\n| conditions[].field | _**string (required within each condition)**_ Max 255 characters. |\n| conditions[].operator | _**string (required within each condition)**_ One of: `=`, `!=`, `>`, `<`, `>=`, `<=`, `in`, `starts_with`, `between`. |\n| conditions[].value | _**mixed (required within each condition)**_ Must be present (`present`). |\n| target_gateway_id | _**integer (optional)**_ Nullable. The target gateway's `internal_id`. Must belong to the authenticated team or a `422` is returned. |\n| is_active | _**boolean (optional)**_ When present, must be a boolean. |\n\n## Response\n\nOn success returns `200` with `success: true`, a `message`, and the updated rule under `data` using the routing rule object shape (see List Routing Rules → Response Object).\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:payment_routers.rules.update` (or legacy `api:update`) permission. |\n| 404 | Payment router not found, or routing rule not found within that router. |\n| 422 | Validation error (invalid `operator`, empty `conditions`, missing `conditions[].value`, or `target_gateway_id` does not exist for this account). |\n\n## Example\n\n`PATCH /v1/payment-routers/123/rules/7`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Routing rule updated successfully\",\n  \"data\": {\n    \"id\": 7,\n    \"name\": \"High value orders (updated)\",\n    \"priority\": 5,\n    \"conditions\": [\n      { \"field\": \"amount\", \"operator\": \"between\", \"value\": \"100,500\" }\n    ],\n    \"target_gateway_id\": 52,\n    \"is_active\": false,\n    \"created_at\": \"2026-06-16T17:45:02.000000Z\",\n    \"updated_at\": \"2026-06-16T18:10:30.000000Z\"\n  }\n}"}],"_postman_id":"592acd32-7c0e-e044-1d53-7741f315ec9f"},{"name":"Delete Routing Rule","id":"04b01007-507f-ec29-9527-0c16dc4f887d","request":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules/7","description":"<h1 id=\"delete-routing-rule\">Delete Routing Rule</h1>\n<p><strong>Permanently remove a routing rule from a payment router.</strong></p>\n<p>Deletes the routing rule identified by <code>{rule_id}</code> (the rule's <code>internal_id</code>) within the payment router identified by <code>{router_id}</code> (the router's <code>internal_id</code>). Both are scoped to the authenticated team. Returns a confirmation message on success.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.rules.delete</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>router_id</td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The payment router's <code>internal_id</code>. Must match <code>[0-9]+</code>.</td>\n</tr>\n<tr>\n<td>rule_id</td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The routing rule's <code>internal_id</code>. Must match <code>[0-9]+</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>200</code> with <code>success: true</code> and a confirmation <code>message</code>. No rule object is returned.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>403</td>\n<td>Token lacks the <code>api:payment_routers.rules.delete</code> (or legacy <code>api:delete</code>) permission.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Payment router not found, or routing rule not found within that router.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>DELETE /v1/payment-routers/123/rules/7</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","123","rules","7"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"f69992e9-5381-9a94-7a2d-0231bfab329f","name":"Delete Routing Rule","originalRequest":{"method":"DELETE","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/123/rules/7","description":"# Delete Routing Rule\n\n**Permanently remove a routing rule from a payment router.**\n\nDeletes the routing rule identified by `{rule_id}` (the rule's `internal_id`) within the payment router identified by `{router_id}` (the router's `internal_id`). Both are scoped to the authenticated team. Returns a confirmation message on success.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.rules.delete`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| router_id | _**integer (required)**_ Path parameter. The payment router's `internal_id`. Must match `[0-9]+`. |\n| rule_id | _**integer (required)**_ Path parameter. The routing rule's `internal_id`. Must match `[0-9]+`. |\n\n## Response\n\nReturns `200` with `success: true` and a confirmation `message`. No rule object is returned.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| 403 | Token lacks the `api:payment_routers.rules.delete` (or legacy `api:delete`) permission. |\n| 404 | Payment router not found, or routing rule not found within that router. |\n\n## Example\n\n`DELETE /v1/payment-routers/123/rules/7`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Routing rule deleted successfully\"\n}"}],"_postman_id":"04b01007-507f-ec29-9527-0c16dc4f887d"}],"id":"e97ae047-ef84-a0b6-ee42-45b451a3d091","_postman_id":"e97ae047-ef84-a0b6-ee42-45b451a3d091","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"List Payment Routers","id":"e3af2b85-b378-3815-ed44-8506e4419af4","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers?is_active=true&per_page=15&page=1","description":"<h1 id=\"list-payment-routers\">List Payment Routers</h1>\n<p><strong>List &amp; Search for Payment Routers</strong></p>\n<p>Retrieve a paginated list of payment routers (orchestrators) available to the authenticated account. Supports free-text search and filtering by active status. Results are ordered by creation date (newest first).</p>\n<h2 id=\"example--search-for-active-payment-routers\">Example — Search for Active Payment Routers</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/payment-routers?is_active=true\n</code></pre><p>Returns a paginated list of all payment routers currently active for the authenticated team. Combine with <code>per_page</code>, <code>page</code>, or <code>search</code> to narrow results.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.view_any</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>search</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Search across router name and internal id. When the value is all digits it is matched against <code>internal_id</code>; otherwise it is matched against <code>name</code>. Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Filter by active status. Accepts <code>true</code>/<code>false</code>, <code>1</code>/<code>0</code>.</td>\n</tr>\n<tr>\n<td><strong>per_page</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Number of results per page. Minimum: 1, Maximum: 100. Default: 15</td>\n</tr>\n<tr>\n<td><strong>page</strong></td>\n<td><em><strong>integer (optional)</strong></em>  <br />Page number to retrieve when results span multiple pages. Used together with per_page. Minimum: 1. Default: 1</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>List responses return the summary representation of each router (the detailed <code>email_tokens</code>, <code>bin_configurations</code>, and <code>mcc_configurations</code> arrays are only returned by the detail, create, and update endpoints).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>array</strong>  <br />Array of payment router objects matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Payment router identifier (team's internal id)</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Payment router display name</td>\n</tr>\n<tr>\n<td><strong>data.algorithm_type</strong></td>\n<td><strong>string/null</strong>  <br />Routing algorithm. One of <code>highest_approval_rate</code>, <code>round_robin</code>, <code>ruleset_only</code></td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the router is active</td>\n</tr>\n<tr>\n<td><strong>data.failover_enabled</strong></td>\n<td><strong>boolean</strong>  <br />Whether failover to backup gateways is enabled</td>\n</tr>\n<tr>\n<td><strong>data.use_weighted_routing</strong></td>\n<td><strong>boolean</strong>  <br />Whether weighted (percentage-based) routing across gateways is used</td>\n</tr>\n<tr>\n<td><strong>data.monthly_processing_limit</strong></td>\n<td><strong>string/null</strong>  <br />Monthly processing limit in dollars, formatted to 2 decimal places (e.g. <code>\"1000000.00\"</code>). <code>null</code> when no limit is set</td>\n</tr>\n<tr>\n<td><strong>data.subscription_routing_strategy</strong></td>\n<td><strong>string/null</strong>  <br />Strategy used to route subscription rebills</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the router was created</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the router was last updated</td>\n</tr>\n<tr>\n<td><strong>pagination</strong></td>\n<td><strong>object</strong>  <br />Contains pagination information for the response</td>\n</tr>\n<tr>\n<td><strong>pagination.total</strong></td>\n<td><strong>integer</strong>  <br />Total number of routers matching the search criteria</td>\n</tr>\n<tr>\n<td><strong>pagination.per_page</strong></td>\n<td><strong>integer</strong>  <br />Number of routers displayed per page</td>\n</tr>\n<tr>\n<td><strong>pagination.current_page</strong></td>\n<td><strong>integer</strong>  <br />Current page number</td>\n</tr>\n<tr>\n<td><strong>pagination.last_page</strong></td>\n<td><strong>integer</strong>  <br />Total number of pages available</td>\n</tr>\n<tr>\n<td><strong>pagination.from</strong></td>\n<td><strong>integer/null</strong>  <br />Starting record number for the current page</td>\n</tr>\n<tr>\n<td><strong>pagination.to</strong></td>\n<td><strong>integer/null</strong>  <br />Ending record number for the current page</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Missing required permission</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers"],"host":["api","sparkcrm","io"],"query":[{"disabled":true,"description":{"content":"<p>Search across router name and internal id. When the value is all digits it is matched against internal_id; otherwise it is matched against name. Maximum 255 characters.</p>\n","type":"text/plain"},"key":"search","value":""},{"disabled":true,"description":{"content":"<p>Filter by active status. Boolean (true/false, 1/0).</p>\n","type":"text/plain"},"key":"is_active","value":"true"},{"description":{"content":"<p>Number of results per page. Minimum: 1, Maximum: 100. Default: 15</p>\n","type":"text/plain"},"key":"per_page","value":"15"},{"disabled":true,"description":{"content":"<p>Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"47f71f13-b263-b23a-07be-9d22e171ced8","name":"List Payment Routers","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/payment-routers?is_active=true&per_page=15&page=1","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","payment-routers"],"query":[{"description":"Search across router name and internal id. When the value is all digits it is matched against internal_id; otherwise it is matched against name. Maximum 255 characters.","key":"search","value":"","disabled":true},{"description":"Filter by active status. Boolean (true/false, 1/0).","key":"is_active","value":"true","disabled":true},{"description":"Number of results per page. Minimum: 1, Maximum: 100. Default: 15","key":"per_page","value":"15"},{"description":"Page number to retrieve when results span multiple pages. Used together with per_page. Default: 1","key":"page","value":"1","disabled":true}]},"description":"# List Payment Routers\n\n**List & Search for Payment Routers**\n\nRetrieve a paginated list of payment routers (orchestrators) available to the authenticated account. Supports free-text search and filtering by active status. Results are ordered by creation date (newest first).\n\n## Example — Search for Active Payment Routers\n\n```\nGET https://api.sparkcrm.io/v1/payment-routers?is_active=true\n```\n\nReturns a paginated list of all payment routers currently active for the authenticated team. Combine with `per_page`, `page`, or `search` to narrow results.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.view_any`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| **search** | _**string (optional)**_  <br>Search across router name and internal id. When the value is all digits it is matched against `internal_id`; otherwise it is matched against `name`. Maximum 255 characters. |\n| **is_active** | _**boolean (optional)**_  <br>Filter by active status. Accepts `true`/`false`, `1`/`0`. |\n| **per_page** | _**integer (optional)**_  <br>Number of results per page. Minimum: 1, Maximum: 100. Default: 15 |\n| **page** | _**integer (optional)**_  <br>Page number to retrieve when results span multiple pages. Used together with per_page. Minimum: 1. Default: 1 |\n\n## Response Object\n\nList responses return the summary representation of each router (the detailed `email_tokens`, `bin_configurations`, and `mcc_configurations` arrays are only returned by the detail, create, and update endpoints).\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **data** | **array**  <br>Array of payment router objects matching the search criteria |\n| **data.id** | **integer**  <br>Payment router identifier (team's internal id) |\n| **data.name** | **string**  <br>Payment router display name |\n| **data.algorithm_type** | **string/null**  <br>Routing algorithm. One of `highest_approval_rate`, `round_robin`, `ruleset_only` |\n| **data.is_active** | **boolean**  <br>Whether the router is active |\n| **data.failover_enabled** | **boolean**  <br>Whether failover to backup gateways is enabled |\n| **data.use_weighted_routing** | **boolean**  <br>Whether weighted (percentage-based) routing across gateways is used |\n| **data.monthly_processing_limit** | **string/null**  <br>Monthly processing limit in dollars, formatted to 2 decimal places (e.g. `\"1000000.00\"`). `null` when no limit is set |\n| **data.subscription_routing_strategy** | **string/null**  <br>Strategy used to route subscription rebills |\n| **data.created_at** | **string**  <br>ISO 8601 timestamp when the router was created |\n| **data.updated_at** | **string**  <br>ISO 8601 timestamp when the router was last updated |\n| **pagination** | **object**  <br>Contains pagination information for the response |\n| **pagination.total** | **integer**  <br>Total number of routers matching the search criteria |\n| **pagination.per_page** | **integer**  <br>Number of routers displayed per page |\n| **pagination.current_page** | **integer**  <br>Current page number |\n| **pagination.last_page** | **integer**  <br>Total number of pages available |\n| **pagination.from** | **integer/null**  <br>Starting record number for the current page |\n| **pagination.to** | **integer/null**  <br>Ending record number for the current page |\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Missing required permission |\n| **422** | Validation error (returns `errors` object with field-level messages) |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 12,\n      \"name\": \"Primary Smart Router\",\n      \"algorithm_type\": \"highest_approval_rate\",\n      \"is_active\": true,\n      \"failover_enabled\": true,\n      \"use_weighted_routing\": false,\n      \"monthly_processing_limit\": \"1000000.00\",\n      \"subscription_routing_strategy\": \"sticky_initial_mid\",\n      \"created_at\": \"2026-05-21T14:08:22.000000Z\",\n      \"updated_at\": \"2026-06-10T09:31:54.000000Z\"\n    },\n    {\n      \"id\": 11,\n      \"name\": \"Round Robin Backup\",\n      \"algorithm_type\": \"round_robin\",\n      \"is_active\": false,\n      \"failover_enabled\": false,\n      \"use_weighted_routing\": true,\n      \"monthly_processing_limit\": null,\n      \"subscription_routing_strategy\": null,\n      \"created_at\": \"2026-04-30T18:45:01.000000Z\",\n      \"updated_at\": \"2026-05-02T11:12:09.000000Z\"\n    }\n  ],\n  \"pagination\": {\n    \"total\": 2,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 2\n  }\n}"}],"_postman_id":"e3af2b85-b378-3815-ed44-8506e4419af4"},{"name":"Create Payment Router","id":"1d857f0e-bcd7-7733-f495-aee4ea60037b","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Primary Smart Router\",\n  \"algorithm_type\": \"highest_approval_rate\",\n  \"monthly_processing_limit\": 1000000,\n  \"failover_enabled\": true,\n  \"is_active\": true,\n  \"use_weighted_routing\": false,\n  \"subscription_routing_strategy\": \"sticky_initial_mid\",\n  \"email_tokens\": [\n    \"@gmail.com\",\n    \"@outlook.com\"\n  ],\n  \"bin_configurations\": [\n    {\n      \"bin\": \"414720\",\n      \"gateway_internal_id\": 3,\n      \"action\": \"route\"\n    }\n  ],\n  \"mcc_configurations\": [\n    {\n      \"mcc\": \"5815\",\n      \"gateway_internal_id\": 3\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers","description":"<h1 id=\"create-payment-router\">Create Payment Router</h1>\n<p><strong>Create a New Payment Router</strong></p>\n<p>Create a new payment router (orchestrator) for the authenticated account. A payment router decides which gateway a transaction is sent to based on its routing algorithm, weighting, failover, and any BIN / MCC / email-token overrides. Returns the detailed router object on success.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (required)</strong></em>  <br />Router name. Must be unique within the team (soft-deleted routers are ignored). Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>algorithm_type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Routing algorithm used to select a gateway. Options: <code>highest_approval_rate</code> (routes to the gateway with the highest likelihood of approval based on recent and historical data), <code>round_robin</code> (evenly distributes transactions across eligible gateways), <code>ruleset_only</code> (only routes using custom rules and fails if no rule matches).</td>\n</tr>\n<tr>\n<td><strong>monthly_processing_limit</strong></td>\n<td><em><strong>number (optional, nullable)</strong></em>  <br />Total monthly processing limit in dollars across the router. Minimum 0. Stored with 2-decimal precision.</td>\n</tr>\n<tr>\n<td><strong>failover_enabled</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />When <code>true</code>, declined or unavailable gateways fail over to the next eligible gateway.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether the router is active and available for routing.</td>\n</tr>\n<tr>\n<td><strong>use_weighted_routing</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />When <code>true</code>, transactions are distributed across gateways according to their configured weights.</td>\n</tr>\n<tr>\n<td><strong>subscription_routing_strategy</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Strategy used to route subscription rebills (e.g. keeping rebills on the gateway that processed the initial sale). Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>email_tokens</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of email token rules used to influence routing (e.g. email domains/patterns mapped to specific handling).</td>\n</tr>\n<tr>\n<td><strong>bin_configurations</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of BIN-level routing overrides. Each entry is an object keyed by card BIN, typically including the target gateway and an action — e.g. <code>bin_configurations[].bin</code>, <code>bin_configurations[].gateway_internal_id</code>, <code>bin_configurations[].action</code>.</td>\n</tr>\n<tr>\n<td><strong>mcc_configurations</strong></td>\n<td><em><strong>array (optional)</strong></em>  <br />List of MCC-level routing overrides. Each entry is an object keyed by merchant category code — e.g. <code>mcc_configurations[].mcc</code>, <code>mcc_configurations[].gateway_internal_id</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p><code>201 Created</code> — returns the full detailed router object identical to the <code>Get Payment Router</code> response (minus the <code>gateways_count</code> / <code>routing_rules_count</code> counts, which are only loaded by the detail endpoint), plus:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Payment router created successfully\"\n}\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Missing required permission</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages, e.g. duplicate <code>name</code> or invalid <code>algorithm_type</code>)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"a6b7e563-f7c2-504b-4367-c23ef3161313","name":"Create Payment Router","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Primary Smart Router\",\n  \"algorithm_type\": \"highest_approval_rate\",\n  \"monthly_processing_limit\": 1000000,\n  \"failover_enabled\": true,\n  \"is_active\": true,\n  \"use_weighted_routing\": false,\n  \"subscription_routing_strategy\": \"sticky_initial_mid\",\n  \"email_tokens\": [\n    \"@gmail.com\",\n    \"@outlook.com\"\n  ],\n  \"bin_configurations\": [\n    {\n      \"bin\": \"414720\",\n      \"gateway_internal_id\": 3,\n      \"action\": \"route\"\n    }\n  ],\n  \"mcc_configurations\": [\n    {\n      \"mcc\": \"5815\",\n      \"gateway_internal_id\": 3\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers","description":"# Create Payment Router\n\n**Create a New Payment Router**\n\nCreate a new payment router (orchestrator) for the authenticated account. A payment router decides which gateway a transaction is sent to based on its routing algorithm, weighting, failover, and any BIN / MCC / email-token overrides. Returns the detailed router object on success.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| **name** | _**string (required)**_  <br>Router name. Must be unique within the team (soft-deleted routers are ignored). Maximum 255 characters. |\n| **algorithm_type** | _**string (optional)**_  <br>Routing algorithm used to select a gateway. Options: `highest_approval_rate` (routes to the gateway with the highest likelihood of approval based on recent and historical data), `round_robin` (evenly distributes transactions across eligible gateways), `ruleset_only` (only routes using custom rules and fails if no rule matches). |\n| **monthly_processing_limit** | _**number (optional, nullable)**_  <br>Total monthly processing limit in dollars across the router. Minimum 0. Stored with 2-decimal precision. |\n| **failover_enabled** | _**boolean (optional)**_  <br>When `true`, declined or unavailable gateways fail over to the next eligible gateway. |\n| **is_active** | _**boolean (optional)**_  <br>Whether the router is active and available for routing. |\n| **use_weighted_routing** | _**boolean (optional)**_  <br>When `true`, transactions are distributed across gateways according to their configured weights. |\n| **subscription_routing_strategy** | _**string (optional)**_  <br>Strategy used to route subscription rebills (e.g. keeping rebills on the gateway that processed the initial sale). Maximum 50 characters. |\n| **email_tokens** | _**array (optional)**_  <br>List of email token rules used to influence routing (e.g. email domains/patterns mapped to specific handling). |\n| **bin_configurations** | _**array (optional)**_  <br>List of BIN-level routing overrides. Each entry is an object keyed by card BIN, typically including the target gateway and an action — e.g. `bin_configurations[].bin`, `bin_configurations[].gateway_internal_id`, `bin_configurations[].action`. |\n| **mcc_configurations** | _**array (optional)**_  <br>List of MCC-level routing overrides. Each entry is an object keyed by merchant category code — e.g. `mcc_configurations[].mcc`, `mcc_configurations[].gateway_internal_id`. |\n\n## Response\n\n`201 Created` — returns the full detailed router object identical to the `Get Payment Router` response (minus the `gateways_count` / `routing_rules_count` counts, which are only loaded by the detail endpoint), plus:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Payment router created successfully\"\n}\n```\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Missing required permission |\n| **422** | Validation error (returns `errors` object with field-level messages, e.g. duplicate `name` or invalid `algorithm_type`) |"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Payment router created successfully\",\n  \"data\": {\n    \"id\": 12,\n    \"name\": \"Primary Smart Router\",\n    \"algorithm_type\": \"highest_approval_rate\",\n    \"is_active\": true,\n    \"failover_enabled\": true,\n    \"use_weighted_routing\": false,\n    \"monthly_processing_limit\": \"1000000.00\",\n    \"subscription_routing_strategy\": \"sticky_initial_mid\",\n    \"created_at\": \"2026-06-16T15:04:11.000000Z\",\n    \"updated_at\": \"2026-06-16T15:04:11.000000Z\",\n    \"email_tokens\": [\n      \"@gmail.com\",\n      \"@outlook.com\"\n    ],\n    \"bin_configurations\": [\n      {\n        \"bin\": \"414720\",\n        \"gateway_internal_id\": 3,\n        \"action\": \"route\"\n      }\n    ],\n    \"mcc_configurations\": [\n      {\n        \"mcc\": \"5815\",\n        \"gateway_internal_id\": 3\n      }\n    ]\n  }\n}"}],"_postman_id":"1d857f0e-bcd7-7733-f495-aee4ea60037b"},{"name":"Get Payment Router","id":"673d64a3-c82e-4831-9eb0-1ef062c2cf19","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/12","description":"<h1 id=\"get-payment-router\">Get Payment Router</h1>\n<p><strong>Retrieve a Single Payment Router</strong></p>\n<p>Retrieve a single payment router (orchestrator) by its identifier (the team's internal router id). Database ids are never exposed. Returns the detailed representation including configuration arrays and counts of associated gateways and routing rules.</p>\n<h2 id=\"example\">Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET https://api.sparkcrm.io/v1/payment-routers/12\n</code></pre><h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.view</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>router_id</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal payment router id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Response Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>success</strong></td>\n<td><strong>boolean</strong>  <br />Indicates if the API request was successful</td>\n</tr>\n<tr>\n<td><strong>data</strong></td>\n<td><strong>object</strong>  <br />Payment router object</td>\n</tr>\n<tr>\n<td><strong>data.id</strong></td>\n<td><strong>integer</strong>  <br />Payment router identifier (team's internal id)</td>\n</tr>\n<tr>\n<td><strong>data.name</strong></td>\n<td><strong>string</strong>  <br />Payment router display name</td>\n</tr>\n<tr>\n<td><strong>data.algorithm_type</strong></td>\n<td><strong>string/null</strong>  <br />Routing algorithm. One of <code>highest_approval_rate</code>, <code>round_robin</code>, <code>ruleset_only</code></td>\n</tr>\n<tr>\n<td><strong>data.is_active</strong></td>\n<td><strong>boolean</strong>  <br />Whether the router is active</td>\n</tr>\n<tr>\n<td><strong>data.failover_enabled</strong></td>\n<td><strong>boolean</strong>  <br />Whether failover to backup gateways is enabled</td>\n</tr>\n<tr>\n<td><strong>data.use_weighted_routing</strong></td>\n<td><strong>boolean</strong>  <br />Whether weighted (percentage-based) routing across gateways is used</td>\n</tr>\n<tr>\n<td><strong>data.monthly_processing_limit</strong></td>\n<td><strong>string/null</strong>  <br />Monthly processing limit in dollars, formatted to 2 decimal places (e.g. <code>\"1000000.00\"</code>). <code>null</code> when no limit is set</td>\n</tr>\n<tr>\n<td><strong>data.subscription_routing_strategy</strong></td>\n<td><strong>string/null</strong>  <br />Strategy used to route subscription rebills</td>\n</tr>\n<tr>\n<td><strong>data.created_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the router was created</td>\n</tr>\n<tr>\n<td><strong>data.updated_at</strong></td>\n<td><strong>string</strong>  <br />ISO 8601 timestamp when the router was last updated</td>\n</tr>\n<tr>\n<td><strong>data.email_tokens</strong></td>\n<td><strong>array/null</strong>  <br />List of email token routing rules</td>\n</tr>\n<tr>\n<td><strong>data.bin_configurations</strong></td>\n<td><strong>array/null</strong>  <br />List of BIN-level routing overrides</td>\n</tr>\n<tr>\n<td><strong>data.mcc_configurations</strong></td>\n<td><strong>array/null</strong>  <br />List of MCC-level routing overrides</td>\n</tr>\n<tr>\n<td><strong>data.gateways_count</strong></td>\n<td><strong>integer</strong>  <br />Number of gateways attached to this router</td>\n</tr>\n<tr>\n<td><strong>data.routing_rules_count</strong></td>\n<td><strong>integer</strong>  <br />Number of routing rules configured on this router</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Missing required permission</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Payment router not found</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","12"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"7002564f-3694-7099-bdac-da44f60a4952","name":"Get Payment Router","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/payment-routers/12","description":"# Get Payment Router\n\n**Retrieve a Single Payment Router**\n\nRetrieve a single payment router (orchestrator) by its identifier (the team's internal router id). Database ids are never exposed. Returns the detailed representation including configuration arrays and counts of associated gateways and routing rules.\n\n## Example\n\n```\nGET https://api.sparkcrm.io/v1/payment-routers/12\n```\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.view`\n\n## Path Variables\n\n| Variable | Description |\n| --- | --- |\n| **router_id** | _**integer (required)**_  <br>The team's internal payment router id. |\n\n## Response Object\n\n| Response Field | Description |\n| --- | --- |\n| **success** | **boolean**  <br>Indicates if the API request was successful |\n| **data** | **object**  <br>Payment router object |\n| **data.id** | **integer**  <br>Payment router identifier (team's internal id) |\n| **data.name** | **string**  <br>Payment router display name |\n| **data.algorithm_type** | **string/null**  <br>Routing algorithm. One of `highest_approval_rate`, `round_robin`, `ruleset_only` |\n| **data.is_active** | **boolean**  <br>Whether the router is active |\n| **data.failover_enabled** | **boolean**  <br>Whether failover to backup gateways is enabled |\n| **data.use_weighted_routing** | **boolean**  <br>Whether weighted (percentage-based) routing across gateways is used |\n| **data.monthly_processing_limit** | **string/null**  <br>Monthly processing limit in dollars, formatted to 2 decimal places (e.g. `\"1000000.00\"`). `null` when no limit is set |\n| **data.subscription_routing_strategy** | **string/null**  <br>Strategy used to route subscription rebills |\n| **data.created_at** | **string**  <br>ISO 8601 timestamp when the router was created |\n| **data.updated_at** | **string**  <br>ISO 8601 timestamp when the router was last updated |\n| **data.email_tokens** | **array/null**  <br>List of email token routing rules |\n| **data.bin_configurations** | **array/null**  <br>List of BIN-level routing overrides |\n| **data.mcc_configurations** | **array/null**  <br>List of MCC-level routing overrides |\n| **data.gateways_count** | **integer**  <br>Number of gateways attached to this router |\n| **data.routing_rules_count** | **integer**  <br>Number of routing rules configured on this router |\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Missing required permission |\n| **404** | Payment router not found |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"id\": 12,\n    \"name\": \"Primary Smart Router\",\n    \"algorithm_type\": \"highest_approval_rate\",\n    \"is_active\": true,\n    \"failover_enabled\": true,\n    \"use_weighted_routing\": false,\n    \"monthly_processing_limit\": \"1000000.00\",\n    \"subscription_routing_strategy\": \"sticky_initial_mid\",\n    \"created_at\": \"2026-05-21T14:08:22.000000Z\",\n    \"updated_at\": \"2026-06-10T09:31:54.000000Z\",\n    \"email_tokens\": [\n      \"@gmail.com\",\n      \"@outlook.com\"\n    ],\n    \"bin_configurations\": [\n      {\n        \"bin\": \"414720\",\n        \"gateway_internal_id\": 3,\n        \"action\": \"route\"\n      }\n    ],\n    \"mcc_configurations\": [\n      {\n        \"mcc\": \"5815\",\n        \"gateway_internal_id\": 3\n      }\n    ],\n    \"gateways_count\": 4,\n    \"routing_rules_count\": 2\n  }\n}"}],"_postman_id":"673d64a3-c82e-4831-9eb0-1ef062c2cf19"},{"name":"Update Payment Router","id":"c30c23ac-4aab-9b78-5036-dcd01e306ed5","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Primary Smart Router (v2)\",\n  \"algorithm_type\": \"round_robin\",\n  \"failover_enabled\": false,\n  \"monthly_processing_limit\": 1500000\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/12","description":"<h1 id=\"update-payment-router\">Update Payment Router</h1>\n<p><strong>Partially Update a Payment Router</strong></p>\n<p>Update mutable fields on a payment router (orchestrator). All fields are optional; only the validated fields included in the request body will be saved. The identifier in the URL is the team's internal router id.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:payment_routers.update</code></p>\n<h2 id=\"path-variables\">Path Variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>router_id</strong></td>\n<td><em><strong>integer (required)</strong></em>  <br />The team's internal payment router id.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional. Only the fields included will be updated.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>name</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Router name. Must be unique within the team (soft-deleted routers are ignored). Maximum 255 characters.</td>\n</tr>\n<tr>\n<td><strong>algorithm_type</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Routing algorithm. Options: <code>highest_approval_rate</code>, <code>round_robin</code>, <code>ruleset_only</code>.</td>\n</tr>\n<tr>\n<td><strong>monthly_processing_limit</strong></td>\n<td><em><strong>number (optional, nullable)</strong></em>  <br />Monthly processing limit in dollars. Minimum 0. Stored with 2-decimal precision.</td>\n</tr>\n<tr>\n<td><strong>failover_enabled</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether failover to backup gateways is enabled.</td>\n</tr>\n<tr>\n<td><strong>is_active</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether the router is active.</td>\n</tr>\n<tr>\n<td><strong>use_weighted_routing</strong></td>\n<td><em><strong>boolean (optional)</strong></em>  <br />Whether weighted routing across gateways is used.</td>\n</tr>\n<tr>\n<td><strong>subscription_routing_strategy</strong></td>\n<td><em><strong>string (optional)</strong></em>  <br />Strategy used to route subscription rebills. Maximum 50 characters.</td>\n</tr>\n<tr>\n<td><strong>email_tokens</strong></td>\n<td><em><strong>array (optional, nullable)</strong></em>  <br />List of email token routing rules.</td>\n</tr>\n<tr>\n<td><strong>bin_configurations</strong></td>\n<td><em><strong>array (optional, nullable)</strong></em>  <br />List of BIN-level routing overrides — e.g. <code>bin_configurations[].bin</code>, <code>bin_configurations[].gateway_internal_id</code>, <code>bin_configurations[].action</code>.</td>\n</tr>\n<tr>\n<td><strong>mcc_configurations</strong></td>\n<td><em><strong>array (optional, nullable)</strong></em>  <br />List of MCC-level routing overrides — e.g. <code>mcc_configurations[].mcc</code>, <code>mcc_configurations[].gateway_internal_id</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p><code>200 OK</code> — returns the updated detailed router object plus:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"message\": \"Payment router updated successfully\"\n}\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>403</strong></td>\n<td>Missing required permission</td>\n</tr>\n<tr>\n<td><strong>404</strong></td>\n<td>Payment router not found</td>\n</tr>\n<tr>\n<td><strong>422</strong></td>\n<td>Validation error (returns <code>errors</code> object with field-level messages)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","payment-routers","12"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"b9568522-b7b7-74d3-12f2-817ae2903e61","name":"Update Payment Router","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Primary Smart Router (v2)\",\n  \"algorithm_type\": \"round_robin\",\n  \"failover_enabled\": false,\n  \"monthly_processing_limit\": 1500000\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/payment-routers/12","description":"# Update Payment Router\n\n**Partially Update a Payment Router**\n\nUpdate mutable fields on a payment router (orchestrator). All fields are optional; only the validated fields included in the request body will be saved. The identifier in the URL is the team's internal router id.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:payment_routers.update`\n\n## Path Variables\n\n| Variable | Description |\n| --- | --- |\n| **router_id** | _**integer (required)**_  <br>The team's internal payment router id. |\n\n## Request Body\n\nAll fields are optional. Only the fields included will be updated.\n\n| Request Field | Description |\n| --- | --- |\n| **name** | _**string (optional)**_  <br>Router name. Must be unique within the team (soft-deleted routers are ignored). Maximum 255 characters. |\n| **algorithm_type** | _**string (optional)**_  <br>Routing algorithm. Options: `highest_approval_rate`, `round_robin`, `ruleset_only`. |\n| **monthly_processing_limit** | _**number (optional, nullable)**_  <br>Monthly processing limit in dollars. Minimum 0. Stored with 2-decimal precision. |\n| **failover_enabled** | _**boolean (optional)**_  <br>Whether failover to backup gateways is enabled. |\n| **is_active** | _**boolean (optional)**_  <br>Whether the router is active. |\n| **use_weighted_routing** | _**boolean (optional)**_  <br>Whether weighted routing across gateways is used. |\n| **subscription_routing_strategy** | _**string (optional)**_  <br>Strategy used to route subscription rebills. Maximum 50 characters. |\n| **email_tokens** | _**array (optional, nullable)**_  <br>List of email token routing rules. |\n| **bin_configurations** | _**array (optional, nullable)**_  <br>List of BIN-level routing overrides — e.g. `bin_configurations[].bin`, `bin_configurations[].gateway_internal_id`, `bin_configurations[].action`. |\n| **mcc_configurations** | _**array (optional, nullable)**_  <br>List of MCC-level routing overrides — e.g. `mcc_configurations[].mcc`, `mcc_configurations[].gateway_internal_id`. |\n\n## Response\n\n`200 OK` — returns the updated detailed router object plus:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Payment router updated successfully\"\n}\n```\n\n## Errors\n\n| Status | Description |\n| --- | --- |\n| **403** | Missing required permission |\n| **404** | Payment router not found |\n| **422** | Validation error (returns `errors` object with field-level messages) |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"message\": \"Payment router updated successfully\",\n  \"data\": {\n    \"id\": 12,\n    \"name\": \"Primary Smart Router (v2)\",\n    \"algorithm_type\": \"round_robin\",\n    \"is_active\": true,\n    \"failover_enabled\": false,\n    \"use_weighted_routing\": false,\n    \"monthly_processing_limit\": \"1500000.00\",\n    \"subscription_routing_strategy\": \"sticky_initial_mid\",\n    \"created_at\": \"2026-05-21T14:08:22.000000Z\",\n    \"updated_at\": \"2026-06-16T15:11:47.000000Z\",\n    \"email_tokens\": [\n      \"@gmail.com\",\n      \"@outlook.com\"\n    ],\n    \"bin_configurations\": [\n      {\n        \"bin\": \"414720\",\n        \"gateway_internal_id\": 3,\n        \"action\": \"route\"\n      }\n    ],\n    \"mcc_configurations\": [\n      {\n        \"mcc\": \"5815\",\n        \"gateway_internal_id\": 3\n      }\n    ]\n  }\n}"}],"_postman_id":"c30c23ac-4aab-9b78-5036-dcd01e306ed5"}],"id":"6f4be677-4fc0-0f07-d27a-aa682a087c56","_postman_id":"6f4be677-4fc0-0f07-d27a-aa682a087c56","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Decline Salvage Profiles","item":[{"name":"List Decline Salvage Profiles","id":"3aa0de23-0b7a-1672-fa73-4dbd5b7555b2","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles?per_page=15&page=1&search=Standard&is_active=true","description":"<h1 id=\"list-decline-salvage-profiles\">List Decline Salvage Profiles</h1>\n<p><strong>Retrieve a paginated, searchable list of the decline salvage profiles owned by your account.</strong></p>\n<p>Returns every decline salvage profile belonging to the authenticated account, newest first. Each profile defines how declined transactions are automatically retried (the retry schedule, attempt limits, amount/window bounds, and excluded decline codes). The list view returns a summary of each profile; use the <strong>Get Decline Salvage Profile</strong> endpoint to retrieve the full object including the <code>retry_schedule</code> and <code>excluded_decline_codes</code> arrays.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:decline_salvage_profiles.view_any</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>search</code></td>\n<td><em><strong>string (optional)</strong></em> Case-insensitive partial match against the profile <code>name</code>. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Filter by active state. Accepts <code>true</code>/<code>false</code> or <code>1</code>/<code>0</code>. When omitted, profiles of all states are returned.</td>\n</tr>\n<tr>\n<td><code>per_page</code></td>\n<td><em><strong>integer (optional)</strong></em> Number of results per page. Min <code>1</code>, max <code>100</code>. Defaults to <code>15</code>.</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td><em><strong>integer (optional)</strong></em> Page number to retrieve. Min <code>1</code>. Defaults to <code>1</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code>, a <code>data</code> array of profile summary objects, and a <code>pagination</code> object. Each item in <code>data</code> contains:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td><em>integer</em> The profile's account-scoped id (<code>internal_id</code>). Use this value in the path of the Get/Update endpoints.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td><em>string</em> The profile name.</td>\n</tr>\n<tr>\n<td><code>salvage_type</code></td>\n<td><em>string</em> One of <code>standard</code> or <code>custom</code>.</td>\n</tr>\n<tr>\n<td><code>transaction_type</code></td>\n<td><em>string|null</em> Which transactions the profile applies to: <code>initial</code>, <code>rebill</code>, or <code>both</code>.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em>boolean</em> Whether the profile is enabled.</td>\n</tr>\n<tr>\n<td><code>is_default</code></td>\n<td><em>boolean</em> Whether this is the account default profile (only one per account).</td>\n</tr>\n<tr>\n<td><code>auto_apply_to_new</code></td>\n<td><em>boolean</em> Whether the profile is automatically applied to newly created campaigns.</td>\n</tr>\n<tr>\n<td><code>fire_affiliate_pixels</code></td>\n<td><em>boolean</em> Whether affiliate pixels fire on a successful salvage.</td>\n</tr>\n<tr>\n<td><code>max_attempts</code></td>\n<td><em>integer|null</em> Maximum number of retry attempts.</td>\n</tr>\n<tr>\n<td><code>minimum_retry_interval</code></td>\n<td><em>integer|null</em> Minimum delay before the first retry, in minutes.</td>\n</tr>\n<tr>\n<td><code>maximum_retry_window</code></td>\n<td><em>integer|null</em> Maximum window over which retries are attempted, in minutes.</td>\n</tr>\n<tr>\n<td><code>minimum_amount</code></td>\n<td><em>string|null</em> Lower transaction-amount bound (decimal, 2 places). Transactions below this are not salvaged.</td>\n</tr>\n<tr>\n<td><code>maximum_amount</code></td>\n<td><em>string|null</em> Upper transaction-amount bound (decimal, 2 places). Transactions above this are not salvaged.</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td><em>string|null</em> ISO 8601 creation timestamp.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td><em>string|null</em> ISO 8601 last-updated timestamp.</td>\n</tr>\n</tbody>\n</table>\n</div><p>The summary list intentionally omits <code>retry_schedule</code> and <code>excluded_decline_codes</code>; both are returned by the Get/Create/Update endpoints.</p>\n<p>The <code>pagination</code> object contains <code>total</code>, <code>per_page</code>, <code>current_page</code>, <code>last_page</code>, <code>from</code>, and <code>to</code>.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:decline_salvage_profiles.view_any</code> (or legacy <code>api:view_any</code>) permission.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error on a query parameter (e.g. <code>per_page</code> above 100).</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET /v1/decline-salvage-profiles?per_page=15&amp;page=1&amp;is_active=true</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","decline-salvage-profiles"],"host":["api","sparkcrm","io"],"query":[{"description":{"content":"<p>Optional. Case-insensitive partial match against the profile name. string, max 255 characters.</p>\n","type":"text/plain"},"key":"search","value":"Standard"},{"disabled":true,"description":{"content":"<p>Optional. Filter by active state. boolean (true/false, 1/0). When present, returns only profiles whose is_active matches.</p>\n","type":"text/plain"},"key":"is_active","value":"true"},{"description":{"content":"<p>Optional. Results per page. integer, min 1, max 100. Defaults to 15.</p>\n","type":"text/plain"},"key":"per_page","value":"15"},{"description":{"content":"<p>Optional. Page number to retrieve. integer, min 1. Defaults to 1.</p>\n","type":"text/plain"},"key":"page","value":"1"}],"variable":[]}},"response":[{"id":"1387edcd-784b-a972-d7f4-d404e5001b62","name":"List Decline Salvage Profiles","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://api.sparkcrm.io/v1/decline-salvage-profiles?per_page=15&page=1&search=Standard&is_active=true","protocol":"https","host":["api","sparkcrm","io"],"path":["v1","decline-salvage-profiles"],"query":[{"key":"search","description":"Optional. Case-insensitive partial match against the profile name. string, max 255 characters.","value":"Standard"},{"key":"is_active","description":"Optional. Filter by active state. boolean (true/false, 1/0). When present, returns only profiles whose is_active matches.","value":"true","disabled":true},{"key":"per_page","description":"Optional. Results per page. integer, min 1, max 100. Defaults to 15.","value":"15"},{"key":"page","description":"Optional. Page number to retrieve. integer, min 1. Defaults to 1.","value":"1"}]},"description":"# List Decline Salvage Profiles\n\n**Retrieve a paginated, searchable list of the decline salvage profiles owned by your account.**\n\nReturns every decline salvage profile belonging to the authenticated account, newest first. Each profile defines how declined transactions are automatically retried (the retry schedule, attempt limits, amount/window bounds, and excluded decline codes). The list view returns a summary of each profile; use the **Get Decline Salvage Profile** endpoint to retrieve the full object including the `retry_schedule` and `excluded_decline_codes` arrays.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:decline_salvage_profiles.view_any`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `search` | _**string (optional)**_ Case-insensitive partial match against the profile `name`. Max 255 characters. |\n| `is_active` | _**boolean (optional)**_ Filter by active state. Accepts `true`/`false` or `1`/`0`. When omitted, profiles of all states are returned. |\n| `per_page` | _**integer (optional)**_ Number of results per page. Min `1`, max `100`. Defaults to `15`. |\n| `page` | _**integer (optional)**_ Page number to retrieve. Min `1`. Defaults to `1`. |\n\n## Response Object\n\nReturns `success: true`, a `data` array of profile summary objects, and a `pagination` object. Each item in `data` contains:\n\n| Field | Description |\n| --- | --- |\n| `id` | _integer_ The profile's account-scoped id (`internal_id`). Use this value in the path of the Get/Update endpoints. |\n| `name` | _string_ The profile name. |\n| `salvage_type` | _string_ One of `standard` or `custom`. |\n| `transaction_type` | _string\\|null_ Which transactions the profile applies to: `initial`, `rebill`, or `both`. |\n| `is_active` | _boolean_ Whether the profile is enabled. |\n| `is_default` | _boolean_ Whether this is the account default profile (only one per account). |\n| `auto_apply_to_new` | _boolean_ Whether the profile is automatically applied to newly created campaigns. |\n| `fire_affiliate_pixels` | _boolean_ Whether affiliate pixels fire on a successful salvage. |\n| `max_attempts` | _integer\\|null_ Maximum number of retry attempts. |\n| `minimum_retry_interval` | _integer\\|null_ Minimum delay before the first retry, in minutes. |\n| `maximum_retry_window` | _integer\\|null_ Maximum window over which retries are attempted, in minutes. |\n| `minimum_amount` | _string\\|null_ Lower transaction-amount bound (decimal, 2 places). Transactions below this are not salvaged. |\n| `maximum_amount` | _string\\|null_ Upper transaction-amount bound (decimal, 2 places). Transactions above this are not salvaged. |\n| `created_at` | _string\\|null_ ISO 8601 creation timestamp. |\n| `updated_at` | _string\\|null_ ISO 8601 last-updated timestamp. |\n\nThe summary list intentionally omits `retry_schedule` and `excluded_decline_codes`; both are returned by the Get/Create/Update endpoints.\n\nThe `pagination` object contains `total`, `per_page`, `current_page`, `last_page`, `from`, and `to`.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:decline_salvage_profiles.view_any` (or legacy `api:view_any`) permission. |\n| `422` | Validation error on a query parameter (e.g. `per_page` above 100). |\n\n## Example\n\n`GET /v1/decline-salvage-profiles?per_page=15&page=1&is_active=true`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": [\n    {\n      \"id\": 1042,\n      \"name\": \"Standard Recovery\",\n      \"salvage_type\": \"standard\",\n      \"transaction_type\": \"both\",\n      \"is_active\": true,\n      \"is_default\": true,\n      \"auto_apply_to_new\": true,\n      \"fire_affiliate_pixels\": false,\n      \"max_attempts\": 4,\n      \"minimum_retry_interval\": 45,\n      \"maximum_retry_window\": 2160,\n      \"minimum_amount\": \"1.00\",\n      \"maximum_amount\": \"500.00\",\n      \"created_at\": \"2026-05-30T14:22:05.000000Z\",\n      \"updated_at\": \"2026-06-12T09:01:44.000000Z\"\n    },\n    {\n      \"id\": 1039,\n      \"name\": \"Aggressive Recovery\",\n      \"salvage_type\": \"custom\",\n      \"transaction_type\": \"rebill\",\n      \"is_active\": true,\n      \"is_default\": false,\n      \"auto_apply_to_new\": false,\n      \"fire_affiliate_pixels\": true,\n      \"max_attempts\": 4,\n      \"minimum_retry_interval\": 30,\n      \"maximum_retry_window\": 4320,\n      \"minimum_amount\": null,\n      \"maximum_amount\": null,\n      \"created_at\": \"2026-05-21T18:47:11.000000Z\",\n      \"updated_at\": \"2026-05-21T18:47:11.000000Z\"\n    }\n  ],\n  \"success\": true,\n  \"pagination\": {\n    \"total\": 2,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 1,\n    \"from\": 1,\n    \"to\": 2\n  }\n}"}],"_postman_id":"3aa0de23-0b7a-1672-fa73-4dbd5b7555b2"},{"name":"Create Decline Salvage Profile","id":"54a24691-4afb-4536-25f3-ca0e1461f067","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Aggressive Recovery\",\n  \"salvage_type\": \"custom\",\n  \"transaction_type\": \"both\",\n  \"is_active\": true,\n  \"is_default\": false,\n  \"auto_apply_to_new\": false,\n  \"fire_affiliate_pixels\": true,\n  \"retry_schedule\": [\n    { \"attempt\": 1, \"delay\": 30 },\n    { \"attempt\": 2, \"delay\": 120 },\n    { \"attempt\": 3, \"delay\": 360 }\n  ],\n  \"max_attempts\": 4,\n  \"minimum_retry_interval\": 30,\n  \"maximum_retry_window\": 4320,\n  \"excluded_decline_codes\": [\"fraud\", \"stolen_card\", \"lost_card\"],\n  \"minimum_amount\": 1.00,\n  \"maximum_amount\": 500.00\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles","description":"<h1 id=\"create-decline-salvage-profile\">Create Decline Salvage Profile</h1>\n<p><strong>Create a new decline salvage profile for your account.</strong></p>\n<p>Defines a reusable strategy for automatically retrying declined transactions. A profile controls which transactions are eligible (by type and amount), how many times and how often retries are attempted, and which decline codes are excluded from salvage. The created profile is returned in full (including <code>retry_schedule</code> and <code>excluded_decline_codes</code>).</p>\n<blockquote>\n<p><strong>Note on <code>retry_schedule</code>:</strong> When <code>salvage_type</code> is <code>standard</code>, the <code>retry_schedule</code> is set automatically to the built-in schedule (attempt 1 = 45 min, 2 = 180 min, 3 = 360 min, 4 = 2160 min) and any <code>retry_schedule</code> you supply is ignored. Supply a custom <code>retry_schedule</code> only when <code>salvage_type</code> is <code>custom</code>.</p>\n</blockquote>\n<blockquote>\n<p><strong>Note on <code>is_default</code>:</strong> Setting <code>is_default</code> to <code>true</code> automatically clears the default flag on any other profile in your account, ensuring at most one default profile.</p>\n</blockquote>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:decline_salvage_profiles.create</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (required)</strong></em> Human-readable profile name. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>salvage_type</code></td>\n<td><em><strong>string (required)</strong></em> Retry strategy. One of <code>standard</code> (built-in 4-attempt schedule) or <code>custom</code> (uses your supplied <code>retry_schedule</code>).</td>\n</tr>\n<tr>\n<td><code>transaction_type</code></td>\n<td><em><strong>string (optional)</strong></em> Which transactions the profile applies to. One of <code>initial</code>, <code>rebill</code>, or <code>both</code>. When omitted it is treated as <code>both</code> at evaluation time.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the profile is enabled.</td>\n</tr>\n<tr>\n<td><code>is_default</code></td>\n<td><em><strong>boolean (optional)</strong></em> Mark this profile as the account default. Setting <code>true</code> unsets the default on all other profiles.</td>\n</tr>\n<tr>\n<td><code>auto_apply_to_new</code></td>\n<td><em><strong>boolean (optional)</strong></em> Automatically apply this profile to newly created campaigns.</td>\n</tr>\n<tr>\n<td><code>fire_affiliate_pixels</code></td>\n<td><em><strong>boolean (optional)</strong></em> Fire affiliate pixels when a salvage succeeds.</td>\n</tr>\n<tr>\n<td><code>retry_schedule</code></td>\n<td><em><strong>array (optional)</strong></em> Ordered list of retry steps, used only when <code>salvage_type</code> is <code>custom</code>. Each item is an object: <code>attempt</code> (integer, the attempt number) and <code>delay</code> (integer, delay in minutes from the original decline). Ignored for <code>standard</code>.</td>\n</tr>\n<tr>\n<td><code>retry_schedule[].attempt</code></td>\n<td><em><strong>integer</strong></em> The attempt number this step applies to (1-based).</td>\n</tr>\n<tr>\n<td><code>retry_schedule[].delay</code></td>\n<td><em><strong>integer</strong></em> Delay in minutes before this attempt is made.</td>\n</tr>\n<tr>\n<td><code>max_attempts</code></td>\n<td><em><strong>integer (optional)</strong></em> Maximum number of retry attempts. Min <code>1</code>.</td>\n</tr>\n<tr>\n<td><code>minimum_retry_interval</code></td>\n<td><em><strong>integer (optional)</strong></em> Minimum delay before the first retry, in minutes. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>maximum_retry_window</code></td>\n<td><em><strong>integer (optional)</strong></em> Maximum window over which retries may run, in minutes. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>excluded_decline_codes</code></td>\n<td><em><strong>array (optional)</strong></em> Normalized decline codes that should never be salvaged. Each entry is a string, max 100 characters (e.g. <code>fraud</code>, <code>stolen_card</code>, <code>lost_card</code>, <code>expired_card</code>, <code>insufficient_funds</code>).</td>\n</tr>\n<tr>\n<td><code>excluded_decline_codes[]</code></td>\n<td><em><strong>string</strong></em> A single decline code. Max 100 characters.</td>\n</tr>\n<tr>\n<td><code>minimum_amount</code></td>\n<td><em><strong>numeric (optional)</strong></em> Lower transaction-amount bound. Min <code>0</code>. Transactions below this are not salvaged. Stored with 2 decimal places.</td>\n</tr>\n<tr>\n<td><code>maximum_amount</code></td>\n<td><em><strong>numeric (optional)</strong></em> Upper transaction-amount bound. Min <code>0</code>. Transactions above this are not salvaged. Stored with 2 decimal places.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code>, a <code>message</code>, and the full created profile in <code>data</code>. The detailed response includes all summary fields plus <code>retry_schedule</code> and <code>excluded_decline_codes</code>. The <code>id</code> field is the profile's account-scoped <code>internal_id</code>. Amount fields are returned as decimal strings with 2 places.</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:decline_salvage_profiles.create</code> (or legacy <code>api:create</code>) permission.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error. Returns <code>message: \"Validation error\"</code> and an <code>errors</code> object. Common causes: missing <code>name</code>, missing or invalid <code>salvage_type</code> (not <code>standard</code>/<code>custom</code>), <code>transaction_type</code> not in <code>initial</code>/<code>rebill</code>/<code>both</code>, <code>max_attempts</code> below 1, negative interval/window/amount.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>POST /v1/decline-salvage-profiles</code> with the request body shown returns the <code>201</code> response below.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","decline-salvage-profiles"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"89043919-0d39-054a-740a-65f695f3987d","name":"Create Decline Salvage Profile","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Aggressive Recovery\",\n  \"salvage_type\": \"custom\",\n  \"transaction_type\": \"both\",\n  \"is_active\": true,\n  \"is_default\": false,\n  \"auto_apply_to_new\": false,\n  \"fire_affiliate_pixels\": true,\n  \"retry_schedule\": [\n    { \"attempt\": 1, \"delay\": 30 },\n    { \"attempt\": 2, \"delay\": 120 },\n    { \"attempt\": 3, \"delay\": 360 }\n  ],\n  \"max_attempts\": 4,\n  \"minimum_retry_interval\": 30,\n  \"maximum_retry_window\": 4320,\n  \"excluded_decline_codes\": [\"fraud\", \"stolen_card\", \"lost_card\"],\n  \"minimum_amount\": 1.00,\n  \"maximum_amount\": 500.00\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles","description":"# Create Decline Salvage Profile\n\n**Create a new decline salvage profile for your account.**\n\nDefines a reusable strategy for automatically retrying declined transactions. A profile controls which transactions are eligible (by type and amount), how many times and how often retries are attempted, and which decline codes are excluded from salvage. The created profile is returned in full (including `retry_schedule` and `excluded_decline_codes`).\n\n> **Note on `retry_schedule`:** When `salvage_type` is `standard`, the `retry_schedule` is set automatically to the built-in schedule (attempt 1 = 45 min, 2 = 180 min, 3 = 360 min, 4 = 2160 min) and any `retry_schedule` you supply is ignored. Supply a custom `retry_schedule` only when `salvage_type` is `custom`.\n\n> **Note on `is_default`:** Setting `is_default` to `true` automatically clears the default flag on any other profile in your account, ensuring at most one default profile.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:decline_salvage_profiles.create`\n\n## Request Body\n\n| Request Field | Description |\n| --- | --- |\n| `name` | _**string (required)**_ Human-readable profile name. Max 255 characters. |\n| `salvage_type` | _**string (required)**_ Retry strategy. One of `standard` (built-in 4-attempt schedule) or `custom` (uses your supplied `retry_schedule`). |\n| `transaction_type` | _**string (optional)**_ Which transactions the profile applies to. One of `initial`, `rebill`, or `both`. When omitted it is treated as `both` at evaluation time. |\n| `is_active` | _**boolean (optional)**_ Whether the profile is enabled. |\n| `is_default` | _**boolean (optional)**_ Mark this profile as the account default. Setting `true` unsets the default on all other profiles. |\n| `auto_apply_to_new` | _**boolean (optional)**_ Automatically apply this profile to newly created campaigns. |\n| `fire_affiliate_pixels` | _**boolean (optional)**_ Fire affiliate pixels when a salvage succeeds. |\n| `retry_schedule` | _**array (optional)**_ Ordered list of retry steps, used only when `salvage_type` is `custom`. Each item is an object: `attempt` (integer, the attempt number) and `delay` (integer, delay in minutes from the original decline). Ignored for `standard`. |\n| `retry_schedule[].attempt` | _**integer**_ The attempt number this step applies to (1-based). |\n| `retry_schedule[].delay` | _**integer**_ Delay in minutes before this attempt is made. |\n| `max_attempts` | _**integer (optional)**_ Maximum number of retry attempts. Min `1`. |\n| `minimum_retry_interval` | _**integer (optional)**_ Minimum delay before the first retry, in minutes. Min `0`. |\n| `maximum_retry_window` | _**integer (optional)**_ Maximum window over which retries may run, in minutes. Min `0`. |\n| `excluded_decline_codes` | _**array (optional)**_ Normalized decline codes that should never be salvaged. Each entry is a string, max 100 characters (e.g. `fraud`, `stolen_card`, `lost_card`, `expired_card`, `insufficient_funds`). |\n| `excluded_decline_codes[]` | _**string**_ A single decline code. Max 100 characters. |\n| `minimum_amount` | _**numeric (optional)**_ Lower transaction-amount bound. Min `0`. Transactions below this are not salvaged. Stored with 2 decimal places. |\n| `maximum_amount` | _**numeric (optional)**_ Upper transaction-amount bound. Min `0`. Transactions above this are not salvaged. Stored with 2 decimal places. |\n\n## Response\n\nReturns `success: true`, a `message`, and the full created profile in `data`. The detailed response includes all summary fields plus `retry_schedule` and `excluded_decline_codes`. The `id` field is the profile's account-scoped `internal_id`. Amount fields are returned as decimal strings with 2 places.\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:decline_salvage_profiles.create` (or legacy `api:create`) permission. |\n| `422` | Validation error. Returns `message: \"Validation error\"` and an `errors` object. Common causes: missing `name`, missing or invalid `salvage_type` (not `standard`/`custom`), `transaction_type` not in `initial`/`rebill`/`both`, `max_attempts` below 1, negative interval/window/amount. |\n\n## Example\n\n`POST /v1/decline-salvage-profiles` with the request body shown returns the `201` response below."},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"id\": 1043,\n    \"name\": \"Aggressive Recovery\",\n    \"salvage_type\": \"custom\",\n    \"transaction_type\": \"both\",\n    \"is_active\": true,\n    \"is_default\": false,\n    \"auto_apply_to_new\": false,\n    \"fire_affiliate_pixels\": true,\n    \"max_attempts\": 4,\n    \"minimum_retry_interval\": 30,\n    \"maximum_retry_window\": 4320,\n    \"minimum_amount\": \"1.00\",\n    \"maximum_amount\": \"500.00\",\n    \"created_at\": \"2026-06-16T15:08:33.000000Z\",\n    \"updated_at\": \"2026-06-16T15:08:33.000000Z\",\n    \"retry_schedule\": [\n      { \"attempt\": 1, \"delay\": 30 },\n      { \"attempt\": 2, \"delay\": 120 },\n      { \"attempt\": 3, \"delay\": 360 }\n    ],\n    \"excluded_decline_codes\": [\"fraud\", \"stolen_card\", \"lost_card\"]\n  },\n  \"success\": true,\n  \"message\": \"Decline salvage profile created successfully\"\n}"}],"_postman_id":"54a24691-4afb-4536-25f3-ca0e1461f067"},{"name":"Get Decline Salvage Profile","id":"47e73f68-1805-86db-faa9-34b1ed0dbdb2","request":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles/1043","description":"<h1 id=\"get-decline-salvage-profile\">Get Decline Salvage Profile</h1>\n<p><strong>Retrieve a single decline salvage profile by id.</strong></p>\n<p>Returns the full decline salvage profile identified by <code>{profile_id}</code>, including the <code>retry_schedule</code> and <code>excluded_decline_codes</code> arrays that the list endpoint omits. The lookup is account-scoped: a profile that does not belong to the authenticated account returns <code>404</code>.</p>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:decline_salvage_profiles.view</code></p>\n<h2 id=\"request-object\">Request Object</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>profile_id</code></td>\n<td><em><strong>integer (required)</strong></em> Path parameter. The profile's account-scoped id (<code>internal_id</code>), matched as digits only. This is the <code>id</code> value returned by the list and create endpoints.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response-object\">Response Object</h2>\n<p>Returns <code>success: true</code> and the full profile in <code>data</code>:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td><em>integer</em> The profile's account-scoped id (<code>internal_id</code>).</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td><em>string</em> The profile name.</td>\n</tr>\n<tr>\n<td><code>salvage_type</code></td>\n<td><em>string</em> One of <code>standard</code> or <code>custom</code>.</td>\n</tr>\n<tr>\n<td><code>transaction_type</code></td>\n<td><em>string|null</em> <code>initial</code>, <code>rebill</code>, or <code>both</code>.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em>boolean</em> Whether the profile is enabled.</td>\n</tr>\n<tr>\n<td><code>is_default</code></td>\n<td><em>boolean</em> Whether this is the account default profile.</td>\n</tr>\n<tr>\n<td><code>auto_apply_to_new</code></td>\n<td><em>boolean</em> Whether the profile is auto-applied to new campaigns.</td>\n</tr>\n<tr>\n<td><code>fire_affiliate_pixels</code></td>\n<td><em>boolean</em> Whether affiliate pixels fire on a successful salvage.</td>\n</tr>\n<tr>\n<td><code>max_attempts</code></td>\n<td><em>integer|null</em> Maximum number of retry attempts.</td>\n</tr>\n<tr>\n<td><code>minimum_retry_interval</code></td>\n<td><em>integer|null</em> Minimum delay before the first retry, in minutes.</td>\n</tr>\n<tr>\n<td><code>maximum_retry_window</code></td>\n<td><em>integer|null</em> Maximum window over which retries run, in minutes.</td>\n</tr>\n<tr>\n<td><code>minimum_amount</code></td>\n<td><em>string|null</em> Lower amount bound (decimal, 2 places).</td>\n</tr>\n<tr>\n<td><code>maximum_amount</code></td>\n<td><em>string|null</em> Upper amount bound (decimal, 2 places).</td>\n</tr>\n<tr>\n<td><code>created_at</code></td>\n<td><em>string|null</em> ISO 8601 creation timestamp.</td>\n</tr>\n<tr>\n<td><code>updated_at</code></td>\n<td><em>string|null</em> ISO 8601 last-updated timestamp.</td>\n</tr>\n<tr>\n<td><code>retry_schedule</code></td>\n<td><em>array|null</em> Ordered list of <code>{ attempt, delay }</code> retry steps (delay in minutes).</td>\n</tr>\n<tr>\n<td><code>excluded_decline_codes</code></td>\n<td><em>array|null</em> Decline codes excluded from salvage.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:decline_salvage_profiles.view</code> (or legacy <code>api:view_any</code>) permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>No profile with that <code>internal_id</code> exists for the authenticated account. Returns <code>message: \"Decline salvage profile not found\"</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>GET /v1/decline-salvage-profiles/1043</code></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","decline-salvage-profiles","1043"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"059310d4-992d-12c6-ebc3-4cd1b86767b6","name":"Get Decline Salvage Profile","originalRequest":{"method":"GET","header":[],"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles/1043","description":"# Get Decline Salvage Profile\n\n**Retrieve a single decline salvage profile by id.**\n\nReturns the full decline salvage profile identified by `{profile_id}`, including the `retry_schedule` and `excluded_decline_codes` arrays that the list endpoint omits. The lookup is account-scoped: a profile that does not belong to the authenticated account returns `404`.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:decline_salvage_profiles.view`\n\n## Request Object\n\n| Request Field | Description |\n| --- | --- |\n| `profile_id` | _**integer (required)**_ Path parameter. The profile's account-scoped id (`internal_id`), matched as digits only. This is the `id` value returned by the list and create endpoints. |\n\n## Response Object\n\nReturns `success: true` and the full profile in `data`:\n\n| Field | Description |\n| --- | --- |\n| `id` | _integer_ The profile's account-scoped id (`internal_id`). |\n| `name` | _string_ The profile name. |\n| `salvage_type` | _string_ One of `standard` or `custom`. |\n| `transaction_type` | _string\\|null_ `initial`, `rebill`, or `both`. |\n| `is_active` | _boolean_ Whether the profile is enabled. |\n| `is_default` | _boolean_ Whether this is the account default profile. |\n| `auto_apply_to_new` | _boolean_ Whether the profile is auto-applied to new campaigns. |\n| `fire_affiliate_pixels` | _boolean_ Whether affiliate pixels fire on a successful salvage. |\n| `max_attempts` | _integer\\|null_ Maximum number of retry attempts. |\n| `minimum_retry_interval` | _integer\\|null_ Minimum delay before the first retry, in minutes. |\n| `maximum_retry_window` | _integer\\|null_ Maximum window over which retries run, in minutes. |\n| `minimum_amount` | _string\\|null_ Lower amount bound (decimal, 2 places). |\n| `maximum_amount` | _string\\|null_ Upper amount bound (decimal, 2 places). |\n| `created_at` | _string\\|null_ ISO 8601 creation timestamp. |\n| `updated_at` | _string\\|null_ ISO 8601 last-updated timestamp. |\n| `retry_schedule` | _array\\|null_ Ordered list of `{ attempt, delay }` retry steps (delay in minutes). |\n| `excluded_decline_codes` | _array\\|null_ Decline codes excluded from salvage. |\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:decline_salvage_profiles.view` (or legacy `api:view_any`) permission. |\n| `404` | No profile with that `internal_id` exists for the authenticated account. Returns `message: \"Decline salvage profile not found\"`. |\n\n## Example\n\n`GET /v1/decline-salvage-profiles/1043`"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"id\": 1043,\n    \"name\": \"Aggressive Recovery\",\n    \"salvage_type\": \"custom\",\n    \"transaction_type\": \"both\",\n    \"is_active\": true,\n    \"is_default\": false,\n    \"auto_apply_to_new\": false,\n    \"fire_affiliate_pixels\": true,\n    \"max_attempts\": 4,\n    \"minimum_retry_interval\": 30,\n    \"maximum_retry_window\": 4320,\n    \"minimum_amount\": \"1.00\",\n    \"maximum_amount\": \"500.00\",\n    \"created_at\": \"2026-06-16T15:08:33.000000Z\",\n    \"updated_at\": \"2026-06-16T15:08:33.000000Z\",\n    \"retry_schedule\": [\n      { \"attempt\": 1, \"delay\": 30 },\n      { \"attempt\": 2, \"delay\": 120 },\n      { \"attempt\": 3, \"delay\": 360 }\n    ],\n    \"excluded_decline_codes\": [\"fraud\", \"stolen_card\", \"lost_card\"]\n  },\n  \"success\": true\n}"}],"_postman_id":"47e73f68-1805-86db-faa9-34b1ed0dbdb2"},{"name":"Update Decline Salvage Profile","id":"62d74d48-991f-191d-bc3c-b83af4f58376","request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Aggressive Recovery v2\",\n  \"is_active\": true,\n  \"is_default\": true,\n  \"max_attempts\": 5,\n  \"minimum_retry_interval\": 20,\n  \"maximum_retry_window\": 5760,\n  \"excluded_decline_codes\": [\"fraud\", \"stolen_card\"],\n  \"minimum_amount\": 5.00,\n  \"maximum_amount\": 750.00\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles/1043","description":"<h1 id=\"update-decline-salvage-profile\">Update Decline Salvage Profile</h1>\n<p><strong>Partially update an existing decline salvage profile.</strong></p>\n<p>Applies a partial (PATCH) update to the profile identified by <code>{profile_id}</code>. Every field is optional; only the fields you send are validated and saved. The lookup is account-scoped, so updating a profile that does not belong to the authenticated account returns <code>404</code>. The full updated profile (including <code>retry_schedule</code> and <code>excluded_decline_codes</code>) is returned.</p>\n<blockquote>\n<p><strong>Note on <code>salvage_type</code>:</strong> Changing <code>salvage_type</code> to <code>standard</code> does not re-apply the built-in schedule on update (the default schedule is only seeded at creation). To change retry timing on an existing profile, send an explicit <code>retry_schedule</code>.</p>\n</blockquote>\n<blockquote>\n<p><strong>Note on <code>is_default</code>:</strong> Setting <code>is_default</code> to <code>true</code> unsets the default flag on all other profiles in your account.</p>\n</blockquote>\n<h2 id=\"authorization\">Authorization</h2>\n<p>Bearer Token from collection Spark CRM</p>\n<p><strong>Required permission:</strong> <code>api:decline_salvage_profiles.update</code></p>\n<h2 id=\"request-body\">Request Body</h2>\n<p>All fields are optional. When a field is present it must satisfy the same rules as on create.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request Field</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>name</code></td>\n<td><em><strong>string (optional)</strong></em> Profile name. When present it cannot be empty. Max 255 characters.</td>\n</tr>\n<tr>\n<td><code>salvage_type</code></td>\n<td><em><strong>string (optional)</strong></em> One of <code>standard</code> or <code>custom</code>.</td>\n</tr>\n<tr>\n<td><code>transaction_type</code></td>\n<td><em><strong>string (optional)</strong></em> One of <code>initial</code>, <code>rebill</code>, or <code>both</code>.</td>\n</tr>\n<tr>\n<td><code>is_active</code></td>\n<td><em><strong>boolean (optional)</strong></em> Whether the profile is enabled.</td>\n</tr>\n<tr>\n<td><code>is_default</code></td>\n<td><em><strong>boolean (optional)</strong></em> Mark as account default. Setting <code>true</code> unsets the default on all other profiles.</td>\n</tr>\n<tr>\n<td><code>auto_apply_to_new</code></td>\n<td><em><strong>boolean (optional)</strong></em> Auto-apply to newly created campaigns.</td>\n</tr>\n<tr>\n<td><code>fire_affiliate_pixels</code></td>\n<td><em><strong>boolean (optional)</strong></em> Fire affiliate pixels on successful salvage.</td>\n</tr>\n<tr>\n<td><code>retry_schedule</code></td>\n<td><em><strong>array (optional)</strong></em> Ordered list of <code>{ attempt, delay }</code> retry steps (delay in minutes). Send this to change retry timing.</td>\n</tr>\n<tr>\n<td><code>retry_schedule[].attempt</code></td>\n<td><em><strong>integer</strong></em> The attempt number this step applies to.</td>\n</tr>\n<tr>\n<td><code>retry_schedule[].delay</code></td>\n<td><em><strong>integer</strong></em> Delay in minutes before this attempt.</td>\n</tr>\n<tr>\n<td><code>max_attempts</code></td>\n<td><em><strong>integer (optional)</strong></em> Maximum retry attempts. Min <code>1</code>.</td>\n</tr>\n<tr>\n<td><code>minimum_retry_interval</code></td>\n<td><em><strong>integer (optional)</strong></em> Minimum delay before the first retry, in minutes. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>maximum_retry_window</code></td>\n<td><em><strong>integer (optional)</strong></em> Maximum retry window, in minutes. Min <code>0</code>.</td>\n</tr>\n<tr>\n<td><code>excluded_decline_codes</code></td>\n<td><em><strong>array (optional)</strong></em> Decline codes excluded from salvage. Each entry is a string, max 100 characters.</td>\n</tr>\n<tr>\n<td><code>excluded_decline_codes[]</code></td>\n<td><em><strong>string</strong></em> A single decline code. Max 100 characters.</td>\n</tr>\n<tr>\n<td><code>minimum_amount</code></td>\n<td><em><strong>numeric (optional)</strong></em> Lower amount bound. Min <code>0</code>. Stored with 2 decimal places.</td>\n</tr>\n<tr>\n<td><code>maximum_amount</code></td>\n<td><em><strong>numeric (optional)</strong></em> Upper amount bound. Min <code>0</code>. Stored with 2 decimal places.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"response\">Response</h2>\n<p>Returns <code>success: true</code>, a <code>message</code>, and the full updated profile in <code>data</code> (detailed shape, including <code>retry_schedule</code> and <code>excluded_decline_codes</code>).</p>\n<h2 id=\"errors\">Errors</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>403</code></td>\n<td>Token lacks the <code>api:decline_salvage_profiles.update</code> (or legacy <code>api:update</code>) permission.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td>No profile with that <code>internal_id</code> exists for the authenticated account. Returns <code>message: \"Decline salvage profile not found\"</code>.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td>Validation error on a supplied field. Returns <code>message: \"Validation error\"</code> and an <code>errors</code> object.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"example\">Example</h2>\n<p><code>PATCH /v1/decline-salvage-profiles/1043</code> with the request body shown returns the <code>200</code> response below.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"protocol":"https","path":["v1","decline-salvage-profiles","1043"],"host":["api","sparkcrm","io"],"query":[],"variable":[]}},"response":[{"id":"8600cfec-d7bf-f1e0-addd-ddd69676813f","name":"Update Decline Salvage Profile","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"name\": \"Aggressive Recovery v2\",\n  \"is_active\": true,\n  \"is_default\": true,\n  \"max_attempts\": 5,\n  \"minimum_retry_interval\": 20,\n  \"maximum_retry_window\": 5760,\n  \"excluded_decline_codes\": [\"fraud\", \"stolen_card\"],\n  \"minimum_amount\": 5.00,\n  \"maximum_amount\": 750.00\n}","options":{"raw":{"language":"json"}}},"url":"https://api.sparkcrm.io/v1/decline-salvage-profiles/1043","description":"# Update Decline Salvage Profile\n\n**Partially update an existing decline salvage profile.**\n\nApplies a partial (PATCH) update to the profile identified by `{profile_id}`. Every field is optional; only the fields you send are validated and saved. The lookup is account-scoped, so updating a profile that does not belong to the authenticated account returns `404`. The full updated profile (including `retry_schedule` and `excluded_decline_codes`) is returned.\n\n> **Note on `salvage_type`:** Changing `salvage_type` to `standard` does not re-apply the built-in schedule on update (the default schedule is only seeded at creation). To change retry timing on an existing profile, send an explicit `retry_schedule`.\n\n> **Note on `is_default`:** Setting `is_default` to `true` unsets the default flag on all other profiles in your account.\n\n## Authorization\n\nBearer Token from collection Spark CRM\n\n**Required permission:** `api:decline_salvage_profiles.update`\n\n## Request Body\n\nAll fields are optional. When a field is present it must satisfy the same rules as on create.\n\n| Request Field | Description |\n| --- | --- |\n| `name` | _**string (optional)**_ Profile name. When present it cannot be empty. Max 255 characters. |\n| `salvage_type` | _**string (optional)**_ One of `standard` or `custom`. |\n| `transaction_type` | _**string (optional)**_ One of `initial`, `rebill`, or `both`. |\n| `is_active` | _**boolean (optional)**_ Whether the profile is enabled. |\n| `is_default` | _**boolean (optional)**_ Mark as account default. Setting `true` unsets the default on all other profiles. |\n| `auto_apply_to_new` | _**boolean (optional)**_ Auto-apply to newly created campaigns. |\n| `fire_affiliate_pixels` | _**boolean (optional)**_ Fire affiliate pixels on successful salvage. |\n| `retry_schedule` | _**array (optional)**_ Ordered list of `{ attempt, delay }` retry steps (delay in minutes). Send this to change retry timing. |\n| `retry_schedule[].attempt` | _**integer**_ The attempt number this step applies to. |\n| `retry_schedule[].delay` | _**integer**_ Delay in minutes before this attempt. |\n| `max_attempts` | _**integer (optional)**_ Maximum retry attempts. Min `1`. |\n| `minimum_retry_interval` | _**integer (optional)**_ Minimum delay before the first retry, in minutes. Min `0`. |\n| `maximum_retry_window` | _**integer (optional)**_ Maximum retry window, in minutes. Min `0`. |\n| `excluded_decline_codes` | _**array (optional)**_ Decline codes excluded from salvage. Each entry is a string, max 100 characters. |\n| `excluded_decline_codes[]` | _**string**_ A single decline code. Max 100 characters. |\n| `minimum_amount` | _**numeric (optional)**_ Lower amount bound. Min `0`. Stored with 2 decimal places. |\n| `maximum_amount` | _**numeric (optional)**_ Upper amount bound. Min `0`. Stored with 2 decimal places. |\n\n## Response\n\nReturns `success: true`, a `message`, and the full updated profile in `data` (detailed shape, including `retry_schedule` and `excluded_decline_codes`).\n\n## Errors\n\n| Status | Meaning |\n| --- | --- |\n| `403` | Token lacks the `api:decline_salvage_profiles.update` (or legacy `api:update`) permission. |\n| `404` | No profile with that `internal_id` exists for the authenticated account. Returns `message: \"Decline salvage profile not found\"`. |\n| `422` | Validation error on a supplied field. Returns `message: \"Validation error\"` and an `errors` object. |\n\n## Example\n\n`PATCH /v1/decline-salvage-profiles/1043` with the request body shown returns the `200` response below."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"data\": {\n    \"id\": 1043,\n    \"name\": \"Aggressive Recovery v2\",\n    \"salvage_type\": \"custom\",\n    \"transaction_type\": \"both\",\n    \"is_active\": true,\n    \"is_default\": true,\n    \"auto_apply_to_new\": false,\n    \"fire_affiliate_pixels\": true,\n    \"max_attempts\": 5,\n    \"minimum_retry_interval\": 20,\n    \"maximum_retry_window\": 5760,\n    \"minimum_amount\": \"5.00\",\n    \"maximum_amount\": \"750.00\",\n    \"created_at\": \"2026-06-16T15:08:33.000000Z\",\n    \"updated_at\": \"2026-06-16T15:41:02.000000Z\",\n    \"retry_schedule\": [\n      { \"attempt\": 1, \"delay\": 30 },\n      { \"attempt\": 2, \"delay\": 120 },\n      { \"attempt\": 3, \"delay\": 360 }\n    ],\n    \"excluded_decline_codes\": [\"fraud\", \"stolen_card\"]\n  },\n  \"success\": true,\n  \"message\": \"Decline salvage profile updated successfully\"\n}"}],"_postman_id":"62d74d48-991f-191d-bc3c-b83af4f58376"}],"id":"68830cec-a89f-e926-36e9-b1f2cd9de10f","_postman_id":"68830cec-a89f-e926-36e9-b1f2cd9de10f","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}}],"id":"c4f0fc4e-e02d-4dcd-9588-fad410f8bb95","description":"<h1 id=\"spark-crm-rest-api\">Spark CRM REST API</h1>\n<p>The <strong>REST API</strong> is used to create, read, update, and delete all system resources, so companies can build truly headless e-commerce experiences without having to do all the integrations Spark has already done.</p>\n<p>This comprehensive API provides full access to your Spark CRM resources including campaigns, products, orders, customers, and more. Designed with flexibility in mind, the REST API enables developers to build custom integrations, dashboards, and automated workflows while leveraging Spark's powerful e-commerce infrastructure. The API follows RESTful conventions and returns consistent JSON responses across all endpoints.</p>\n<p><a href=\"https://app.sparkcrm.io/register\">Register for a Spark CRM account to get started</a></p>\n<h2 id=\"api-authentication\">API Authentication</h2>\n<h3 id=\"getting-your-api-key\">Getting Your API Key</h3>\n<ol>\n<li>Login to your Spark Account</li>\n<li>Navigate to Settings &gt; API Keys</li>\n<li>Click \"Generate API Key\"</li>\n<li>Copy your newly generated API key</li>\n<li>Store this key securely - it will only be shown once</li>\n</ol>\n<h3 id=\"using-your-api-key\">Using Your API Key</h3>\n<p>Include your API key in all requests as a Bearer token in the Authorization header:\n<code>Authorization: Bearer YOUR_API_KEY_HERE</code></p>\n<p>All authenticated endpoints require this header to be present with a valid API key.</p>\n<h3 id=\"content-type-and-accept-headers\">Content-Type And Accept Headers</h3>\n<p>This is a JSON API and requires proper headers for all requests:</p>\n<ul>\n<li>All requests must include <code>Content-Type: application/json</code></li>\n<li>All requests must include <code>Accept: application/json</code></li>\n</ul>\n<p>If these headers are not included, the API will return a 400 Bad Request response with an error message indicating which header is missing or incorrect, such as \"Content-Type must be application/json\" or \"Accept must be application/json\".</p>\n<h3 id=\"api-permissions\">API Permissions</h3>\n<p>Different API endpoints require specific permissions. Your API key must have the appropriate permissions assigned to access each endpoint:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Permission</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>api:campaigns.view_any</code></td>\n<td>View all campaigns</td>\n</tr>\n<tr>\n<td><code>api:campaigns.view</code></td>\n<td>View specific campaigns</td>\n</tr>\n<tr>\n<td><code>api:campaigns.products.view</code></td>\n<td>View campaign products (offers and upsells)</td>\n</tr>\n</tbody>\n</table>\n</div><p>If your API key lacks the necessary permissions, you'll receive a 403 Forbidden response with the message \"Unauthorized. Token lacks the necessary permissions.\"</p>\n<h3 id=\"rate-and-usage-limits\">Rate and Usage Limits</h3>\n<p>To ensure system stability and fair usage, API requests are subject to the below rate limiting per account:</p>\n<ul>\n<li>100 requests per minute is default</li>\n<li>Enterprise accounts can be set to custom rate limits (e.g. 1,000 requests per minute and beyond). To increase rate limits please email <a href=\"mailto:hello@sparkcrm.io\">hello@sparkcrm.io</a>.</li>\n</ul>\n<p>When a rate limit is exceeded, the API will return a 429 Too Many Requests response with the following headers:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Header</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>X-RateLimit-Limit</td>\n<td>The maximum number of requests that the consumer is permitted to make per minute. Default to 100 requests per minute. Please contact support if you need a higher quota.</td>\n</tr>\n<tr>\n<td>X-RateLimit-Remaining</td>\n<td>The number of requests remaining in the current rate limit window.</td>\n</tr>\n<tr>\n<td>X-RateLimit-Reset</td>\n<td>The time in milliseconds until the current window resets.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"base-url\">Base URL</h2>\n<p>All REST API requests should be made to:\n<code>https://api.sparkcrm.io/v1</code></p>\n<h2 id=\"pagination\">Pagination</h2>\n<p>List endpoints support pagination to help you manage large datasets efficiently:</p>\n<h3 id=\"pagination-parameters\">Pagination Parameters</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Type</th>\n<th>Default</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>per_page</code></td>\n<td>integer</td>\n<td>15</td>\n<td>Number of items per page (max: 15)</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>integer</td>\n<td>1</td>\n<td>Page number to retrieve</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"pagination-response\">Pagination Response</h3>\n<p>Paginated responses include a <code>pagination</code> object with the following structure:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": [...],\n  \"pagination\": {\n    \"total\": 150,\n    \"per_page\": 15,\n    \"current_page\": 1,\n    \"last_page\": 10,\n    \"from\": 1,\n    \"to\": 15\n  }\n}\n</code></pre>\n<h2 id=\"filtering-and-search\">Filtering and Search</h2>\n<p>Many endpoints support filtering and search capabilities:</p>\n<h3 id=\"common-filter-parameters\">Common Filter Parameters</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>is_active</code></td>\n<td>boolean</td>\n<td>Filter by active status</td>\n</tr>\n<tr>\n<td><code>search</code></td>\n<td>string</td>\n<td>Search across relevant text fields</td>\n</tr>\n<tr>\n<td><code>category_id</code></td>\n<td>integer</td>\n<td>Filter by category</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"search-behavior\">Search Behavior</h3>\n<p>Search parameters typically perform partial matches across multiple fields (e.g., name, internal_id) using SQL LIKE operations.</p>\n<h2 id=\"resource-identification\">Resource Identification</h2>\n<p>Resources can be identified using multiple identifiers for flexibility:</p>\n<h3 id=\"campaign-identifiers\">Campaign Identifiers</h3>\n<ul>\n<li><strong>Internal ID</strong>: Numeric identifier (e.g., <code>123</code>)</li>\n<li><strong>UUID</strong>: Universal unique identifier (e.g., <code>550e8400-e29b-41d4-a716-446655440000</code>)</li>\n</ul>\n<p>The API automatically detects the identifier type - numeric values are treated as internal IDs, while non-numeric values are treated as UUIDs.</p>\n<h2 id=\"errors\">Errors</h2>\n<p>Spark CRM uses conventional HTTP response codes to indicate the success or failure of an API request. In general:</p>\n<ul>\n<li>Codes in the <code>2xx</code> range indicate success</li>\n<li>Codes in the <code>4xx</code> range indicate an error that failed given the information provided (e.g., a required parameter was omitted, invalid object passed, etc.)</li>\n<li>Codes in the <code>5xx</code> range indicate an error with Spark CRM's servers (these are rare)</li>\n</ul>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>HTTP STATUS CODE</th>\n<th>SUMMARY</th>\n<th>DESCRIPTION</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>OK</td>\n<td>Everything worked as expected.</td>\n</tr>\n<tr>\n<td>201</td>\n<td>Created</td>\n<td>Resource was successfully created.</td>\n</tr>\n<tr>\n<td>400</td>\n<td>Bad Request</td>\n<td>The request was unacceptable, often due to missing a required parameter.</td>\n</tr>\n<tr>\n<td>401</td>\n<td>Unauthorized</td>\n<td>No valid API key provided.</td>\n</tr>\n<tr>\n<td>403</td>\n<td>Forbidden</td>\n<td>The API key doesn't have permissions to perform the request.</td>\n</tr>\n<tr>\n<td>404</td>\n<td>Not Found</td>\n<td>The requested resource doesn't exist.</td>\n</tr>\n<tr>\n<td>422</td>\n<td>Validation Error</td>\n<td>The request was well-formed but was unable to be followed due to validation errors.</td>\n</tr>\n<tr>\n<td>429</td>\n<td>Too Many Requests</td>\n<td>Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.</td>\n</tr>\n<tr>\n<td>500, 502, 503, 504</td>\n<td>Server Errors</td>\n<td>Something went wrong on Spark CRM's end. (These are rare.)</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"example-error-response\">Example Error Response</h3>\n<p>All <code>4xx</code> and <code>5xx</code> errors return an error message via the \"errors\" field.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": false,\n  \"message\": \"Validation error\",\n  \"errors\": {\n    \"identifier\": [\n      \"The identifier field is required.\"\n    ],\n    \"per_page\": [\n      \"The per page field must be between 1 and 15.\"\n    ]\n  }\n}\n</code></pre>\n<h3 id=\"null-values\">Null Values</h3>\n<p>If there is no data for a response field, the API will use <code>null</code> for that field's value.</p>\n<h2 id=\"response-format\">Response Format</h2>\n<p>All API responses follow a consistent format:</p>\n<h3 id=\"success-response-structure\">Success Response Structure</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": true,\n  \"data\": {...},\n  \"pagination\": {...} // Only present for paginated responses\n}\n</code></pre>\n<h3 id=\"error-response-structure\">Error Response Structure</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"success\": false,\n  \"message\": \"Error description\",\n  \"errors\": {...}, // Validation errors (when applicable)\n  \"error\": \"Technical error message\" // Server errors (when applicable)\n}\n</code></pre>\n<h2 id=\"data-types-and-formats\">Data Types and Formats</h2>\n<h3 id=\"common-data-types\">Common Data Types</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Type</th>\n<th>Format</th>\n<th>Example</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Boolean</td>\n<td><code>true</code>/<code>false</code></td>\n<td><code>true</code></td>\n</tr>\n<tr>\n<td>Integer</td>\n<td>Whole numbers</td>\n<td><code>123</code></td>\n</tr>\n<tr>\n<td>String</td>\n<td>Text values</td>\n<td><code>\"Campaign Name\"</code></td>\n</tr>\n<tr>\n<td>Array</td>\n<td>List of values</td>\n<td><code>[\"USD\", \"EUR\", \"GBP\"]</code></td>\n</tr>\n<tr>\n<td>Object</td>\n<td>Nested data</td>\n<td><code>{\"id\": 1, \"name\": \"Category\"}</code></td>\n</tr>\n<tr>\n<td>Timestamp</td>\n<td>ISO 8601 format</td>\n<td><code>\"2024-01-15T10:30:00.000Z\"</code></td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"currency-and-amounts\">Currency and Amounts</h3>\n<ul>\n<li>All monetary amounts are represented as integers in the smallest currency unit (e.g., cents for USD)</li>\n<li>Example: $19.99 USD is represented as <code>1999</code></li>\n</ul>\n<h3 id=\"country-and-currency-codes\">Country and Currency Codes</h3>\n<ul>\n<li>Country codes follow ISO 3166-1 alpha-2 format (e.g., <code>\"US\"</code>, <code>\"CA\"</code>, <code>\"GB\"</code>)</li>\n<li>Currency codes follow ISO 4217 format (e.g., <code>\"USD\"</code>, <code>\"EUR\"</code>, <code>\"GBP\"</code>)</li>\n</ul>\n<h2 id=\"team-isolation\">Team Isolation</h2>\n<p>All API requests are automatically scoped to your team/account. You can only access resources that belong to your team, ensuring complete data isolation and security.</p>\n","_postman_id":"c4f0fc4e-e02d-4dcd-9588-fad410f8bb95","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}},{"name":"Enrichment","item":[{"name":"Email Validation","id":"7d07dd7d-233a-4414-864e-cf846f094051","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"description":"<h1 id=\"email-validation-response\">Email Validation Response</h1>\n<p>When email validation is enabled, the following structure is returned in the enrichment.email object:</p>\n<h2 id=\"response-fields\">Response Fields</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>is_valid</td>\n<td>boolean</td>\n<td>Whether the email address is valid and deliverable</td>\n</tr>\n<tr>\n<td>action_required</td>\n<td>string</td>\n<td>Required action to resolve issues. Values: email_update, email_confirmation, none</td>\n</tr>\n<tr>\n<td>message</td>\n<td>string</td>\n<td>Human-readable validation result message</td>\n</tr>\n<tr>\n<td>low_deliverability</td>\n<td>boolean</td>\n<td>Indicates if the email has known deliverability issues</td>\n</tr>\n<tr>\n<td>deliverability_score</td>\n<td>number</td>\n<td>Score from 0-1, where 1 indicates highest deliverability</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"common-validation-messages\">Common Validation Messages</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Message</th>\n<th>Action Required</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Email address is valid and deliverable</td>\n<td>none</td>\n<td>Email passed validation</td>\n</tr>\n<tr>\n<td>Email address is invalid</td>\n<td>email_update</td>\n<td>Email failed validation</td>\n</tr>\n<tr>\n<td>Domain accepts all email addresses</td>\n<td>email_confirmation</td>\n<td>Catch-all domain detected</td>\n</tr>\n<tr>\n<td>Unable to verify email address</td>\n<td>email_confirmation</td>\n<td>Validation inconclusive</td>\n</tr>\n<tr>\n<td>Email address is a spam trap</td>\n<td>email_update</td>\n<td>Known spam trap detected</td>\n</tr>\n<tr>\n<td>Email address is for abuse complaints</td>\n<td>email_confirmation</td>\n<td>Abuse/role email detected</td>\n</tr>\n<tr>\n<td>Email address is on suppression list</td>\n<td>email_update</td>\n<td>Email on bounce/complaint list</td>\n</tr>\n<tr>\n<td>Disposable email detected</td>\n<td>email_update</td>\n<td>Temporary email service</td>\n</tr>\n<tr>\n<td>Role-based email detected</td>\n<td>email_confirmation</td>\n<td>Generic email like info@, support@</td>\n</tr>\n<tr>\n<td>Low deliverability score</td>\n<td>email_confirmation</td>\n<td>Poor deliverability metrics</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"deliverability-score-ranges\">Deliverability Score Ranges</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Score Range</th>\n<th>Meaning</th>\n<th>Recommended Action</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0.8 - 1.0</td>\n<td>Excellent</td>\n<td>Process normally</td>\n</tr>\n<tr>\n<td>0.5 - 0.79</td>\n<td>Good</td>\n<td>Process with caution</td>\n</tr>\n<tr>\n<td>0.25 - 0.49</td>\n<td>Poor</td>\n<td>Request confirmation</td>\n</tr>\n<tr>\n<td>0 - 0.24</td>\n<td>Very Poor</td>\n<td>Require new email</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"query":[],"variable":[]},"url":""},"response":[{"id":"c9307aed-bc40-4cad-8650-9ec44f6642cc","name":"Email Validation Response","originalRequest":{"method":"GET","header":[],"url":""},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:21:35 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Server","value":"cloudflare"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-Xss-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"Cf-Cache-Status","value":"DYNAMIC"},{"key":"Content-Encoding","value":"br"},{"key":"CF-RAY","value":"9239fa083e7c72eb-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"}],"cookie":[],"responseTime":null,"body":"\"email\": {\n    \"is_valid\": false,\n    \"action_required\": \"email_update\",\n    \"message\": \"Email address is on suppression list (global suppression)\",\n    \"low_deliverability\": true,\n    \"deliverability_score\": 0\n}"}],"_postman_id":"7d07dd7d-233a-4414-864e-cf846f094051"},{"name":"Phone Validation","id":"52d9048c-ca3c-43a4-83df-e170fdf42445","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"description":"<h1 id=\"phone-validation-response\">Phone Validation Response</h1>\n<p>When phone validation is enabled, the following structure is returned in the enrichment.phone object:</p>\n<h2 id=\"response-fields\">Response Fields</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>is_valid</td>\n<td>boolean</td>\n<td>Whether the phone number is valid and callable</td>\n</tr>\n<tr>\n<td>action_required</td>\n<td>string</td>\n<td>Required action to resolve issues. Values: phone_update, phone_confirmation, none</td>\n</tr>\n<tr>\n<td>message</td>\n<td>string</td>\n<td>Validation result message</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"common-messages\">Common Messages</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Message</th>\n<th>Action Required</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Phone number validated successfully</td>\n<td>none</td>\n<td>Valid phone number</td>\n</tr>\n<tr>\n<td>Phone validation failed: INVALID</td>\n<td>phone_update</td>\n<td>Invalid phone number</td>\n</tr>\n<tr>\n<td>Phone validation failed: INVALID_BUT_POSSIBLE</td>\n<td>phone_confirmation</td>\n<td>Format could be valid</td>\n</tr>\n<tr>\n<td>Phone number not found</td>\n<td>phone_update</td>\n<td>Number doesn't exist</td>\n</tr>\n<tr>\n<td>No phone number provided</td>\n<td>phone_update</td>\n<td>Missing phone field</td>\n</tr>\n<tr>\n<td>VOIP phone detected</td>\n<td>phone_confirmation</td>\n<td>Voice over IP number</td>\n</tr>\n<tr>\n<td>Prepaid phone detected</td>\n<td>phone_confirmation</td>\n<td>Prepaid service detected</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"query":[],"variable":[]},"url":""},"response":[{"id":"c15cab4d-0584-4488-aa47-95bf82ac2ce0","name":"Phone Validation Response","originalRequest":{"method":"GET","header":[],"url":""},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:21:35 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Server","value":"cloudflare"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-Xss-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"Cf-Cache-Status","value":"DYNAMIC"},{"key":"Content-Encoding","value":"br"},{"key":"CF-RAY","value":"9239fa083e7c72eb-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"}],"cookie":[],"responseTime":null,"body":"\"phone\": {\n    \"is_valid\": false,\n    \"action_required\": \"phone_update\",\n    \"message\": \"Phone validation failed: INVALID_BUT_POSSIBLE\"\n}"}],"_postman_id":"52d9048c-ca3c-43a4-83df-e170fdf42445"},{"name":"Address Verification","id":"556e7cf0-e53c-44d0-a37b-ce2141ddd117","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"description":"<h1 id=\"address-verification-response\">Address Verification Response</h1>\n<p>When address verification is enabled, the following structure is returned in the enrichment.address object:</p>\n<h2 id=\"response-fields\">Response Fields</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>standardized</td>\n<td>object</td>\n<td>Standardized version of the address</td>\n</tr>\n<tr>\n<td>standardized.street_1</td>\n<td>string</td>\n<td>Standardized primary address line</td>\n</tr>\n<tr>\n<td>standardized.street_2</td>\n<td>string</td>\n<td>Standardized secondary address line</td>\n</tr>\n<tr>\n<td>standardized.city</td>\n<td>string</td>\n<td>Standardized city name</td>\n</tr>\n<tr>\n<td>standardized.state</td>\n<td>string</td>\n<td>Standardized state abbreviation</td>\n</tr>\n<tr>\n<td>standardized.postal_code</td>\n<td>string</td>\n<td>5-digit ZIP code</td>\n</tr>\n<tr>\n<td>standardized.plus4</td>\n<td>string</td>\n<td>ZIP+4 extension for precise delivery</td>\n</tr>\n<tr>\n<td>action_available</td>\n<td>string</td>\n<td>Optional improvement available. Values: address_standardization, none</td>\n</tr>\n<tr>\n<td>action_required</td>\n<td>string</td>\n<td>Required action. Values: apartment_number, address_update, none</td>\n</tr>\n<tr>\n<td>message</td>\n<td>string</td>\n<td>Human-readable verification result</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"common-messages\">Common Messages</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Message</th>\n<th>Action</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Address validated successfully</td>\n<td>none</td>\n<td>Address verified and deliverable</td>\n</tr>\n<tr>\n<td>Address validation failed</td>\n<td>address_update</td>\n<td>Could not verify address</td>\n</tr>\n<tr>\n<td>Address not found</td>\n<td>address_update</td>\n<td>Street address doesn't exist</td>\n</tr>\n<tr>\n<td>Apartment or suite number may be missing</td>\n<td>apartment_number</td>\n<td>Secondary address needed</td>\n</tr>\n<tr>\n<td>Invalid address</td>\n<td>address_update</td>\n<td>Address failed validation</td>\n</tr>\n<tr>\n<td>Address not deliverable</td>\n<td>address_update</td>\n<td>Valid but undeliverable</td>\n</tr>\n<tr>\n<td>Vacant address detected</td>\n<td>address_confirmation</td>\n<td>Address is vacant</td>\n</tr>\n<tr>\n<td>Reship center detected</td>\n<td>address_confirmation</td>\n<td>Package forwarding service</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}},"urlObject":{"query":[],"variable":[]},"url":""},"response":[{"id":"2d384d9d-02ae-4bce-8a28-4966789267bb","name":"Address Verification Response","originalRequest":{"method":"GET","header":[],"url":""},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Date","value":"Fri, 21 Mar 2025 02:21:35 GMT"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"Server","value":"cloudflare"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"X-Frame-Options","value":"SAMEORIGIN"},{"key":"X-Xss-Protection","value":"1; mode=block"},{"key":"X-Content-Type-Options","value":"nosniff"},{"key":"Cf-Cache-Status","value":"DYNAMIC"},{"key":"Content-Encoding","value":"br"},{"key":"CF-RAY","value":"9239fa083e7c72eb-ORD"},{"key":"alt-svc","value":"h3=\":443\"; ma=86400"}],"cookie":[],"responseTime":null,"body":"\"address\": {\n    \"standardized\": {\n        \"street_1\": \"123 S Main St Apt 4B\",\n        \"street_2\": \"\",\n        \"city\": \"Los Angeles\",\n        \"state\": \"CA\",\n        \"postal_code\": \"90012\",\n        \"plus4\": \"3701\"\n    },\n    \"action_available\": \"address_standardization\",\n    \"action_required\": \"apartment_number\",\n    \"message\": \"Apartment or suite number may be missing\"\n}"}],"_postman_id":"556e7cf0-e53c-44d0-a37b-ce2141ddd117"}],"id":"f0661368-c1f5-4053-abcb-c1b13f056a79","description":"<h1 id=\"data-enrichment--validation\">Data Enrichment &amp; Validation</h1>\n<p>Spark CRM's enrichment services provide real-time validation and standardization for customer data during checkout. When enabled, these services automatically validate email addresses, phone numbers, and shipping addresses to reduce fraud, improve deliverability, and ensure accurate fulfillment.</p>\n<h2 id=\"service-activation\">Service Activation</h2>\n<p>To use enrichment services:</p>\n<ol>\n<li>Login to your Spark Account</li>\n<li>Navigate to Billing &gt; Manage Services</li>\n<li>Enable the desired services:<ul>\n<li>Email Validation</li>\n<li>Phone Validation</li>\n<li>Address Verification</li>\n</ul>\n</li>\n</ol>\n<h2 id=\"how-it-works\">How It Works</h2>\n<p>When enrichment services are enabled:</p>\n<ul>\n<li><strong>Automatic Enrichment</strong>: Data validation occurs automatically during order creation and payment processing</li>\n<li><strong>Selective Response</strong>: Only enabled services appear in the <code>enrichment</code> response object</li>\n<li><strong>Action Guidance</strong>: Each service provides specific action recommendations when issues are detected</li>\n</ul>\n<h2 id=\"affected-endpoints\">Affected Endpoints</h2>\n<p>Enrichment data is automatically included in responses from:</p>\n<ul>\n<li><code>POST /checkout/orders</code> - Create Order</li>\n<li><code>POST /checkout/orders/payment</code> - Process Payment</li>\n<li><code>POST /checkout/leads</code> - Create Lead (when <code>enrich=true</code> parameter is included)</li>\n<li><code>GET /checkout/orders</code> - Search Orders (for orders processed with enrichment enabled)</li>\n</ul>\n<h2 id=\"pricing\">Pricing</h2>\n<p>Each enrichment service is billed per validation. Contact <a href=\"mailto:support@sparkcrm.io\">support@sparkcrm.io</a> for pricing details.</p>\n","_postman_id":"f0661368-c1f5-4053-abcb-c1b13f056a79","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]},"isInherited":true,"source":{"_postman_id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","id":"53f3b62c-89a1-4d64-8456-aac75f451f9c","name":"Spark CRM","type":"collection"}}}],"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":""}]}},"event":[{"listen":"prerequest","script":{"id":"d3d7ec52-5d69-440f-8239-1f5fc232dfac","type":"text/javascript","packages":{},"exec":[""]}},{"listen":"test","script":{"id":"93ee4ca0-d48e-4b11-8412-a2ae392a252b","type":"text/javascript","packages":{},"exec":[""]}}],"variable":[{"id":"93302e77-7d5f-496d-8f18-e6ed3daebb74","key":"api_token","value":"","type":"string"}]}