# Agentic Commerce Protocol Checkout Guide Source: https://docs.stateset.com/agentic-commerce/agentic-commerce-checkout-guide Learn how to use the Agentic Commerce Protocol to create, update, and complete checkout flows. # Build the Agentic Commerce Protocol checkout endpoints Learn about the Agentic Commerce Protocol specification. You can use the Agentic Commerce Protocol (ACP) to enable AI agents to manage commerce transactions between buyers and sellers. This specification defines the methods and data structures for creating, updating, and completing checkout flows. You can find examples for REST integrations below. ACP is the transaction layer of StateSet’s agentic commerce offering. For the full conversation‑to‑fulfillment architecture, see Stateset iCommerce Architecture. ## Create a Checkout Session You can create a new Checkout Session with buyer details, line items, and shipping information. ### Request Specify the parameters required for your request. | Parameter | Type | Description | | ------------------------ | ----------------- | ------------------------------------------- | | **items** | `array` | Array of items you can purchase. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **fulfillment\_address** | `hash` (optional) | Address where the order will ship. | **Example request:** ```json theme={null} POST /checkouts { "items": [ { "id": "item_123", "quantity": 2 } ], "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "fulfillment_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" } } ``` ### Response The response returns the current state of the checkout from the seller. | Parameter | Type | Description | | --------------------- | ----------------- | ------------------------------------------------------------- | | **id** | `string` | Unique identifier for the Checkout Session. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **payment\_provider** | `hash` (optional) | Payment provider configuration and supported payment methods. | | **status** | `string` | Current status of the checkout process. (Required) | Possible values: `not_ready_for_payment` | `ready_for_payment` | `completed` | `canceled` | `in_progress` | \| **currency** | `string` | Three-letter ISO currency code, in lowercase. (Required) | \| **line\_items** | `array` | Array of line items in the checkout process. (Required) | \| **fulfillment\_address** | `hash` (optional) | Address where the order will ship. | \| **fulfillment\_options** | `array` | Available shipping and fulfillment options. (Required) | \| **fulfillment\_option\_id** | `string` (optional) | ID of the currently selected fulfillment option. | \| **totals** | `array` | Overview of charges and discounts. (Required) | \| **messages** | `array` | Array of messages or notifications related to the checkout process. (Required) | \| **links** | `array` | Array of links related to the checkout process. (Required) | **Example response:** ```json theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "payment_provider": { "provider": "stripe", "supported_payment_methods": ["card"] }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 2 }, "base_amount": 2000, "discount": 0, "total": 2000, "subtotal": 2000, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 2000 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 2250 } ], "messages": [], "links": [] } ``` ## Retrieve a Checkout object To retrieve an existing Checkout Session using its ID, make a request to the appropriate API endpoint with the ID included in the request. ### Request Specify the parameters required for your request. | Parameter | Type | Description | | --------- | -------- | ------------------------------------------------------ | | **id** | `string` | Unique identifier for the checkout process. (Required) | **Example request:** ```json theme={null} GET /checkouts/:id ``` ### Response The response returns the current state of the checkout from the seller. | Parameter | Type | Description | | --------------------- | ----------------- | ------------------------------------------------------------- | | **id** | `string` | Unique identifier for the checkout session. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **payment\_provider** | `hash` (optional) | Payment provider configuration and supported payment methods. | | **status** | `string` | Current status of the checkout process. (Required) | Possible values: `not_ready_for_payment` | `ready_for_payment` | `completed` | `canceled` | `in_progress` | \| **currency** | `string` | Three-letter ISO currency code, in lowercase. (Required) | \| **line\_items** | `array` | Array of line items in the checkout process. (Required) | \| **fulfillment\_address** | `hash` (optional) | Address where the order will ship. | \| **fulfillment\_options** | `array` | Available shipping and fulfillment options. (Required) | \| **fulfillment\_option\_id** | `string` (optional) | ID of the currently selected fulfillment option. | \| **totals** | `array` | Overview of charges and discounts. (Required) | \| **messages** | `array` | Array of messages or notifications related to the checkout process. (Required) | \| **links** | `array` | Array of links related to the checkout process. (Required) | **Example response:** ```json theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "payment_provider": { "provider": "stripe", "supported_payment_methods": ["card"] }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 2 }, "base_amount": 2000, "discount": 0, "total": 2000, "subtotal": 2000, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 2000 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 2250 } ], "messages": [], "links": [] } ``` ## Update a Checkout Session You can update an existing Checkout Session by modifying line items, shipping address, or fulfillment options. ### Request Specify the parameters required for your request. | Parameter | Type | Description | | --------------------------- | ------------------- | ------------------------------------------------------ | | **id** | `string` | Unique identifier for the checkout process. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **items** | `array` (optional) | Updated array of items to be purchased. | | **fulfillment\_address** | `hash` (optional) | Updated fulfillment address. | | **fulfillment\_option\_id** | `string` (optional) | Identifier for the selected fulfillment option. | **Example request:** ```json theme={null} PUT /checkouts/:id { "items": [ { "id": "item_123", "quantity": 3 }, { "id": "item_456", "quantity": 1 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_option_id": "shipping_fast" } ``` ### Response The response returns the current state of the checkout from the seller. | Parameter | Type | Description | | --------------------- | ----------------- | ------------------------------------------------------------- | | **id** | `string` | Unique identifier for the Checkout Session. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **payment\_provider** | `hash` (optional) | Payment provider configuration and supported payment methods. | | **status** | `string` | Current status of the checkout process. (Required) | Possible values: `not_ready_for_payment` | `ready_for_payment` | `completed` | `canceled` | `in_progress` | \| **currency** | `string` | Three-letter ISO currency code, in lowercase. (Required) | \| **line\_items** | `array` | Array of line items in the checkout process. (Required) | \| **fulfillment\_address** | `hash` (optional) | Address where the order will ship. | \| **fulfillment\_options** | `array` | Available shipping and fulfillment options. (Required) | \| **fulfillment\_option\_id** | `string` (optional) | ID of the currently selected fulfillment option. | \| **totals** | `array` | Overview of charges and discounts. (Required) | \| **messages** | `array` | Array of messages or notifications related to the checkout process. (Required) | \| **links** | `array` | Array of links related to the checkout process. (Required) | **Example response:** ```json theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "payment_provider": { "provider": "stripe", "supported_payment_methods": ["card"] }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 3 }, "base_amount": 3000, "discount": 0, "total": 3000, "subtotal": 3000, "tax": 0 }, { "id": "item_456", "item": { "id": "item_456", "quantity": 1 }, "base_amount": 500, "discount": 0, "total": 500, "subtotal": 500, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 3500 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 3750 } ], "messages": [], "links": [] } ``` ## Complete a Checkout You can complete the checkout process by processing the payment and creating an order. ### Request Specify the parameters required for your request. | Parameter | Type | Description | | ----------------- | ----------------- | ----------------------------------------------------------------- | | **id** | `string` | Unique identifier for the checkout process. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **payment\_data** | `hash` | Payment method details for processing the transaction. (Required) | **Example request:** ```json theme={null} POST /checkouts/:id/complete { "payment_data": { "token": "spt_123", "provider": "stripe", "billing_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" } } } ``` ### Response The response returns the current state of the checkout from the seller. | Parameter | Type | Description | | --------------------- | ----------------- | ------------------------------------------------------------- | | **id** | `string` | Unique identifier for the Checkout Session. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **payment\_provider** | `hash` (optional) | Payment provider configuration and supported payment methods. | | **status** | `string` | Current status of the checkout process. (Required) | Possible values: `not_ready_for_payment` | `ready_for_payment` | `completed` | `canceled` | `in_progress` | \| **currency** | `string` | Three-letter ISO currency code, in lowercase. (Required) | \| **line\_items** | `array` | Array of line items in the checkout process. (Required) | \| **fulfillment\_address** | `hash` (optional) | Address where the order will ship. | \| **fulfillment\_options** | `array` | Available shipping and fulfillment options. (Required) | \| **fulfillment\_option\_id** | `string` (optional) | ID of the currently selected fulfillment option. | \| **totals** | `array` | Overview of charges and discounts. (Required) | \| **messages** | `array` | Array of messages or notifications related to the checkout process. (Required) | \| **links** | `array` | Array of links related to the checkout process. (Required) | **Example response:** ```json theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "status": "completed", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 3 }, "base_amount": 3000, "discount": 0, "total": 3000, "subtotal": 3000, "tax": 0 }, { "id": "item_456", "item": { "id": "item_456", "quantity": 1 }, "base_amount": 500, "discount": 0, "total": 500, "subtotal": 500, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 3500 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 3750 } ], "messages": [], "links": [] } ``` ## Cancel a Checkout You can cancel an existing Checkout Session if necessary. ### Request Specify the parameters required for your request. | Parameter | Type | Description | | --------- | -------- | ------------------------------------------------------ | | **id** | `string` | Unique identifier for the checkout process. (Required) | **Example request:** ```json theme={null} POST /checkouts/:id/cancel {} ``` ### Response The response returns the current state of the checkout from the seller. | Parameter | Type | Description | | --------------------- | ----------------- | ------------------------------------------------------------- | | **id** | `string` | Unique identifier for the Checkout Session. (Required) | | **buyer** | `hash` (optional) | Information about the buyer. | | **payment\_provider** | `hash` (optional) | Payment provider configuration and supported payment methods. | | **status** | `string` | Current status of the checkout process. (Required) | Possible values: `not_ready_for_payment` | `ready_for_payment` | `completed` | `canceled` | `in_progress` | \| **currency** | `string` | Three-letter ISO currency code, in lowercase. (Required) | \| **line\_items** | `array` | Array of line items in the checkout process. (Required) | \| **fulfillment\_address** | `hash` (optional) | Address where the order will ship. | \| **fulfillment\_options** | `array` | Available shipping and fulfillment options. (Required) | \| **fulfillment\_option\_id** | `string` (optional) | ID of the currently selected fulfillment option. | \| **totals** | `array` | Overview of charges and discounts. (Required) | \| **messages** | `array` | Array of messages or notifications related to the checkout process. (Required) | \| **links** | `array` | Array of links related to the checkout process. (Required) | **Example response:** ```json theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "status": "canceled", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 3 }, "base_amount": 3000, "discount": 0, "total": 3000, "subtotal": 3000, "tax": 0 }, { "id": "item_456", "item": { "id": "item_456", "quantity": 1 }, "base_amount": 500, "discount": 0, "total": 500, "subtotal": 500, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 3500 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 3750 } ], "messages": [ { "type": "info", "content_type": "plain", "content": "Checkout cancelled: Customer changed their mind" } ], "links": [] } ``` ## Data structures This section outlines the data structures involved in the checkout process. ### Buyer The buyer is an individual who initiates the purchase. | Parameter | Type | Description | | ----------------- | ------------------- | --------------------------------------- | | **first\_name** | `string` | The first name of the buyer. (Required) | | **last\_name** | `string` | The last name of the buyer. (Required) | | **email** | `string` | The email of the buyer. **Required** | | **phone\_number** | `string` (optional) | The phone number of the buyer. | ### Item The Item is a product or service that the buyer requests to purchase, along with its quantity. | Parameter | Type | Description | | ------------ | --------- | ---------------------------------------------------------------- | | **id** | `string` | Unique identifier for the item. (Required) | | **quantity** | `integer` | The requested quantity of the item for this checkout. (Required) | ### LineItem The LineItem includes provides about the item added to the checkout, including the amount. | Parameter | Type | Description | | ---------------- | --------- | ------------------------------------------------ | | **id** | `string` | Unique identifier for the line item. (Required) | | **item** | `hash` | The item details. (Required) | | **base\_amount** | `integer` | The base amount of the line item. (Required) | | **discount** | `integer` | The discount amount of the line item. (Required) | | **total** | `integer` | The total amount of the line item. (Required) | | **subtotal** | `integer` | The subtotal amount of the line item. (Required) | | **tax** | `integer` | The tax amount of the line item. (Required) | ### Address The Address provides the buyer’s shipping or billing address. | Parameter | Type | Description | | ---------------- | ------------------- | ------------------------------------------------------------------ | | **name** | `string` | Name of the person to whom the items are fulfilled. (Required) | | **line\_one** | `string` | Address line 1 (e.g., street, PO Box, or company name). (Required) | | **line\_two** | `string` (optional) | Address line 2 (e.g., apartment, suite, unit, or building). | | **city** | `string` | City, district, suburb, town, or village. (Required) | | **state** | `string` | State, county, province, or region. (Required) | | **country** | `string` | Two-letter country code (ISO 3166-1 alpha-2). (Required) | | **postal\_code** | `string` | ZIP or postal code. (Required) | ### PaymentData The PaymentData provides the buyer’s payment details, including the tokenized value and the payment provider. | Parameter | Type | Description | | -------------------- | ----------------- | ------------------------------------------------------------- | | **token** | `string` | The secure reference to a payment credential. (Required) | | **provider** | `string` | The payment provider that the payment data is for. (Required) | | **billing\_address** | `hash` (optional) | Billing address for the payment method. | ### Total The Total provides a summary of the overall total. | Parameter | Type | Description | | --------- | ------ | ----------------------------- | | **type** | `enum` | The type of total. (Required) | Possible values: `items_base_amount` | `items_discount` | `subtotal` | `discount` | `fulfillment` | `tax` | `fee` | `total` | \| **display\_text** | `string` | The display text for the total. (Required) | \| **amount** | `integer` | The amount of the total. (Required) | ### FulfillmentOption Fulfillment options are either shipping or digital. See [ShippingFulfillmentOption](https://docs.stripe.com/agentic-commerce/protocol/specification.md#shipping-fulfillment-option) and [DigitalFulfillmentOption](https://docs.stripe.com/agentic-commerce/protocol/specification.md#digital-fulfillment-option) for specific implementations. ### ShippingFulfillmentOption The ShippingFulfillmentOption defines the parameters for shipping fulfillment options, including the carrier information and delivery times. | Parameter | Type | Description | | --------- | ------ | ------------------------------------------ | | **type** | `enum` | The type of fulfillment option. (Required) | Possible values: `shipping` | \| **id** | `string` | Unique identifier for the shipping fulfillment option. (Required) | \| **title** | `string` | The title of the shipping fulfillment option. (Required) | \| **subtitle** | `string` (optional) | The subtitle of the shipping fulfillment option. | \| **carrier** | `string` (optional) | The carrier of the shipping fulfillment option. | \| **earliest\_delivery\_time** | `string` (optional) | The earliest delivery time of the shipping fulfillment option (ISO 8601 format). | \| **latest\_delivery\_time** | `string` (optional) | The latest delivery time of the shipping fulfillment option (ISO 8601 format). | \| **subtotal** | `integer` | The subtotal of the shipping fulfillment option. (Required) | \| **tax** | `integer` | The tax of the shipping fulfillment option. (Required) | \| **total** | `integer` | The total of the shipping fulfillment option. (Required) | ### DigitalFulfillmentOption The DigitalFulfillmentOption defines the parameters for digital fulfillment options, including the title and pricing information. | Parameter | Type | Description | | --------- | ------ | ------------------------------------------ | | **type** | `enum` | The type of fulfillment option. (Required) | Possible values: `digital` | \| **id** | `string` | Unique identifier for the digital fulfillment option. (Required) | \| **title** | `string` | The title of the digital fulfillment option. (Required) | \| **subtitle** | `string` (optional) | The subtitle of the digital fulfillment option. | \| **subtotal** | `integer` | The subtotal of the digital fulfillment option. (Required) | \| **tax** | `integer` | The tax of the digital fulfillment option. (Required) | \| **total** | `integer` | The total of the digital fulfillment option. (Required) | ### PaymentProvider The PaymentProvider defines the seller’s supported payment provider and available methods. | Parameter | Type | Description | | ------------ | -------- | ----------------------------------------- | | **provider** | `string` | The seller’s payment provider. (Required) | Possible values: `stripe` | \| **supported\_payment\_methods** | `array` | The payment methods allowed by the seller. (Required) Possible values: `card` | ### Message Messages are either informational or error messages. #### InfoMessage The InfoMessage represents informational messages, detailing the type and content. | Parameter | Type | Description | | --------- | ------ | --------------------------------------- | | **type** | `enum` | String value representing message type. | Possible values: `info` | \| **param** | `string` (optional) | RFC 9535 JSONPath to the component of the Checkout Session that the message references. | \| **content\_type** | `enum` (optional) | The type of content of the message. Possible values: `plain` | `markdown` | \| **content** | `string` | The content of the message. | #### ErrorMessage The ErrorMessage represents error messages, detailing the type and code. | Parameter | Type | Description | | --------- | ------ | --------------------------------------- | | **type** | `enum` | String value representing message type. | Possible values: `error` | \| **code** | `enum` | The code of the error. Possible values: `missing` | `invalid` | `out_of_stock` | `payment_declined` | `requires_sign_in` | `requires_3ds` | \| **param** | `string` (optional) | RFC 9535 JSONPath to the component of the Checkout Session that the message references. | \| **content\_type** | `enum` (optional) | The type of content of the message. Possible values: `plain` | `markdown` | \| **content** | `string` | The content of the message. | ### Error The Error defines the parameters related to errors occurring during the checkout process. | Parameter | Type | Description | | --------- | ------ | ----------------------------- | | **type** | `enum` | The type of error. (Required) | Possible values: `invalid_request` | `request_not_idempotent` | `processing_error` | `service_unavailable` | \| **code** | `string` | The implementation-defined error code. (Required) | \| **message** | `string` | The message of the error. (Required) | \| **param** | `string` (optional) | RFC 9535 JSONPath to the component of the Checkout Session that the message references. | ### Link The Link defines the parameters for links related to policies and agreements. | Parameter | Type | Description | | --------- | ------ | ------------------------------------------------------ | | **type** | `enum` | String value representing the type of link. (Required) | Possible values: `terms_of_use` | `privacy_policy` | `seller_shop_policies` | \| **url** | `string` | The URL of the link. (Required) | ### Order The Order provides the result of the checkout process and offers details to the buyer for order lookup. | Parameter | Type | Description | | ------------------------- | -------- | ---------------------------------------------------------------------------- | | **id** | `string` | Unique identifier for the order. (Required) | | **checkout\_session\_id** | `string` | Reference to the Checkout Session that the order originated from. (Required) | | **permalink\_url** | `string` | The permalink URL for the order. (Required) | ### Event The Event defines the parameters for events related to order creation and updates. | Parameter | Type | Description | | --------- | ------ | ----------------------------- | | **type** | `enum` | The type of event. (Required) | Possible values: `order_created` | `order_updated` | \| **data** | `hash` | Event data containing order information. (Required) | ### OrderEventData The OrderEventData includes data related to order events. | Parameter | Type | Description | | ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | | **type** | `string` | The string value represents the type of event data. For order data, use the value `order`. (Required) | | **checkout\_session\_id** | `string` | ID that identifies the Checkout Session that created this order. (Required) | | **permalink\_url** | `string` | The URL points to the order. Customers can visit this URL and provide their email address to view order details. (Required) | | **status** | `enum` | String representing the latest status of the order. (Required) | Possible values: `created` | `manual_review` | `confirmed` | `canceled` | `shipped` | `fulfilled` | \| **refunds** | `array` | List of refunds that have been issued for the order. (Required) | ### Refund The Refund defines the parameters for managing refunds associated with completed orders. | Parameter | Type | Description | | --------- | ------ | ------------------------------ | | **type** | `enum` | The type of refund. (Required) | Possible values: `store_credit` | `original_payment` | \| **amount** | `integer` | The amount of the refund. (Required) | # Create Account Source: https://docs.stateset.com/api-reference/accounts/create POST https://api.stateset.com/v1/accounts This endpoint creates a new account ### Body This is the id of the account. This is the account name of the account. This is the account notes of the account. This is the account subtype of the account. This is the account type of the account. This is the account owner of the account. This is the account source of the account. This is the annual revenue of the account. This is the avatar of the account. This is the billing city of the account. This is the billing country of the account. This is the billing latitude of the account. This is the billing longitude of the account. This is the billing state of the account. This is the billing street of the account. This is the created at of the account. This is the description of the account. This is the employees of the account. This is the fax of the account. This is the industry of the account. This is the is active of the account. This is the is public of the account. ### Response This is the id of the account. This is the account name of the account. This is the account notes of the account. This is the account subtype of the account. This is the account type of the account. This is the account owner of the account. This is the account source of the account. This is the annual revenue of the account. This is the avatar of the account. This is the billing city of the account. This is the billing country of the account. This is the billing latitude of the account. This is the billing longitude of the account. This is the billing state of the account. This is the billing street of the account. This is the created at of the account. This is the description of the account. This is the employees of the account. This is the fax of the account. This is the industry of the account. This is the is active of the account. This is the is public of the account. This is the last modified by of the account. This is the number of employees of the account. This is the ownership of the account. This is the phone of the account. This is the rating of the account. This is the shipping city of the account. This is the shipping country of the account. This is the shipping latitude of the account. This is the shipping longitude of the account. This is the shipping state of the account. This is the shipping street of the account. This is the sic code of the account. This is the ticker symbol of the account. This is the website of the account. This is the year started of the account. This is the zip code of the account. This is the created by of the account. This is the updated by of the account. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/account' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```graphQL graphQL theme={null} mutation ( $account: accounts_insert_input! ) { insert_accounts ( objects: [$account] ) { returning { id{ accountName accountType rating industry contacts { id firstName lastName email phone controller processor account_id } } } } ``` ```javascript Node.js theme={null} const acccount = await stateset.account.create({ accountName: 'Example 1', accountType: 'Example 1', rating: 'Example 1', industry: 'Example 1', }); ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Delete Account Source: https://docs.stateset.com/api-reference/accounts/delete DELETE https://api.return.com/v1/accounts This endpoint deletes an existing account. ### Body The ID provided in the data tab may be used to identify the account ### Response The ID provided in the data tab may be used to identify the account The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/accounts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation { delete_accounts( where: { id: { _eq: "" } } ) { affected_rows } } ``` ```javascript Node.js theme={null} var deleted = await stateset.accounts.del({ "1" }); ``` ```json Response theme={null} { { "data": { "delete_accounts": { "affected_rows": 1 } } } } ``` # Get Account Source: https://docs.stateset.com/api-reference/accounts/get GET https://api.stateset.com/v1/accounts/:id This endpoint gets or creates a new account. ### Body This is the id of the account. ### Response This is the id of the account. This is the account name of the account. This is the account notes of the account. This is the account subtype of the account. This is the account type of the account. This is the account owner of the account. This is the account source of the account. This is the annual revenue of the account. This is the avatar of the account. This is the billing city of the account. This is the billing country of the account. This is the billing latitude of the account. This is the billing longitude of the account. This is the billing state of the account. This is the billing street of the account. This is the created at of the account. This is the description of the account. This is the employees of the account. This is the fax of the account. This is the industry of the account. This is the is active of the account. This is the is public of the account. This is the last modified by of the account. This is the number of employees of the account. This is the ownership of the account. This is the phone of the account. This is the rating of the account. This is the shipping city of the account. This is the shipping country of the account. This is the shipping latitude of the account. This is the shipping longitude of the account. This is the shipping state of the account. This is the shipping street of the account. This is the sic code of the account. This is the ticker symbol of the account. This is the website of the account. This is the year started of the account. This is the zip code of the account. This is the created by of the account. This is the updated by of the account. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/customer' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "count": 1, "next": null, "previous": null, "results": [ { "id": "1", "accountName": "Test Account", "accountNotes": "Test Account Notes", "accountSubtype": "Test Account Subtype", "accountType": "Test Account Type", "account_owner": "Test Account Owner", "account_source": "Test Account Source", "annualRevenue": "Test Annual Revenue", "avatar": "Test Avatar", "billingCity": "Test Billing City", "billingCountry": "Test Billing Country", "billingLatitude": "Test Billing Latitude", "billingLongitude": "Test Billing Longitude", "billingState": "Test Billing State", "billingStreet": "Test Billing Street", "created_at": "2021-04-27T15:00:00.000000Z", "description": "Test Description", "employees": "Test Employees", "fax": "Test Fax", "industry": "Test Industry", "is_active": true, "is_public": true, "last_modified_by": "Test Last Modified By", "numberOfEmployees": "Test Number Of Employees", "ownership": "Test Ownership", "phone": "Test Phone", "rating": "Test Rating", "shippingCity": "Test Shipping City", "shippingCountry": "Test Shipping Country", "shippingLatitude": "Test Shipping Latitude", "shippingLongitude": "Test Shipping Longitude", "shippingState": "Test Shipping State", "shippingStreet": "Test Shipping Street", "sicCode": "Test Sic Code", "tickerSymbol": "Test Ticker Symbol", "website": "Test Website", "yearStarted": "Test Year Started", "zipCode": "Test Zip Code", "created_by": "Test Created By", "updated_by": "Test Updated By" } ] } ``` # Accounts Accounts describes the general data about the accounts in Stateset. ## The account object #### Attributes | Name | Type | Description | | ------------------ | --------- | -------------------------------------------------------- | | id | Text | Unique identifier for the account | | accountName | Text | Name of the account | | accountNotes | Text | Notes or additional information about the account | | accountSubtype | Text | Subtype or specific category of the account | | accountType | Text | Type or general category of the account | | account\_owner | Text | Owner or responsible person for the account | | account\_source | Text | Source or origin of the account | | annualRevenue | Text | Annual revenue associated with the account | | avatar | Text | URL or path to the account's avatar image | | billingCity | Text | City of the billing address | | billingCountry | Text | Country of the billing address | | billingLatitude | Text | Latitude coordinate of the billing address | | billingLongitude | Text | Longitude coordinate of the billing address | | billingState | Text | State or province of the billing address | | billingStreet | Text | Street address of the billing address | | created\_at | Date/Time | Date and time when the account was created | | description | Text | Description or additional details about the account | | employees | Text | Number or range of employees associated with the account | | fax | Text | Fax number of the account | | industry | Text | Industry or sector of the account | | is\_active | Boolean | Indicates whether the account is currently active | | is\_public | Boolean | Indicates whether the account is public or private | | last\_modified\_by | Text | Last person who modified the account | | numberOfEmployees | Text | Number of employees associated with the account | | ownership | Text | Ownership type or structure of the account | | parentAccount | Text | Parent account associated with the account | | phone | Text | Phone number of the account | | rating | Text | Rating or evaluation of the account | | shippingCity | Text | City of the shipping address | | shippingCountry | Text | Country of the shipping address | | shippingLatitude | Text | Latitude coordinate of the shipping address | | shippingLongitude | Text | Longitude coordinate of the shipping address | | shippingState | Text | State or province of the shipping address | | shippingStreet | Text | Street address of the shipping address | | stockTicker | Text | Stock ticker symbol associated with the account | | website | Text | Website URL of the account | | yearStarted | Text | Year the account was started or established | # List Accounts Source: https://docs.stateset.com/api-reference/accounts/list GET https://api.stateset.com/v1/accounts/list This endpoint gets or creates a new account. ### Body This is the limit of the accounts. This is the offset of the accounts. This is the order direction of the accounts. ### Response This is the id of the account. This is the account name of the account. This is the account notes of the account. This is the account subtype of the account. This is the account type of the account. This is the account owner of the account. This is the account source of the account. This is the annual revenue of the account. This is the avatar of the account. This is the billing city of the account. This is the billing country of the account. This is the billing latitude of the account. This is the billing longitude of the account. This is the billing state of the account. This is the billing street of the account. This is the created at of the account. This is the description of the account. This is the employees of the account. This is the fax of the account. This is the industry of the account. This is the is active of the account. This is the is public of the account. This is the last modified by of the account. This is the number of employees of the account. This is the ownership of the account. This is the phone of the account. This is the rating of the account. This is the shipping city of the account. This is the shipping country of the account. This is the shipping latitude of the account. This is the shipping longitude of the account. This is the shipping state of the account. This is the shipping street of the account. This is the sic code of the account. This is the ticker symbol of the account. This is the website of the account. This is the year started of the account. This is the zip code of the account. This is the created by of the account. This is the updated by of the account. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/accounts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "desc" }' ``` ```json Response theme={null} { "count": 1, "next": null, "previous": null, "results": [ { "id": "1", "accountName": "Test Account", "accountNotes": "Test Account Notes", "accountSubtype": "Test Account Subtype", "accountType": "Test Account Type", "account_owner": "Test Account Owner", "account_source": "Test Account Source", "annualRevenue": "Test Annual Revenue", "avatar": "Test Avatar", "billingCity": "Test Billing City", "billingCountry": "Test Billing Country", "billingLatitude": "Test Billing Latitude", "billingLongitude": "Test Billing Longitude", "billingState": "Test Billing State", "billingStreet": "Test Billing Street", "created_at": "2021-04-27T15:00:00.000000Z", "description": "Test Description", "employees": "Test Employees", "fax": "Test Fax", "industry": "Test Industry", "is_active": true, "is_public": true, "last_modified_by": "Test Last Modified By", "numberOfEmployees": "Test Number Of Employees", "ownership": "Test Ownership", "phone": "Test Phone", "rating": "Test Rating", "shippingCity": "Test Shipping City", "shippingCountry": "Test Shipping Country", "shippingLatitude": "Test Shipping Latitude", "shippingLongitude": "Test Shipping Longitude", "shippingState": "Test Shipping State", "shippingStreet": "Test Shipping Street", "sicCode": "Test Sic Code", "tickerSymbol": "Test Ticker Symbol", "website": "Test Website", "yearStarted": "Test Year Started", "zipCode": "Test Zip Code", "created_by": "Test Created By", "updated_by": "Test Updated By" } ] } ``` # Accounts Accounts describes the general data about the accounts in Stateset. ## The account object #### Attributes | Name | Type | Description | | ------------------ | --------- | -------------------------------------------------------- | | id | Text | Unique identifier for the account | | accountName | Text | Name of the account | | accountNotes | Text | Notes or additional information about the account | | accountSubtype | Text | Subtype or specific category of the account | | accountType | Text | Type or general category of the account | | account\_owner | Text | Owner or responsible person for the account | | account\_source | Text | Source or origin of the account | | annualRevenue | Text | Annual revenue associated with the account | | avatar | Text | URL or path to the account's avatar image | | billingCity | Text | City of the billing address | | billingCountry | Text | Country of the billing address | | billingLatitude | Text | Latitude coordinate of the billing address | | billingLongitude | Text | Longitude coordinate of the billing address | | billingState | Text | State or province of the billing address | | billingStreet | Text | Street address of the billing address | | created\_at | Date/Time | Date and time when the account was created | | description | Text | Description or additional details about the account | | employees | Text | Number or range of employees associated with the account | | fax | Text | Fax number of the account | | industry | Text | Industry or sector of the account | | is\_active | Boolean | Indicates whether the account is currently active | | is\_public | Boolean | Indicates whether the account is public or private | | last\_modified\_by | Text | Last person who modified the account | | numberOfEmployees | Text | Number of employees associated with the account | | ownership | Text | Ownership type or structure of the account | | parentAccount | Text | Parent account associated with the account | | phone | Text | Phone number of the account | | rating | Text | Rating or evaluation of the account | | shippingCity | Text | City of the shipping address | | shippingCountry | Text | Country of the shipping address | | shippingLatitude | Text | Latitude coordinate of the shipping address | | shippingLongitude | Text | Longitude coordinate of the shipping address | | shippingState | Text | State or province of the shipping address | | shippingStreet | Text | Street address of the shipping address | | stockTicker | Text | Stock ticker symbol associated with the account | | website | Text | Website URL of the account | | yearStarted | Text | Year the account was started or established | # Update Account Source: https://docs.stateset.com/api-reference/accounts/update PUT https://api.stateset.com/v1/accounts This endpoint updates an existing account. ### Body This is the id of the account. This is the account name of the account. This is the account notes of the account. This is the account subtype of the account. This is the account type of the account. This is the account owner of the account. This is the account source of the account. This is the annual revenue of the account. This is the avatar of the account. This is the billing city of the account. This is the billing country of the account. This is the billing latitude of the account. This is the billing longitude of the account. This is the billing state of the account. This is the billing street of the account. This is the created at of the account. This is the description of the account. This is the employees of the account. This is the fax of the account. This is the industry of the account. This is the is active of the account. This is the is public of the account. ### Response This is the id of the account. This is the account name of the account. This is the account notes of the account. This is the account subtype of the account. This is the account type of the account. This is the account owner of the account. This is the account source of the account. This is the annual revenue of the account. This is the avatar of the account. This is the billing city of the account. This is the billing country of the account. This is the billing latitude of the account. This is the billing longitude of the account. This is the billing state of the account. This is the billing street of the account. This is the created at of the account. This is the description of the account. This is the employees of the account. This is the fax of the account. This is the industry of the account. This is the is active of the account. This is the is public of the account. This is the last modified by of the account. This is the number of employees of the account. This is the ownership of the account. This is the phone of the account. This is the rating of the account. This is the shipping city of the account. This is the shipping country of the account. This is the shipping latitude of the account. This is the shipping longitude of the account. This is the shipping state of the account. This is the shipping street of the account. This is the sic code of the account. This is the ticker symbol of the account. This is the website of the account. This is the year started of the account. This is the zip code of the account. This is the created by of the account. This is the updated by of the account. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/account' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # API Design Guidelines Source: https://docs.stateset.com/api-reference/api-design-guidelines Best practices and standards for StateSet API development # StateSet API Design Guidelines This document outlines the design principles, patterns, and best practices for the StateSet API. Following these guidelines ensures consistency, usability, and maintainability across all API endpoints. ## Core Principles ### 1. RESTful Design * Use standard HTTP methods appropriately: * `GET` for retrieving resources * `POST` for creating resources * `PUT/PATCH` for updating resources * `DELETE` for removing resources ### 2. Resource-Oriented URLs ``` Good: GET /v1/orders GET /v1/orders/{id} POST /v1/orders PUT /v1/orders/{id} DELETE /v1/orders/{id} Avoid: GET /v1/getOrders POST /v1/createOrder POST /v1/orders/update ``` ### 3. Consistent Naming Conventions * Use lowercase with hyphens for URLs: `/v1/work-orders` * Use camelCase for JSON properties: `firstName`, `createdAt` * Use snake\_case for query parameters: `created_after`, `sort_by` * Pluralize collection endpoints: `/orders` not `/order` ## Request Standards ### Headers Required headers for all requests: ```http theme={null} Authorization: Bearer YOUR_API_KEY Content-Type: application/json Accept: application/json ``` Optional headers: ```http theme={null} X-API-Version: 2024-01-01 X-Idempotency-Key: unique-request-id X-Request-ID: client-generated-id Accept-Language: en-US ``` ### Query Parameters #### Pagination All list endpoints must support: ``` GET /v1/orders?limit=20&offset=0 GET /v1/orders?limit=20&cursor=eyJpZCI6MTAwfQ== ``` Default pagination: * `limit`: 20 (max: 100) * `offset`: 0 #### Filtering Use consistent filter patterns: ``` # Exact match GET /v1/orders?status=shipped # Multiple values GET /v1/orders?status_in=shipped,delivered # Range queries GET /v1/orders?created_after=2024-01-01T00:00:00Z GET /v1/orders?created_before=2024-12-31T23:59:59Z GET /v1/orders?amount_gte=10000 GET /v1/orders?amount_lte=50000 # Search GET /v1/orders?search=john+doe GET /v1/orders?customer_email=john@example.com ``` #### Sorting ``` GET /v1/orders?sort=created_at&order=desc GET /v1/orders?sort=-created_at # Alternative: prefix with - for desc ``` ### Request Body #### Required Fields Clearly mark required fields in documentation: ```json theme={null} { "customer": { // required "email": "...", // required "name": "..." // optional } } ``` #### Nested Objects Use nested objects for logical grouping: ```json theme={null} { "customer": { "email": "john@example.com", "first_name": "John", "last_name": "Doe" }, "shipping_address": { "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } } ``` ## Response Standards ### Success Responses #### Single Resource ```json theme={null} { "id": "ord_1a2b3c4d", "object": "order", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", // ... resource fields } ``` #### Collection ```json theme={null} { "object": "list", "data": [ { "id": "ord_1a2b3c4d", "object": "order", // ... resource fields } ], "has_more": true, "total_count": 150, "url": "/v1/orders" } ``` #### With Metadata ```json theme={null} { "data": { "id": "ord_1a2b3c4d", "object": "order", // ... resource fields }, "meta": { "request_id": "req_xyz789", "version": "v1", "timestamp": "2024-01-15T10:30:00Z" } } ``` ### Error Responses #### Standard Error Format ```json theme={null} { "error": { "type": "validation_error", "code": "VALIDATION_ERROR", "message": "Invalid request parameters", "details": { "field_errors": { "email": "Invalid email format", "quantity": "Must be a positive integer" } }, "documentation_url": "https://docs.stateset.com/errors/VALIDATION_ERROR", "request_id": "req_xyz789" } } ``` #### HTTP Status Codes | Status | Usage | | ------------------------- | --------------------------------------- | | 200 OK | Successful GET, PUT, PATCH | | 201 Created | Successful POST creating resource | | 202 Accepted | Request accepted for async processing | | 204 No Content | Successful DELETE | | 400 Bad Request | Invalid request parameters | | 401 Unauthorized | Missing or invalid authentication | | 403 Forbidden | Valid auth but insufficient permissions | | 404 Not Found | Resource doesn't exist | | 409 Conflict | Resource conflict (e.g., duplicate) | | 422 Unprocessable Entity | Validation errors | | 429 Too Many Requests | Rate limit exceeded | | 500 Internal Server Error | Server error | | 503 Service Unavailable | Temporary unavailability | ## Data Types and Formats ### Timestamps Always use ISO 8601 format with timezone: ```json theme={null} { "created_at": "2024-01-15T10:30:00Z", "scheduled_for": "2024-01-20T14:00:00-08:00" } ``` ### Money/Currency Store monetary values in smallest currency unit (cents): ```json theme={null} { "amount": 1999, // $19.99 "currency": "USD" } ``` ### Phone Numbers Use E.164 format: ```json theme={null} { "phone": "+14155551234" } ``` ### Countries and States Use ISO standards: * Countries: ISO 3166-1 alpha-2 (US, CA, GB) * States/Provinces: ISO 3166-2 (CA-ON, US-NY) ```json theme={null} { "country": "US", "state": "CA" } ``` ## Versioning ### URL Versioning Primary versioning method: ``` https://api.stateset.com/v1/orders https://api.stateset.com/v2/orders ``` ### Header Versioning For minor versions: ```http theme={null} X-API-Version: 2024-01-01 ``` ### Deprecation Process 1. Announce deprecation with 90-day notice 2. Add deprecation headers: ```http theme={null} Sunset: Sat, 31 Dec 2024 23:59:59 GMT Deprecation: true Link: ; rel="successor-version" ``` 3. Maintain deprecated version for minimum 12 months ## Idempotency ### Implementation Support idempotency for all POST, PUT, PATCH requests: ```http theme={null} POST /v1/orders X-Idempotency-Key: unique-request-id-123 ``` Response includes: ```http theme={null} X-Idempotency-Key: unique-request-id-123 X-Idempotent-Replayed: true ``` ## Webhooks ### Event Naming Use dot notation for event types: ``` order.created order.updated order.shipped order.delivered return.requested return.approved payment.succeeded payment.failed ``` ### Webhook Payload ```json theme={null} { "id": "evt_1a2b3c4d", "type": "order.created", "created_at": "2024-01-15T10:30:00Z", "data": { "object": { "id": "ord_xyz789", "object": "order", // ... full object }, "previous_attributes": { // ... for update events } }, "request": { "id": "req_abc123", "idempotency_key": "unique-key-123" } } ``` ### Security Always include signature header: ```http theme={null} X-StateSet-Signature: sha256=3f3b3c4d... ``` ## Performance Guidelines ### Response Times Target response times: * Simple reads: \< 200ms * Complex queries: \< 500ms * Writes: \< 1000ms ### Payload Size * Limit response size to 1MB * Use pagination for large collections * Support field filtering: ``` GET /v1/orders?fields=id,status,customer ``` ### Caching Include cache headers: ```http theme={null} Cache-Control: private, max-age=300 ETag: "33a64df551" Last-Modified: Wed, 15 Jan 2024 10:30:00 GMT ``` ## GraphQL Guidelines ### Query Naming ```graphql theme={null} # Good query GetOrder($id: ID!) { order(id: $id) { id status } } # Avoid query fetchOrderData($id: ID!) { getOrderById(id: $id) { id status } } ``` ### Mutations ```graphql theme={null} mutation CreateOrder($input: OrderCreateInput!) { orderCreate(input: $input) { order { id status } userErrors { field message } } } ``` ### Error Handling Return errors in userErrors field: ```json theme={null} { "data": { "orderCreate": { "order": null, "userErrors": [ { "field": "customer.email", "message": "Email is required" } ] } } } ``` ## Testing ### Test Coverage All endpoints must include: * Success path tests * Error handling tests * Edge case tests * Performance tests ### Example Test Cases ```javascript theme={null} describe('POST /v1/orders', () => { test('creates order successfully', async () => { const response = await api.post('/v1/orders', validOrderData); expect(response.status).toBe(201); expect(response.body.object).toBe('order'); }); test('returns 400 for invalid data', async () => { const response = await api.post('/v1/orders', invalidOrderData); expect(response.status).toBe(400); expect(response.body.error.code).toBe('VALIDATION_ERROR'); }); test('handles idempotency', async () => { const key = 'test-idempotency-key'; const response1 = await api.post('/v1/orders', data, { headers: { 'X-Idempotency-Key': key } }); const response2 = await api.post('/v1/orders', data, { headers: { 'X-Idempotency-Key': key } }); expect(response1.body.id).toBe(response2.body.id); }); }); ``` ## Documentation Requirements Every endpoint must document: 1. **Description**: Clear explanation of what the endpoint does 2. **Authentication**: Required permissions 3. **Parameters**: All query params, headers, and body fields 4. **Response**: Success and error response formats 5. **Examples**: Working code examples in multiple languages 6. **Rate Limits**: Specific limits if different from defaults 7. **Webhooks**: Related webhook events 8. **See Also**: Links to related endpoints ## Security Best Practices 1. **Always use HTTPS** 2. **Validate all inputs** - Never trust client data 3. **Rate limit all endpoints** 4. **Log security events** - Failed auth, permission denials 5. **Sanitize outputs** - Prevent XSS in responses 6. **Use secure headers**: ```http theme={null} X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block ``` ## Monitoring and Observability Include correlation IDs in all requests: ```http theme={null} X-Request-ID: client-generated-uuid X-Correlation-ID: server-generated-uuid ``` Log format: ```json theme={null} { "timestamp": "2024-01-15T10:30:00Z", "request_id": "req_abc123", "method": "POST", "path": "/v1/orders", "status": 201, "duration_ms": 145, "user_id": "usr_xyz789" } ``` ## Change Management 1. **Backwards Compatibility**: Never break existing integrations 2. **Additive Changes**: New fields are safe to add 3. **Deprecation Notices**: Minimum 90 days 4. **Migration Guides**: Provide clear upgrade paths 5. **Changelog**: Maintain detailed changelog ## Contact For API design questions or to propose changes to these guidelines: * Email: [api-team@stateset.com](mailto:api-team@stateset.com) * Slack: #api-design * GitHub: stateset/api-guidelines # Cancel ASN Source: https://docs.stateset.com/api-reference/asns/cancel POST https://api.stateset.com/v1/asns/:id/cancel Cancel an ASN that hasn't been received yet ASNs can only be cancelled if they haven't been received. Once receiving has started, the ASN cannot be cancelled. ### Path Parameters The unique identifier of the ASN to cancel ### Request Body Reason for cancellation User ID or email of the person cancelling the ASN Whether to notify the supplier of the cancellation (default: true) Additional notes about the cancellation ### Response ASN ID ASN number Updated status (will be "cancelled") Timestamp of cancellation User who cancelled the ASN Reason for cancellation ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/asns/asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "reason": "Supplier notified of production delay", "cancelled_by": "purchasing@company.com", "notify_supplier": true, "notes": "Shipment delayed by 2 weeks due to material shortage. Will create new ASN when shipment is ready." }' ``` ```graphQL GraphQL theme={null} mutation CancelASN($id: ID!, $input: CancelASNInput!) { cancelASN(id: $id, input: $input) { id asn_number status cancelled_at cancelled_by cancellation_reason purchase_order_id } } ``` ```javascript Node.js theme={null} const result = await stateset.asns.cancel( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { reason: 'Supplier notified of production delay', cancelled_by: 'purchasing@company.com', notify_supplier: true, notes: 'Shipment delayed by 2 weeks due to material shortage' } ); ``` ```python Python theme={null} result = stateset.asns.cancel( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', reason='Supplier notified of production delay', cancelled_by='purchasing@company.com', notify_supplier=True, notes='Shipment delayed by 2 weeks due to material shortage' ) ``` ```json Response theme={null} { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "asn", "asn_number": "ASN-2024-00001", "status": "cancelled", "cancelled_at": "2024-01-16T10:30:00Z", "cancelled_by": "purchasing@company.com", "cancellation_reason": "Supplier notified of production delay", "purchase_order_id": "po_123456789", "supplier_id": "sup_abc123", "items_affected": [ { "sku": "WBH-001", "quantity": 500 }, { "sku": "USB-C-001", "quantity": 1000 } ], "notifications_sent": [ { "type": "email", "recipient": "supplier@audiotech.com", "sent_at": "2024-01-16T10:31:00Z" }, { "type": "webhook", "endpoint": "warehouse_system", "sent_at": "2024-01-16T10:31:00Z" } ], "notes": "Shipment delayed by 2 weeks due to material shortage. Will create new ASN when shipment is ready." } ``` ### Error Responses Error object when cancellation fails Type of error (e.g., "invalid\_status", "already\_received") Human-readable error message Error code for programmatic handling ```json Error Response theme={null} { "error": { "type": "invalid_status", "message": "Cannot cancel ASN that has already been received", "code": "ASN_ALREADY_RECEIVED" } } ``` # Create ASN Source: https://docs.stateset.com/api-reference/asns/create POST https://api.stateset.com/v1/asns Create an Advanced Shipping Notice for inbound shipments This endpoint creates a new ASN (Advanced Shipping Notice) to notify about incoming shipments from suppliers. ASNs help warehouses prepare for receiving inventory and automate the receiving process. ## Authentication This endpoint requires a valid API key with `asns:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body The purchase order ID this ASN is associated with The supplier ID sending the shipment Date when the shipment was sent (ISO 8601) Expected delivery date at warehouse (ISO 8601) Destination warehouse ID Shipping and tracking information Carrier name (e.g., "UPS", "FedEx", "DHL") Primary tracking number Service level (e.g., "Ground", "Express", "2-Day") Additional tracking numbers for multi-package shipments Array of items being shipped Product SKU Quantity being shipped Original quantity ordered (for reference) Cost per unit Cost in cents ISO 4217 currency code Lot or batch number for tracking Expiration date for perishable items (ISO 8601) Array of serial numbers for serialized items Packaging and palletization information Total number of packages/boxes Total number of pallets Total shipment weight Weight value Weight unit (e.g., "lb", "kg") Detailed package information Unique package identifier Package type (e.g., "box", "pallet", "crate") Package dimensions Package weight Items contained in this package Related shipping documents Document type (e.g., "packing\_list", "bill\_of\_lading", "commercial\_invoice") Document reference number URL to access the document Additional notes or special instructions for receiving Additional custom fields as key-value pairs ### Response Unique ASN identifier Always "asn" System-generated ASN number ASN status: "pending", "in\_transit", "delivered", "received", "cancelled" ISO 8601 timestamp of creation ISO 8601 timestamp of last update ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/asns' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "purchase_order_id": "po_123456789", "supplier_id": "sup_abc123", "shipment_date": "2024-01-15T14:00:00Z", "expected_arrival_date": "2024-01-18T10:00:00Z", "warehouse_id": "wh_001", "tracking_info": { "carrier": "UPS", "tracking_number": "1Z999AA10123456784", "service_type": "Ground" }, "items": [ { "sku": "WBH-001", "quantity_shipped": 500, "quantity_ordered": 500, "unit_cost": { "amount": 7500, "currency": "USD" }, "lot_number": "LOT-2024-001" }, { "sku": "USB-C-001", "quantity_shipped": 1000, "quantity_ordered": 1000, "unit_cost": { "amount": 450, "currency": "USD" }, "lot_number": "LOT-2024-002" } ], "packaging_details": { "total_packages": 10, "total_pallets": 2, "total_weight": { "value": 250, "unit": "lb" } }, "notes": "Please schedule receiving appointment. Fragile electronics." }' ``` ```graphQL GraphQL theme={null} mutation CreateASN { createASN(input: { purchase_order_id: "po_123456789" supplier_id: "sup_abc123" shipment_date: "2024-01-15T14:00:00Z" expected_arrival_date: "2024-01-18T10:00:00Z" warehouse_id: "wh_001" tracking_info: { carrier: "UPS" tracking_number: "1Z999AA10123456784" service_type: "Ground" } items: [ { sku: "WBH-001" quantity_shipped: 500 unit_cost: { amount: 7500 currency: "USD" } } ] }) { id asn_number status expected_arrival_date items { sku quantity_shipped } } } ``` ```javascript Node.js theme={null} const asn = await stateset.asns.create({ purchase_order_id: "po_123456789", supplier_id: "sup_abc123", shipment_date: "2024-01-15T14:00:00Z", expected_arrival_date: "2024-01-18T10:00:00Z", warehouse_id: "wh_001", tracking_info: { carrier: "UPS", tracking_number: "1Z999AA10123456784", service_type: "Ground" }, items: [ { sku: "WBH-001", quantity_shipped: 500, quantity_ordered: 500, unit_cost: { amount: 7500, currency: "USD" }, lot_number: "LOT-2024-001" } ], packaging_details: { total_packages: 10, total_pallets: 2, total_weight: { value: 250, unit: "lb" } } }); ``` ```python Python theme={null} asn = stateset.asns.create({ "purchase_order_id": "po_123456789", "supplier_id": "sup_abc123", "shipment_date": "2024-01-15T14:00:00Z", "expected_arrival_date": "2024-01-18T10:00:00Z", "warehouse_id": "wh_001", "tracking_info": { "carrier": "UPS", "tracking_number": "1Z999AA10123456784", "service_type": "Ground" }, "items": [ { "sku": "WBH-001", "quantity_shipped": 500, "quantity_ordered": 500, "unit_cost": { "amount": 7500, "currency": "USD" }, "lot_number": "LOT-2024-001" } ] }) ``` ```json Response theme={null} { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "asn", "asn_number": "ASN-2024-00001", "status": "pending", "created_at": "2024-01-15T14:30:00Z", "updated_at": "2024-01-15T14:30:00Z", "purchase_order_id": "po_123456789", "supplier_id": "sup_abc123", "warehouse_id": "wh_001", "shipment_date": "2024-01-15T14:00:00Z", "expected_arrival_date": "2024-01-18T10:00:00Z", "actual_arrival_date": null, "tracking_info": { "carrier": "UPS", "tracking_number": "1Z999AA10123456784", "service_type": "Ground", "tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784" }, "items": [ { "id": "asn_item_123", "sku": "WBH-001", "product_name": "Wireless Bluetooth Headphones", "quantity_shipped": 500, "quantity_ordered": 500, "quantity_received": 0, "unit_cost": { "amount": 7500, "currency": "USD" }, "lot_number": "LOT-2024-001", "status": "pending" }, { "id": "asn_item_124", "sku": "USB-C-001", "product_name": "USB-C Charging Cable", "quantity_shipped": 1000, "quantity_ordered": 1000, "quantity_received": 0, "unit_cost": { "amount": 450, "currency": "USD" }, "lot_number": "LOT-2024-002", "status": "pending" } ], "packaging_details": { "total_packages": 10, "total_pallets": 2, "total_weight": { "value": 250, "unit": "lb" } }, "notes": "Please schedule receiving appointment. Fragile electronics.", "metadata": {} } ``` # Delete ASN Source: https://docs.stateset.com/api-reference/asns/delete DELETE https://api.stateset.com/v1/asns/:id Delete an ASN from the system ASNs can only be deleted if they are in "cancelled" status or created in error. Received ASNs cannot be deleted for audit trail purposes. ### Path Parameters The unique identifier of the ASN to delete ### Response The ID of the deleted ASN Always "asn" Always true for successful deletion ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/asns/asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```graphQL GraphQL theme={null} mutation DeleteASN($id: ID!) { deleteASN(id: $id) { id deleted } } ``` ```javascript Node.js theme={null} const result = await stateset.asns.delete( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} result = stateset.asns.delete( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "asn", "deleted": true } ``` ### Error Responses Error object when deletion fails Type of error (e.g., "invalid\_request", "asn\_received") Human-readable error message Error code for programmatic handling ```json Error Response theme={null} { "error": { "type": "asn_received", "message": "Cannot delete ASN that has been received. ASNs with received status must be maintained for audit purposes.", "code": "ASN_ALREADY_RECEIVED" } } ``` # Get ASN Source: https://docs.stateset.com/api-reference/asns/get GET https://api.stateset.com/v1/asns/:id Retrieve a single ASN by ID with full shipment details ### Path Parameters The unique identifier of the ASN to retrieve ### Query Parameters Include detailed receiving data if available (default: true) Include tracking status history (default: false) ### Response Unique ASN identifier Always "asn" System-generated ASN number Current status: "pending", "in\_transit", "delivered", "received", "partially\_received", "cancelled" ISO 8601 timestamp of creation ISO 8601 timestamp of last update Associated purchase order ID Supplier information Destination warehouse details Date when shipment was sent Expected delivery date Actual delivery date (when delivered) Shipping and tracking details Array of items with shipping and receiving details Packaging and palletization information Receiving information if ASN has been processed Date when items were received User who processed the receiving Any discrepancies found during receiving Receiving notes Related shipping documents Additional notes or instructions Custom metadata fields ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/asns/asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```graphQL GraphQL theme={null} query GetASN($id: ID!) { asn(id: $id) { id asn_number status supplier { id name } warehouse { id name } shipment_date expected_arrival_date actual_arrival_date tracking_info { carrier tracking_number tracking_url current_status } items { id sku product_name quantity_shipped quantity_received status discrepancies { type expected actual notes } } receiving_data { received_date received_by total_items_received discrepancy_count } } } ``` ```javascript Node.js theme={null} const asn = await stateset.asns.retrieve( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { include_receiving_data: true, include_tracking_history: true } ); ``` ```python Python theme={null} asn = stateset.asns.retrieve( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', include_receiving_data=True, include_tracking_history=True ) ``` ```json Response theme={null} { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "asn", "asn_number": "ASN-2024-00001", "status": "delivered", "created_at": "2024-01-15T14:30:00Z", "updated_at": "2024-01-18T11:15:00Z", "purchase_order_id": "po_123456789", "purchase_order_number": "PO-2024-00123", "supplier": { "id": "sup_abc123", "name": "AudioTech Suppliers Inc.", "contact_email": "shipping@audiotech.com" }, "warehouse": { "id": "wh_001", "name": "Main Distribution Center", "address": { "line1": "123 Warehouse Way", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" } }, "shipment_date": "2024-01-15T14:00:00Z", "expected_arrival_date": "2024-01-18T10:00:00Z", "actual_arrival_date": "2024-01-18T09:30:00Z", "tracking_info": { "carrier": "UPS", "tracking_number": "1Z999AA10123456784", "service_type": "Ground", "tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784", "current_status": "Delivered", "last_update": "2024-01-18T09:30:00Z", "tracking_history": [ { "timestamp": "2024-01-15T14:15:00Z", "status": "Picked up", "location": "San Francisco, CA" }, { "timestamp": "2024-01-16T22:00:00Z", "status": "In transit", "location": "Fresno, CA" }, { "timestamp": "2024-01-18T06:00:00Z", "status": "Out for delivery", "location": "Los Angeles, CA" }, { "timestamp": "2024-01-18T09:30:00Z", "status": "Delivered", "location": "Los Angeles, CA" } ] }, "items": [ { "id": "asn_item_123", "sku": "WBH-001", "product_name": "Wireless Bluetooth Headphones", "quantity_shipped": 500, "quantity_ordered": 500, "quantity_received": 0, "unit_cost": { "amount": 7500, "currency": "USD" }, "lot_number": "LOT-2024-001", "status": "pending_receipt" }, { "id": "asn_item_124", "sku": "USB-C-001", "product_name": "USB-C Charging Cable", "quantity_shipped": 1000, "quantity_ordered": 1000, "quantity_received": 0, "unit_cost": { "amount": 450, "currency": "USD" }, "lot_number": "LOT-2024-002", "status": "pending_receipt" } ], "packaging_details": { "total_packages": 10, "total_pallets": 2, "total_weight": { "value": 250, "unit": "lb" }, "packages": [ { "package_id": "PKG001", "type": "pallet", "tracking_number": "1Z999AA10123456784" } ] }, "shipping_documents": [ { "type": "packing_list", "document_number": "PL-2024-00001", "url": "https://documents.stateset.com/packing-lists/PL-2024-00001.pdf" } ], "receiving_data": null, "notes": "Please schedule receiving appointment. Fragile electronics.", "metadata": {} } ``` # List ASNs Source: https://docs.stateset.com/api-reference/asns/list GET https://api.stateset.com/v1/asns Retrieve a paginated list of ASNs with filtering options ### Query Parameters Number of ASNs to return (default: 20, max: 100) Number of ASNs to skip (for pagination) Cursor for pagination (alternative to offset) Filter by status: "pending", "in\_transit", "delivered", "received", "partially\_received", "cancelled" Filter by purchase order ID Filter by supplier ID Filter by destination warehouse ID Filter by shipping carrier Filter ASNs with expected arrival after this date (ISO 8601) Filter ASNs with expected arrival before this date (ISO 8601) Filter ASNs created after this date (ISO 8601) Filter ASNs created before this date (ISO 8601) Filter ASNs with receiving discrepancies Search by ASN number, tracking number, or supplier name Sort field: "created\_at", "expected\_arrival\_date", "asn\_number", "status" (default: "created\_at") Sort order: "asc" or "desc" (default: "desc") ### Response Always "list" Array of ASN objects Whether there are more ASNs to retrieve Total number of ASNs matching the filters Cursor for retrieving the next page ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/asns?status=in_transit&warehouse_id=wh_001&limit=10' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```graphQL GraphQL theme={null} query ListASNs( $limit: Int $offset: Int $status: ASNStatus $warehouse_id: String $expected_arrival_after: DateTime ) { asns( limit: $limit offset: $offset status: $status warehouse_id: $warehouse_id expected_arrival_after: $expected_arrival_after ) { data { id asn_number status supplier { id name } warehouse { id name } expected_arrival_date tracking_info { carrier tracking_number current_status } item_summary { total_items total_quantity } } has_more total_count } } ``` ```javascript Node.js theme={null} const asns = await stateset.asns.list({ status: 'in_transit', warehouse_id: 'wh_001', expected_arrival_after: '2024-01-15T00:00:00Z', limit: 10, sort_by: 'expected_arrival_date', sort_order: 'asc' }); // Iterate through all ASNs for await (const asn of stateset.asns.list()) { console.log(asn.asn_number, asn.status); } ``` ```python Python theme={null} asns = stateset.asns.list( status='in_transit', warehouse_id='wh_001', expected_arrival_after='2024-01-15T00:00:00Z', limit=10, sort_by='expected_arrival_date', sort_order='asc' ) # Iterate through all ASNs for asn in stateset.asns.list(): print(asn.asn_number, asn.status) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "asn", "asn_number": "ASN-2024-00001", "status": "in_transit", "created_at": "2024-01-15T14:30:00Z", "updated_at": "2024-01-16T08:00:00Z", "purchase_order_id": "po_123456789", "purchase_order_number": "PO-2024-00123", "supplier": { "id": "sup_abc123", "name": "AudioTech Suppliers Inc." }, "warehouse": { "id": "wh_001", "name": "Main Distribution Center" }, "shipment_date": "2024-01-15T14:00:00Z", "expected_arrival_date": "2024-01-18T10:00:00Z", "tracking_info": { "carrier": "UPS", "tracking_number": "1Z999AA10123456784", "current_status": "In Transit", "last_update": "2024-01-16T08:00:00Z" }, "item_summary": { "total_items": 2, "total_quantity": 1500, "total_value": { "amount": 4200000, "currency": "USD" } } }, { "id": "asn_xyz789def456", "object": "asn", "asn_number": "ASN-2024-00002", "status": "in_transit", "created_at": "2024-01-16T09:00:00Z", "updated_at": "2024-01-16T15:00:00Z", "purchase_order_id": "po_987654321", "purchase_order_number": "PO-2024-00124", "supplier": { "id": "sup_def456", "name": "TechConnect Wholesale" }, "warehouse": { "id": "wh_001", "name": "Main Distribution Center" }, "shipment_date": "2024-01-16T08:00:00Z", "expected_arrival_date": "2024-01-19T14:00:00Z", "tracking_info": { "carrier": "FedEx", "tracking_number": "123456789012", "current_status": "In Transit", "last_update": "2024-01-16T15:00:00Z" }, "item_summary": { "total_items": 5, "total_quantity": 2500, "total_value": { "amount": 1875000, "currency": "USD" } } } ], "has_more": true, "total_count": 15, "next_cursor": "eyJpZCI6ImFzbl94eXo3ODlkZWY0NTYifQ==" } ``` # Receive ASN Source: https://docs.stateset.com/api-reference/asns/receive POST https://api.stateset.com/v1/asns/:id/receive Process the receiving of items from an ASN and update inventory This endpoint processes the receiving of items from an ASN. It updates inventory levels, records any discrepancies, and can trigger automated workflows for putaway and quality control. ### Path Parameters The unique identifier of the ASN to receive ### Request Body Date and time when items were received (ISO 8601) User ID or name of the person processing the receipt Array of received items with quantities and conditions ASN item ID being received Actual quantity received Condition of received items: "new", "damaged", "defective" Lot number for tracking (can override ASN lot number) Expiration date for perishable items Array of serial numbers for serialized items Warehouse location where items are placed Notes about any discrepancies found Quality control information Whether quality check was performed Whether items passed quality check Quality check notes List of items that failed quality check Overall discrepancies found during receiving Type: "quantity", "damage", "wrong\_item", "missing\_item" Description of the discrepancy How the discrepancy was resolved General receiving notes Whether this completes the ASN receipt (default: true) ### Response ASN ID Updated ASN status Summary of the receiving process Details of inventory updates made Summary of any discrepancies found ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/asns/asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/receive' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "received_date": "2024-01-18T11:00:00Z", "received_by": "john.doe@warehouse.com", "items": [ { "item_id": "asn_item_123", "quantity_received": 498, "condition": "new", "lot_number": "LOT-2024-001", "location": "A-12-3", "discrepancy_notes": "2 units damaged in transit" }, { "item_id": "asn_item_124", "quantity_received": 1000, "condition": "new", "lot_number": "LOT-2024-002", "location": "B-5-1" } ], "quality_check": { "performed": true, "passed": true, "notes": "All items meet quality standards" }, "discrepancies": [ { "type": "damage", "description": "2 units of WBH-001 damaged in transit", "resolution": "Filed claim with carrier" } ], "notes": "Shipment received in good condition except for noted damages", "complete_receipt": true }' ``` ```graphQL GraphQL theme={null} mutation ReceiveASN($id: ID!, $input: ReceiveASNInput!) { receiveASN(id: $id, input: $input) { id status receiving_summary { total_items_expected total_items_received discrepancy_count receipt_completed } inventory_updates { sku quantity_added new_total location } discrepancy_report { has_discrepancies total_discrepancies discrepancies { type description impact } } } } ``` ```javascript Node.js theme={null} const receipt = await stateset.asns.receive( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { received_date: '2024-01-18T11:00:00Z', received_by: 'john.doe@warehouse.com', items: [ { item_id: 'asn_item_123', quantity_received: 498, condition: 'new', lot_number: 'LOT-2024-001', location: 'A-12-3', discrepancy_notes: '2 units damaged in transit' }, { item_id: 'asn_item_124', quantity_received: 1000, condition: 'new', lot_number: 'LOT-2024-002', location: 'B-5-1' } ], quality_check: { performed: true, passed: true, notes: 'All items meet quality standards' }, complete_receipt: true } ); ``` ```python Python theme={null} receipt = stateset.asns.receive( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', received_date='2024-01-18T11:00:00Z', received_by='john.doe@warehouse.com', items=[ { 'item_id': 'asn_item_123', 'quantity_received': 498, 'condition': 'new', 'lot_number': 'LOT-2024-001', 'location': 'A-12-3', 'discrepancy_notes': '2 units damaged in transit' }, { 'item_id': 'asn_item_124', 'quantity_received': 1000, 'condition': 'new', 'lot_number': 'LOT-2024-002', 'location': 'B-5-1' } ], quality_check={ 'performed': True, 'passed': True, 'notes': 'All items meet quality standards' }, complete_receipt=True ) ``` ```json Response theme={null} { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "asn_number": "ASN-2024-00001", "status": "received", "receiving_summary": { "total_items_expected": 1500, "total_items_received": 1498, "discrepancy_count": 1, "receipt_completed": true, "received_date": "2024-01-18T11:00:00Z", "received_by": "john.doe@warehouse.com" }, "inventory_updates": [ { "sku": "WBH-001", "product_name": "Wireless Bluetooth Headphones", "quantity_added": 498, "previous_quantity": 145, "new_total": 643, "location": "A-12-3", "lot_number": "LOT-2024-001" }, { "sku": "USB-C-001", "product_name": "USB-C Charging Cable", "quantity_added": 1000, "previous_quantity": 487, "new_total": 1487, "location": "B-5-1", "lot_number": "LOT-2024-002" } ], "discrepancy_report": { "has_discrepancies": true, "total_discrepancies": 1, "discrepancies": [ { "type": "damage", "description": "2 units of WBH-001 damaged in transit", "expected_quantity": 500, "received_quantity": 498, "impact": "inventory_shortage", "resolution": "Filed claim with carrier" } ] }, "purchase_order_update": { "po_id": "po_123456789", "items_received": 1498, "items_outstanding": 2, "po_status": "partially_received" }, "workflows_triggered": [ { "type": "putaway", "status": "initiated", "assigned_to": "warehouse_team" }, { "type": "carrier_claim", "status": "initiated", "reference": "CLAIM-2024-00123" } ] } ``` # Update ASN Source: https://docs.stateset.com/api-reference/asns/update PUT https://api.stateset.com/v1/asns/:id Update an existing ASN with new tracking information or status This endpoint supports partial updates. Only include the fields you want to change. Once an ASN is received, only certain fields can be updated. ### Path Parameters The unique identifier of the ASN to update ### Request Body Updated expected delivery date (ISO 8601) Actual delivery date when shipment arrives (ISO 8601) Updated status: "pending", "in\_transit", "delivered", "received", "partially\_received", "cancelled" Updated tracking information Carrier name Primary tracking number Service level Current tracking status Additional tracking numbers Updated packaging information Total number of packages Total number of pallets Total shipment weight Updated or additional shipping documents Document type Document reference number URL to access the document Updated notes or instructions Updated custom metadata ### Response Returns the updated ASN object with all fields. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/asns/asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "status": "delivered", "actual_arrival_date": "2024-01-18T09:30:00Z", "tracking_info": { "current_status": "Delivered" }, "shipping_documents": [ { "type": "proof_of_delivery", "document_number": "POD-2024-00001", "url": "https://documents.stateset.com/pod/POD-2024-00001.pdf" } ] }' ``` ```graphQL GraphQL theme={null} mutation UpdateASN($id: ID!, $input: UpdateASNInput!) { updateASN(id: $id, input: $input) { id asn_number status actual_arrival_date tracking_info { current_status last_update } shipping_documents { type document_number url } } } ``` ```javascript Node.js theme={null} const asn = await stateset.asns.update( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { status: 'delivered', actual_arrival_date: '2024-01-18T09:30:00Z', tracking_info: { current_status: 'Delivered' }, shipping_documents: [ { type: 'proof_of_delivery', document_number: 'POD-2024-00001', url: 'https://documents.stateset.com/pod/POD-2024-00001.pdf' } ] } ); ``` ```python Python theme={null} asn = stateset.asns.update( 'asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', status='delivered', actual_arrival_date='2024-01-18T09:30:00Z', tracking_info={ 'current_status': 'Delivered' }, shipping_documents=[ { 'type': 'proof_of_delivery', 'document_number': 'POD-2024-00001', 'url': 'https://documents.stateset.com/pod/POD-2024-00001.pdf' } ] ) ``` ```json Response theme={null} { "id": "asn_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "asn", "asn_number": "ASN-2024-00001", "status": "delivered", "created_at": "2024-01-15T14:30:00Z", "updated_at": "2024-01-18T09:35:00Z", "purchase_order_id": "po_123456789", "supplier_id": "sup_abc123", "warehouse_id": "wh_001", "shipment_date": "2024-01-15T14:00:00Z", "expected_arrival_date": "2024-01-18T10:00:00Z", "actual_arrival_date": "2024-01-18T09:30:00Z", "tracking_info": { "carrier": "UPS", "tracking_number": "1Z999AA10123456784", "service_type": "Ground", "tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784", "current_status": "Delivered", "last_update": "2024-01-18T09:30:00Z" }, "items": [ { "id": "asn_item_123", "sku": "WBH-001", "product_name": "Wireless Bluetooth Headphones", "quantity_shipped": 500, "quantity_ordered": 500, "quantity_received": 0, "unit_cost": { "amount": 7500, "currency": "USD" }, "lot_number": "LOT-2024-001", "status": "pending_receipt" }, { "id": "asn_item_124", "sku": "USB-C-001", "product_name": "USB-C Charging Cable", "quantity_shipped": 1000, "quantity_ordered": 1000, "quantity_received": 0, "unit_cost": { "amount": 450, "currency": "USD" }, "lot_number": "LOT-2024-002", "status": "pending_receipt" } ], "packaging_details": { "total_packages": 10, "total_pallets": 2, "total_weight": { "value": 250, "unit": "lb" } }, "shipping_documents": [ { "type": "packing_list", "document_number": "PL-2024-00001", "url": "https://documents.stateset.com/packing-lists/PL-2024-00001.pdf" }, { "type": "proof_of_delivery", "document_number": "POD-2024-00001", "url": "https://documents.stateset.com/pod/POD-2024-00001.pdf" } ], "notes": "Please schedule receiving appointment. Fragile electronics.", "metadata": {} } ``` # Authentication Source: https://docs.stateset.com/api-reference/authentication Complete guide to authenticating with the Stateset API **Quick Start:** All API requests require authentication via API key in the `Authorization` header: ```bash theme={null} Authorization: Bearer sk_live_your_api_key_here ``` Stateset provides multiple authentication methods to secure your API access, including API keys, JWT tokens, and OAuth 2.0 for different use cases. ## Authentication Overview All data in Stateset is private by default, requiring authentication for every API request. We support multiple authentication methods: ### Supported Authentication Methods Best for server-to-server communication and backend integrations Ideal for user-specific access and session management Perfect for third-party integrations and partner access Secure webhook delivery with HMAC signatures ## API Key Authentication ### Key Types and Permissions | Key Type | Prefix | Use Case | Permissions | | ------------------- | ---------- | ---------------------- | --------------------- | | **Secret Key** | `sk_live_` | Server-side operations | Full API access | | **Restricted Key** | `rk_live_` | Limited scope access | Custom permissions | | **Publishable Key** | `pk_live_` | Client-side operations | Read-only public data | | **Test Key** | `sk_test_` | Development & testing | Sandbox environment | ### Creating API Keys 1. Navigate to **Settings → API Keys** in your dashboard 2. Click **Create New Key** 3. Select key type and permissions 4. Copy and securely store your key API keys are shown only once. Store them securely and never expose secret keys in client-side code. ### Using API Keys ```bash cURL theme={null} curl https://api.stateset.com/v1/orders \ -H "Authorization: Bearer sk_live_your_api_key_here" \ -H "Content-Type: application/json" ``` ```javascript Node.js theme={null} // Using environment variables (recommended) const headers = { 'Authorization': `Bearer ${process.env.STATESET_API_KEY}`, 'Content-Type': 'application/json' }; const response = await fetch('https://api.stateset.com/v1/orders', { headers }); ``` ```python Python theme={null} import os import requests headers = { 'Authorization': f'Bearer {os.getenv("STATESET_API_KEY")}', 'Content-Type': 'application/json' } response = requests.get( 'https://api.stateset.com/v1/orders', headers=headers ) ``` ### Restricted API Keys Create keys with specific permissions for enhanced security: ```javascript theme={null} // Creating a restricted key via API const restrictedKey = await stateset.apiKeys.create({ name: 'Read-only Orders Key', permissions: [ 'orders:read', 'customers:read' ], expires_at: '2024-12-31T23:59:59Z' }); ``` ## JWT Token Authentication JWT tokens provide secure, stateless authentication for user sessions. ### JWT Token Structure ```json theme={null} { "header": { "alg": "RS256", "typ": "JWT", "kid": "key_id_123" }, "payload": { "sub": "user_123", "org_id": "org_456", "role": "admin", "permissions": ["orders:*", "customers:*"], "iat": 1704067200, "exp": 1704070800, "iss": "https://api.stateset.com" }, "signature": "..." } ``` ## GraphQL API Authentication ### GraphQL Endpoint Access Stateset GraphQL API requires authentication via HTTP headers: ```graphql theme={null} # GraphQL endpoint https://api.stateset.com/graphql # Required headers Authorization: Bearer sk_live_your_api_key Content-Type: application/json ``` ### GraphQL Request Example ```javascript Apollo Client theme={null} import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; const httpLink = createHttpLink({ uri: 'https://api.stateset.com/graphql', }); const authLink = setContext((_, { headers }) => { const token = process.env.STATESET_API_KEY; return { headers: { ...headers, authorization: token ? `Bearer ${token}` : "", } } }); const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() }); ``` ```python Python GraphQL theme={null} import requests query = """ query GetOrders { orders(limit: 10) { id status total } } """ response = requests.post( 'https://api.stateset.com/graphql', json={'query': query}, headers={ 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } ) ``` ## OAuth 2.0 Authentication For third-party integrations and partner access, we support OAuth 2.0: ### OAuth Flow ```bash theme={null} GET https://api.stateset.com/oauth/authorize? client_id=YOUR_CLIENT_ID& redirect_uri=YOUR_REDIRECT_URI& response_type=code& scope=orders:read customers:read& state=RANDOM_STATE ``` ```bash theme={null} POST https://api.stateset.com/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=AUTH_CODE& client_id=YOUR_CLIENT_ID& client_secret=YOUR_CLIENT_SECRET& redirect_uri=YOUR_REDIRECT_URI ``` ```bash theme={null} GET https://api.stateset.com/v1/orders Authorization: Bearer ACCESS_TOKEN ``` ### Available Scopes | Scope | Description | | ----------------- | ------------------------ | | `orders:read` | Read order data | | `orders:write` | Create and update orders | | `customers:read` | Read customer data | | `customers:write` | Manage customers | | `inventory:read` | View inventory levels | | `inventory:write` | Update inventory | | `returns:*` | Full returns access | | `admin` | Full API access | ## Role-Based Access Control (RBAC) ### User Roles and Permissions Stateset implements fine-grained permissions using role-based access control: | Role | Description | Default Permissions | API Key Prefix | | ---------------- | -------------------- | -------------------------- | -------------- | | **anonymous** | Unauthenticated user | Public read-only endpoints | N/A | | **viewer** | Read-only access | All read operations | `rk_view_` | | **operator** | Standard user | CRUD on assigned resources | `sk_live_` | | **manager** | Team manager | CRUD on team resources | `sk_mgr_` | | **admin** | Full access | All operations | `sk_admin_` | | **super\_admin** | System admin | System configuration | `sk_super_` | ### Permission Matrix | Resource | Anonymous | Viewer | Operator | Manager | Admin | | --------- | --------- | ------ | ---------- | ------------- | ---------- | | Orders | ❌ | Read | CRUD (own) | CRUD (team) | CRUD (all) | | Customers | ❌ | Read | Read (own) | CRUD (team) | CRUD (all) | | Inventory | Read | Read | Read | CRUD | CRUD | | Returns | ❌ | Read | CRUD (own) | CRUD (team) | CRUD (all) | | Reports | ❌ | Read | Read (own) | Read (team) | CRUD | | Settings | ❌ | ❌ | Read (own) | Update (team) | CRUD | ### Custom Permissions with Session Variables Implement fine-grained access control using session variables: #### JWT Claims Structure ```json theme={null} { "https://hasura.io/jwt/claims": { "x-hasura-org-id": "org_123", "x-hasura-user-id": "user_456", "x-hasura-default-role": "operator", "x-hasura-allowed-roles": ["viewer", "operator", "manager"], "x-hasura-team-id": "team_789", "x-hasura-permissions": [ "orders:read", "orders:write", "customers:read" ] }, "iat": 1704067200, "exp": 1704070800 } ``` #### Permission Checks ```javascript theme={null} // Middleware for permission checking function requirePermission(permission) { return (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; const decoded = jwt.verify(token, process.env.JWT_SECRET); const claims = decoded['https://hasura.io/jwt/claims']; const permissions = claims['x-hasura-permissions'] || []; if (!permissions.includes(permission)) { return res.status(403).json({ error: 'INSUFFICIENT_PERMISSIONS', message: `Missing required permission: ${permission}` }); } req.user = { id: claims['x-hasura-user-id'], org_id: claims['x-hasura-org-id'], role: claims['x-hasura-default-role'], permissions }; next(); }; } // Usage app.post('/api/orders', requirePermission('orders:write'), createOrderHandler ); ``` ## Webhook Authentication ### Webhook Signature Verification All webhooks from Stateset are signed for security: ```javascript theme={null} const crypto = require('crypto'); class WebhookVerifier { constructor(secret) { this.secret = secret; } verify(payload, signature) { // Parse signature header const elements = signature.split(' '); const timestamp = elements.find(e => e.startsWith('t=')).slice(2); const signatures = elements .filter(e => e.startsWith('v1=')) .map(e => e.slice(3)); // Check timestamp (5 minute tolerance) const currentTime = Math.floor(Date.now() / 1000); if (currentTime - parseInt(timestamp) > 300) { throw new Error('Webhook timestamp expired'); } // Compute expected signature const signedPayload = `${timestamp}.${payload}`; const expectedSig = crypto .createHmac('sha256', this.secret) .update(signedPayload) .digest('hex'); // Timing-safe comparison const valid = signatures.some(sig => crypto.timingSafeEqual( Buffer.from(sig), Buffer.from(expectedSig) ) ); if (!valid) { throw new Error('Invalid webhook signature'); } return JSON.parse(payload); } } // Express middleware const webhookAuth = (req, res, next) => { const verifier = new WebhookVerifier(process.env.WEBHOOK_SECRET); try { req.body = verifier.verify( req.rawBody, req.headers['stateset-signature'] ); next(); } catch (error) { res.status(401).json({ error: 'Webhook verification failed' }); } }; ``` ## Security Best Practices * Store keys in environment variables, never in code * Use different keys for different environments * Rotate keys regularly (every 90 days recommended) * Use restricted keys with minimal permissions * Monitor key usage for anomalies * Implement short token lifetimes (15-30 minutes) * Use refresh tokens for long-lived sessions * Store tokens securely (httpOnly cookies) * Implement token revocation * Log all authentication events * Always use HTTPS for API calls * Implement IP allowlisting for production * Use VPN or private networks when possible * Enable CORS with specific origins * Implement rate limiting per API key ## Authentication Examples ### React Hook with Authentication ```jsx theme={null} import { useState, useEffect } from 'react'; import { useAuth } from '@clerk/nextjs'; /** * Custom hook for authenticated Stateset API calls */ export const useStatesetAPI = () => { const { getToken, isSignedIn } = useAuth(); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const apiCall = async (endpoint, options = {}) => { if (!isSignedIn) { throw new Error('User not authenticated'); } setLoading(true); setError(null); try { const token = await getToken({ template: 'stateset' }); const response = await fetch(`https://api.stateset.com/v1${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', ...options.headers } }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'API request failed'); } const data = await response.json(); return data; } catch (err) { setError(err); throw err; } finally { setLoading(false); } }; return { apiCall, loading, error }; }; // Usage function OrderList() { const { apiCall } = useStatesetAPI(); const [orders, setOrders] = useState([]); useEffect(() => { apiCall('/orders') .then(data => setOrders(data.orders)) .catch(console.error); }, []); return (
{orders.map(order => ( ))}
); } ``` ### Python Authentication Manager ```python theme={null} import os import time import requests from typing import Optional, Dict, Any from functools import wraps class StatesetAuth: def __init__(self, api_key: Optional[str] = None): self.api_key = api_key or os.getenv('STATESET_API_KEY') self.base_url = 'https://api.stateset.com/v1' self.session = requests.Session() self.session.headers.update({ 'Authorization': f'Bearer {self.api_key}', 'Content-Type': 'application/json' }) def validate_key(self) -> bool: """Validate API key is active""" try: response = self.session.get(f'{self.base_url}/auth/validate') return response.status_code == 200 except: return False def with_retry(self, max_retries: int = 3): """Decorator for automatic retry with exponential backoff""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): for attempt in range(max_retries): try: return func(*args, **kwargs) except requests.exceptions.RequestException as e: if attempt == max_retries - 1: raise wait_time = 2 ** attempt time.sleep(wait_time) return None return wrapper return decorator @with_retry(max_retries=3) def api_request( self, method: str, endpoint: str, data: Optional[Dict[Any, Any]] = None ) -> Dict[Any, Any]: """Make authenticated API request""" url = f'{self.base_url}{endpoint}' response = self.session.request(method, url, json=data) response.raise_for_status() return response.json() # Usage auth = StatesetAuth() if auth.validate_key(): orders = auth.api_request('GET', '/orders') print(f"Found {len(orders['data'])} orders") ``` ## Troubleshooting Authentication ### Common Issues and Solutions | Issue | Cause | Solution | | ----------------------- | ---------------------------- | ------------------------------- | | `401 Unauthorized` | Invalid or expired API key | Check key validity in dashboard | | `403 Forbidden` | Insufficient permissions | Verify key has required scopes | | `429 Too Many Requests` | Rate limit exceeded | Implement exponential backoff | | `CORS Error` | Cross-origin request blocked | Use server-side proxy or SDK | | `Signature Mismatch` | Invalid webhook secret | Verify webhook secret matches | ### Debug Authentication ```bash theme={null} # Test API key validity curl -I https://api.stateset.com/v1/auth/validate \ -H "Authorization: Bearer YOUR_API_KEY" # Check key permissions curl https://api.stateset.com/v1/auth/permissions \ -H "Authorization: Bearer YOUR_API_KEY" ``` *** **Next Steps:** [Create your first API request →](/api-reference/quickstart) # StateSet API Source: https://docs.stateset.com/api-reference/backend-framework A high-performance, scalable backend framework built with Rust, Axum, and SeaORM for enterprise-grade applications. # StateSet API: A Robust Backend Framework StateSet API is a modern, scalable, and reliable backend system designed for enterprise-grade web services. Built with Rust, it leverages cutting-edge web technologies and best practices to deliver a high-performance infrastructure solution. It is particularly well-suited for e-commerce and manufacturing businesses, adept at handling order management, inventory control, returns processing, warranty management, shipment tracking, and work order handling. ## Core Features StateSet API is built to handle complex business operations. Here's a breakdown of its key features: * **Order Management:** Full CRUD operations for orders, support for complex workflows and statuses. * **Inventory Control:** Real-time tracking across multiple locations, automated reorder point notifications. * **Returns Processing:** Streamlined return authorization, processing, and integration with refund and exchange systems. * **Warranty Management:** Track and manage product warranties, handle automated claim processing. * **Shipment Tracking:** Real-time integration with major carriers, custom shipment status notifications. * **Manufacturing & Production:** Supplier management, BOM tracking, and version control. * **Work Order Handling:** Create and manage work orders, track progress, and manage resource allocation. ## Tech Stack: The Foundation of Performance Our carefully selected tech stack ensures high performance, scalability, and maintainability. ### Core Technologies * **Language:** [Rust](https://www.rust-lang.org/) (for performance, safety, and concurrency) * **Web Framework:** [Axum](https://github.com/tokio-rs/axum/) (a lightweight, async, and fast web framework) * **Database:** [PostgreSQL](https://www.postgresql.org/) (for robust, reliable data storage) with [SQLx](https://github.com/launchbadge/sqlx) (for async operations). ### ORM and Query Building * [SeaORM](https://www.sea-ql.org/SeaORM) (a powerful async ORM for Rust). ### API Protocols and Services * **REST:** Implemented natively with Axum. * **GraphQL:** Implemented using [Async-GraphQL](https://async-graphql.github.io/) for a high-performance GraphQL API. * **gRPC:** Built with [Tonic](https://github.com/hyperium/tonic) for efficient, type-safe gRPC support. ### Caching and Messaging * **Caching:** [Redis](https://redis.io/) for high-speed data caching. * **Message Queue:** [RabbitMQ](https://www.rabbitmq.com/) for reliable asynchronous processing. ### Observability * **Metrics:** [Prometheus](https://prometheus.io/) for detailed system monitoring. * **Tracing:** [OpenTelemetry](https://opentelemetry.io/) with [Jaeger](https://www.jaegertracing.io/) for distributed tracing. * **Logging:** [slog](https://docs.rs/slog/latest/slog/) for structured, efficient logging. ### Technological Advantages: * **Rust's Performance & Safety:** Guarantees memory safety and prevents common programming errors, leading to a highly reliable and performant API. * **Asynchronous Operations:** Utilizing Rust's async capabilities for high-throughput and non-blocking processing. * **Comprehensive Observability:** Enables proactive maintenance and rapid issue resolution. * **Flexible API Protocols:** Supports various API protocols, ensuring integration with different client applications and services. ### Use Cases: * **E-commerce Platforms:** Efficiently manage orders, inventory, shipments, and customer interactions. * **Manufacturing Systems:** Streamline production workflows, inventory control, supplier management, and quality assurance. * **Enterprise Solutions:** Provides a scalable backend infrastructure for a wide variety of business operations and services. ## Architecture: Modular and Event-Driven StateSet API adopts a modular, asynchronous, event-driven architecture designed for scalability and maintainability. ```mermaid theme={null} flowchart TB Client[Client] subgraph API["StateSet API"] direction TB Handlers[Handlers] Commands[Commands] Queries[Queries] Services[Services] Models[Models] Middleware[Middleware] end subgraph Core["Core Technologies"] direction LR Rust[Rust] Axum[Axum] PostgreSQL[PostgreSQL] end subgraph Data["Data Layer"] direction LR SeaORM[SeaORM] SQLx[SQLx] end subgraph Protocols["API Protocols"] direction TB REST[REST] GraphQL[Async-GraphQL] gRPC[Tonic gRPC] end subgraph Cache["Caching & Messaging"] direction LR Redis[Redis] RabbitMQ[RabbitMQ] end subgraph Observability["Observability"] direction TB Prometheus[Prometheus] OpenTelemetry[OpenTelemetry] Jaeger[Jaeger] Slog[Slog] end Client --> Protocols Protocols --> API API --> Core API --> Data API --> Cache API --> Observability Core --> PostgreSQL Data --> PostgreSQL ``` ### Key Components * **Services:** Implement the core business logic for specific functionalities. * **Handlers:** Process incoming HTTP requests, routing them to the appropriate logic. * **Commands:** Handle operations that modify data or state in the system (writes). * **Queries:** Handle read operations, retrieving data without modifying it. * **Events:** Enable asynchronous communication and processing through event triggers. * **Models:** Represent domain entities, providing a structured data layer. * **Middleware:** Handle cross-cutting concerns like authentication, rate limiting, and logging. ## Performance and Reliability StateSet API is engineered for high performance and reliability: * Handles 10,000+ requests per second on a single node (This is a claim. If you have concrete benchmarks include them here or state in which conditions you measured this). * Scales horizontally to accommodate increased load. * Designed for 99.99% uptime SLA (Include specifics if this is part of an actual SLA). ## Code Examples Here are some representative code snippets to demonstrate the implementation. ### Axum Web Service Entrypoint This code sets up the Axum web service, including routes, middleware, and integration with other services. ```rust theme={null} #[tokio::main] async fn main() -> Result<(), AppError> { dotenv().ok(); let config = Arc::new(config::load()?); let log = setup_logger(&config); info!(log, "Starting StateSet API"; "environment" => &config.environment, "version" => env!("CARGO_PKG_VERSION") ); let app_state = build_app_state(&config, &log).await?; let schema = Arc::new(graphql::create_schema( app_state.services.order_service.clone(), // ... other service clones )); setup_telemetry(&config)?; // Spawn event processing tokio::spawn(events::process_events( app_state.event_sender.subscribe(), app_state.services.clone(), log.clone(), )); // Start gRPC server (conditionally included) #[cfg(feature = "grpc")] let grpc_server = grpc_server::start(config.clone(), app_state.services.clone()).await?; let app = Router::new() .route("/health", get(health::health_check)) .nest("/orders", handlers::orders::routes()) // ... other route nests .route("/proto_endpoint", post(handle_proto_request)) .layer(Extension(app_state)) .layer(Extension(schema)) .layer(TraceLayer::new_for_http()) .layer(CompressionLayer::new()) .layer(axum::middleware::from_fn(auth::auth_middleware)) .layer(axum::middleware::from_fn(rate_limiter::rate_limit_middleware)); let addr = format!("{}:{}", config.host, config.port); info!(log, "StateSet API server running"; "address" => &addr); axum::Server::bind(&addr.parse().unwrap()) .serve(app.into_make_service()) .await .unwrap(); info!(log, "Shutting down"); Ok(()) } ``` > This shows the main entry point of the server including the config loading, setup of global services, the route definition, telemetry and the server startup ### Handlers: API Request Routing Here are some examples of how API requests are routed to the correct command. #### Create Order Handler ```rust theme={null} async fn create_order( State(order_service): State>, Json(command): Json, ) -> Result { let result = command.execute(order_service).await?; Ok(Json(result)) } ``` > This handler pulls the OrderService from the application state and calls the execute method on the CreateOrderCommand #### Close Return Handler ```rust theme={null} async fn close_return( State(return_service): State>, Path(return_id): Path, ) -> Result { let command = CloseReturnCommand { return_id }; let closed_return = command.execute(return_service).await?; Ok(Json(closed_return)) } ``` > This handler pulls the ReturnService from the application state and calls the execute method on the CloseReturnCommand ### Commands: Business Logic Execution The following shows the Create Order and Close Return commands which handle the business logic. #### Create Order Command ```rust theme={null} #[derive(Debug, Serialize, Deserialize, Validate)] pub struct CreateOrderCommand { pub customer_id: Uuid, #[validate(length(min = 1, message = "At least one item is required"))] pub items: Vec, } #[derive(Debug, Serialize, Deserialize)] pub struct OrderItem { pub product_id: Uuid, #[validate(range(min = 1))] pub quantity: i32, } #[derive(Debug, Serialize, Deserialize)] pub struct CreateOrderResult { pub id: Uuid, pub customer_id: Uuid, pub status: String, pub created_at: DateTime, pub items: Vec, } #[async_trait::async_trait] impl Command for CreateOrderCommand { type Result = CreateOrderResult; #[instrument(skip(self, db_pool, event_sender))] async fn execute( &self, db_pool: Arc, event_sender: Arc, ) -> Result { // Validates the incoming command. Returns a validation error if invalid self.validate().map_err(|e| { ORDER_CREATION_FAILURES.inc(); let msg = format!("Invalid input: {}", e); error!("{}", msg); ServiceError::ValidationError(msg) })?; let db = db_pool.as_ref(); let saved_order = self.create_order(db).await?; self.log_and_trigger_event(&event_sender, &saved_order).await?; ORDER_CREATIONS.inc(); Ok(CreateOrderResult { id: saved_order.id, customer_id: saved_order.customer_id, status: saved_order.status, created_at: saved_order.created_at.and_utc(), items: self.items.clone(), }) } } // ... create order implementation ``` > This shows the command definition, validation, and execution of the create order command. #### Close Return Command ```rust theme={null} #[derive(Debug, Serialize, Deserialize)] pub struct CloseReturnCommand { pub return_id: Uuid, } #[derive(Debug, Serialize, Deserialize)] pub struct CloseReturnResult { pub id: Uuid, pub object: String, pub completed: bool, } #[async_trait::async_trait] impl Command for CloseReturnCommand { type Result = CloseReturnResult; #[instrument(skip(self, db_pool, event_sender))] async fn execute( &self, db_pool: Arc, event_sender: Arc, ) -> Result { let db = db_pool.as_ref(); let completed_return = self.close_return(db).await?; self.log_and_trigger_event(&event_sender, &completed_return) .await?; Ok(CloseReturnResult { id: completed_return.id, object: "return".to_string(), completed: true, }) } } // ... close return implementation ``` > This shows the command definition, and execution of the close return command. ### Queries: Data Retrieval These show the two return queries used by the application. #### Get Returns By Order Query ```rust theme={null} #[derive(Debug, Serialize, Deserialize)] pub struct GetReturnsByOrderQuery { pub order_id: i32, } #[async_trait] impl Query for GetReturnsByOrderQuery { type Result = Vec; async fn execute(&self, db_pool: Arc) -> Result { let db = db_pool.get().map_err(|_| ServiceError::DatabaseError)?; Return::find() .filter(Return::Column::OrderId.eq(self.order_id)) .all(&db) .await .map_err(|_| ServiceError::DatabaseError) } } ``` > This shows how we can find the returns based on the order ID using SeaORM #### Get Returns By Date Range Query ```rust theme={null} #[derive(Debug, Serialize, Deserialize)] pub struct GetReturnsByDateRangeQuery { pub start_date: DateTime, pub end_date: DateTime, pub limit: u64, pub offset: u64, } #[async_trait] impl Query for GetReturnsByDateRangeQuery { type Result = Vec; async fn execute(&self, db_pool: Arc) -> Result { let db = db_pool.get().map_err(|_| ServiceError::DatabaseError)?; Return::find() .filter(Return::Column::CreatedAt.between(self.start_date, self.end_date)) .order_by_desc(Return::Column::CreatedAt) .limit(self.limit) .offset(self.offset) .all(&db) .await .map_err(|_| ServiceError::DatabaseError) } } ``` > This shows how we can find the returns based on a date range using SeaORM. To learn more about SeaORM, check out [this article](https://www.sea-ql.org/blog/2024-08-04-sea-orm-1.0/). ## Acknowledgments We express our gratitude to the open-source community and the creators of the following libraries: * [Axum](https://github.com/tokio-rs/axum/) for the powerful web framework. * [SeaORM](https://www.sea-ql.org/SeaORM) for providing a robust ORM. * [Tonic](https://github.com/hyperium/tonic) for enabling gRPC support. * [Async-GraphQL](https://async-graphql.github.io/) for efficient GraphQL handling. # Build to Stock Source: https://docs.stateset.com/api-reference/billofmaterials/buildtostock POST https://api.stateset.com/v1/bill_of_materials/:id/buildtostock This endpoint updates the status of a bill of materials to build to stock. ### Body The ID provided in the data tab may be used to identify the bill\_of\_materials ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/bill_of_materials/:id/buildtostock' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```js Node.js theme={null} const buildToStock = await stateset.billofmaterials.buildToStock({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "bill_of_materials", "built_to_stock": true } ``` # Create Bill of Materials Source: https://docs.stateset.com/api-reference/billofmaterials/create POST https://api.stateset.com/v1/bill_of_materials This endpoint creates a new bill of materials ### Body This is the id of the bill of materials This is the number of the bill of materials This is the name of the bill of materials This is the description of the bill of materials This is the groups of the bill of materials This is the date and time when the bill of materials was created This is the date and time when the bill of materials was last updated This indicates whether the bill of materials is valid or not ### Response This is the id of the bill of materials. This is the number of the bill of materials. This is the name of the bill of materials. This is the description of the bill of materials. This is the groups of the bill of materials. This is the date and time when the bill of materials was created. This is the date and time when the bill of materials was last updated. This indicates whether the bill of materials is valid or not. This is an array of line items associated with the bill of materials. This is the id of the line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the number or code associated with the part or item. This is the name of the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/bill_of_materials' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b" }' ``` ```graphQL GraphQL theme={null} mutation addBillOfMaterial($bill_of_material: bill_of_materials_insert_input!) { insert_bill_of_materials(objects: [$bill_of_material]) { returning { id } } } ``` ```javascript Node.js theme={null} const created = await stateset.billofmaterials.create( 'bom_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} created = stateset.billofmaterials.create( 'bom_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} created = Stateset::BillOfMaterials.create( 'bom_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $created = $stateset->billofmaterials->create( 'bom_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} created, err := stateset.BillOfMaterials.Create( 'bom_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} BillOfMaterials created = stateset.billOfMaterials.create( 'bom_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "name": "Bill of Materials", "description": "Bill of Materials", "groups": "Bill of Materials", "created_at": "2021-01-01T00:00:00.000Z", "updated_at": "2021-01-01T00:00:00.000Z", "valid": true, "line_items": [ { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "bill_of_materials_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "line_type": "Bill of Materials", "part_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "part_name": "Bill of Materials", "purchase_supply_type": "Bill of Materials", "quantity": 1, "status": "Bill of Materials" } ] } } ``` # Delete Bill Of Materials Source: https://docs.stateset.com/api-reference/billofmaterials/delete DELETE https://api.return.com/v1/bill_of_materials This endpoint deletes an existing bill of materials. ### Body The id of the bill of materials to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/bill_of_materials' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "bom_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteBillOfMaterials ($id: String!) { delete_bill_of_materials(where: {id: {_eq: $id}}) { affected_rows } } ``` ```javascript Node.js theme={null} const billOfMaterials = await stateset.billofmaterials.del({ 'bom_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```python Python theme={null} billOfMaterials = stateset.billofmaterials.del({ 'bom_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```ruby Ruby theme={null} billOfMaterials = Stateset::BillOfMaterials.delete({ 'bom_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $billOfMaterials = $stateset->billOfMaterials->delete([ 'bom_1NXWPnCo6bFb1KQto6C8OWvE' ]); ``` ```go Go theme={null} billOfMaterials, err := stateset.BillOfMaterials.Delete( "bom_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} BillOfMaterials billOfMaterials = stateset.billOfMaterials.delete( "bom_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```json Response theme={null} { "id": "bom_1NXWPnCo6bFb1KQto6C8OWvE", "object": "billofmaterials", "deleted": true } ``` # Get Bill Of Materials Source: https://docs.stateset.com/api-reference/billofmaterials/get GET https://api.stateset.com/v1/bill_of_materials/:id This endpoint gets or creates a new bill of materials. ### Body This is the id of the bill of materials to get. If the id is not provided, a new bill of materials will be created. ### Response This is the id of the bill of materials. This is the number of the bill of materials. This is the name of the bill of materials. This is the description of the bill of materials. This is the groups of the bill of materials. This is the date and time when the bill of materials was created. This is the date and time when the bill of materials was last updated. This indicates whether the bill of materials is valid or not. This is an array of line items associated with the bill of materials. This is the id of the line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the number or code associated with the part or item. This is the name of the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/bill_of_materials' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b" }' ``` ```graphQL GraphQL theme={null} query MyBillOfMaterials { bill_of_materials { created_at description groups id number name updated_at valid bill_of_material_line_items { bill_of_materials_number id line_type part_name part_number purchase_supply_type quantity status } } } ``` ```js Node.js theme={null} var billOfMaterials = stateset.billofmaterials.retrieve({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }); ``` ```python Python theme={null} bill_of_materials = stateset.billofmaterials.retrieve({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }) ``` ```ruby Ruby theme={null} bill_of_materials = Stateset::BillOfMaterials.retreive({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }) ``` ```php PHP theme={null} $bill_of_materials = $stateset->billofmaterials->retrieve({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }); ``` ```go Go theme={null} bill_of_materials, err := stateset.BillOfMaterials.Retrieve({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }) ``` ```java Java theme={null} BillOfMaterials billOfMaterials = stateset.billOfMaterials.retrieve({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }); ``` ```json Response theme={null} { { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "name": "Bill of Materials", "description": "Bill of Materials", "groups": "Bill of Materials", "created_at": "2021-01-01T00:00:00.000Z", "updated_at": "2021-01-01T00:00:00.000Z", "valid": true, "line_items": [ { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "bill_of_materials_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "line_type": "Bill of Materials", "part_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "part_name": "Bill of Materials", "purchase_supply_type": "Bill of Materials", "quantity": 1, "status": "Bill of Materials" } ] } } ``` ### Bill Of Materials | Name | Type | Description | | ----------- | --------- | ------------------------------------------------------------- | | created\_at | Date/Time | Date and time when the bill of materials was created | | description | Text | Description or additional details about the bill of materials | | groups | Text | Groups or categories associated with the bill of materials | | id | Text | Unique identifier for the bill of materials | | number | Text | Number associated with the bill of materials | | name | Text | Name of the bill of materials | | updated\_at | Date/Time | Date and time when the bill of materials was last updated | | valid | Boolean | Indicates whether the bill of materials is valid or not | ### Bill Of Materials Line Item | Name | Type | Description | | --------------------------- | ------- | --------------------------------------------------------------------------- | | bill\_of\_materials\_number | Text | Number associated with the bill of materials to which the line item belongs | | id | Text | Unique identifier for the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the bill of materials | | part\_number | Text | Number or code associated with the part or item | | purchase\_supply\_type | Text | Type or category of the purchase/supply associated with the line item | | quantity | Numeric | Quantity of the part or item required in the bill of materials | | status | Text | Status or state of the line item | # List Bill Of Materials Source: https://docs.stateset.com/api-reference/billofmaterials/list GET https://api.stateset.com/v1/bill_of_materials/list This endpoint lists the bill of materials. ### Body This is the limit of the bill of materials. This is the offset of the bill of materials. This is the order direction of the bill of materials. ### Response This is the id of the bill of materials. This is the number of the bill of materials. This is the name of the bill of materials. This is the description of the bill of materials. This is the groups of the bill of materials. This is the date and time when the bill of materials was created. This is the date and time when the bill of materials was last updated. This indicates whether the bill of materials is valid or not. This is an array of line items associated with the bill of materials. This is the id of the line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the number or code associated with the part or item. This is the name of the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/bill_of_materials' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { bill_of_materials(limit: $limit, offset: $offset, order_by: {created_at: $order_direction}) { created_at description groups id number name updated_at valid bill_of_material_line_items { bill_of_materials_number id line_type part_name part_number purchase_supply_type quantity status } } } ``` ```js Node.js theme={null} var billOfMaterials = stateset.billofmaterials.list({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }); ``` ```python Python theme={null} bill_of_materials = stateset.billofmaterials.list({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }) ``` ```ruby Ruby theme={null} bill_of_materials = Stateset::BillOfMaterials.retreive({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }) ``` ```php PHP theme={null} $bill_of_materials = $stateset->billofmaterials->list({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }); ``` ```go Go theme={null} bill_of_materials, err := stateset.BillOfMaterials.list({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }) ``` ```java Java theme={null} BillOfMaterials billOfMaterials = stateset.billOfMaterials.list({ '5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b' }); ``` ```json Response theme={null} { { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "name": "Bill of Materials", "description": "Bill of Materials", "groups": "Bill of Materials", "created_at": "2021-01-01T00:00:00.000Z", "updated_at": "2021-01-01T00:00:00.000Z", "valid": true, "line_items": [ { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "bill_of_materials_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "line_type": "Bill of Materials", "part_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "part_name": "Bill of Materials", "purchase_supply_type": "Bill of Materials", "quantity": 1, "status": "Bill of Materials" } ] } } ``` ### Bill Of Materials | Name | Type | Description | | ----------- | --------- | ------------------------------------------------------------- | | created\_at | Date/Time | Date and time when the bill of materials was created | | description | Text | Description or additional details about the bill of materials | | groups | Text | Groups or categories associated with the bill of materials | | id | Text | Unique identifier for the bill of materials | | number | Text | Number associated with the bill of materials | | name | Text | Name of the bill of materials | | updated\_at | Date/Time | Date and time when the bill of materials was last updated | | valid | Boolean | Indicates whether the bill of materials is valid or not | ### Bill Of Materials Line Item | Name | Type | Description | | --------------------------- | ------- | --------------------------------------------------------------------------- | | bill\_of\_materials\_number | Text | Number associated with the bill of materials to which the line item belongs | | id | Text | Unique identifier for the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the bill of materials | | part\_number | Text | Number or code associated with the part or item | | purchase\_supply\_type | Text | Type or category of the purchase/supply associated with the line item | | quantity | Numeric | Quantity of the part or item required in the bill of materials | | status | Text | Status or state of the line item | # Update Bill of Materials Source: https://docs.stateset.com/api-reference/billofmaterials/update PUT https://api.stateset.com/v1/bill_of_materials/:id This endpoint updates an existing bill of materials. ### Body This is the id of the bill of materials This is the number of the bill of materials This is the name of the bill of materials This is the description of the bill of materials This is the groups of the bill of materials This is the date and time when the bill of materials was created This is the date and time when the bill of materials was last updated This indicates whether the bill of materials is valid or not ### Response This is the id of the bill of materials. This is the number of the bill of materials. This is the name of the bill of materials. This is the description of the bill of materials. This is the groups of the bill of materials. This is the date and time when the bill of materials was created. This is the date and time when the bill of materials was last updated. This indicates whether the bill of materials is valid or not. This is an array of line items associated with the bill of materials. This is the id of the line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the number or code associated with the part or item. This is the name of the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/bill_of_materials' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```javascript Node.js theme={null} const updated = await stateset.billofmaterials.update( 'bom_ODkRWQtx9NVsRX' ); ``` ```graphQL GraphQL theme={null} mutation ( $id: String $bill_of_materials: bill_of_materials_set_input! ) { update_bill_of_materials ( where: { id : { _eq: $id}} _set: $bill_of_materials ) { returning { created_at description groups id number name updated_at valid } } }`; ``` ```python Python theme={null} updated = stateset.billofmaterials.update( 'bom_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} updated = Stateset::BillOfMaterials.update( 'bom_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $updated = $stateset->billofmaterials->update( 'bom_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} updated, err := stateset.BillOfMaterials.Update( 'bom_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} BillOfMaterials updated = stateset.billOfMaterials.update( 'bom_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "name": "Bill of Materials", "description": "Bill of Materials", "groups": "Bill of Materials", "created_at": "2021-01-01T00:00:00.000Z", "updated_at": "2021-01-01T00:00:00.000Z", "valid": true, "line_items": [ { "id": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "bill_of_materials_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "line_type": "Bill of Materials", "part_number": "5f7b1b4a-5b0b-4b0a-8b0b-4b0a5b0b4a5b", "part_name": "Bill of Materials", "purchase_supply_type": "Bill of Materials", "quantity": 1, "status": "Bill of Materials" } ] } } ``` # Create Bill of Materials Line Item Source: https://docs.stateset.com/api-reference/billofmaterialslineitem/create POST https://api.stateset.com/api/bill_of_materials_line_items This endpoint creates a new bill of materials line item. ### Body This is the id of the bill of materials line item. This is the part number of the bill of materials line item. This is the part name of the bill of materials line item. This is the quantity of the bill of materials line item. This is the purchase supply type of the bill of materials line item. This is the bill of materials number of the bill of materials line item. ### Response This is the id of the bill of materials line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the name of the part or item included in the bill of materials. This is the number or code associated with the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/api/bill_of_materials_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```graphQL GraphQL theme={null} mutation AddBillOfMaterialLineItem($bill_of_material_line_item: bill_of_material_line_items_insert_input!) { insert_bill_of_material_line_items(objects: [$bill_of_material_line_item]) { returning { ...BillOfMaterialLineItemFields } } } fragment BillOfMaterialLineItemFields on bill_of_material_line_items { id part_number part_name quantity purchase_supply_type bill_of_materials_number } ``` ```js Node.js theme={null} const created = await stateset.billofmaterialItems.create( 'bomi_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} created = stateset.billofmaterialItems.create( 'bomi_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} created = Stateset::BillOfMaterialItems.create( 'bomi_ODkRWQtx9NVsRX' ) ``` ```go Golang theme={null} created, err := stateset.BillOfMaterialItems.Create( 'bomi_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} BillOfMaterialItems created = stateset.billOfMaterialItems.create( 'bomi_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { { "data": { "insert_bill_of_material_line_items": { "returning": [ { "id": "bomli_1", "bill_of_materials_number": "bom_1", "line_type": "part", "part_name": "Part 1", "part_number": "P1", "purchase_supply_type": "purchase", "quantity": 1, "status": "active" } ] } } } } ``` # Delete Bill of Materials Line Item Source: https://docs.stateset.com/api-reference/billofmaterialslineitem/delete DELETE https://api.return.com/v1/bill_of_materials_line_items/:id This endpoint deletes an existing bill of materials line item. ### Body The id of the bill of materials line item you want to delete ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/bill_of_materials_line_item/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```graphQL GraphQL theme={null} mutation deleteBillOfMaterialLineItem($bill_of_material_line_item_id: uuid!) { delete_bill_of_material_line_items(where: { id: { _eq: $bill_of_material_line_item_id } }) { affected_rows } } ``` ```javascript Node.js theme={null} const created = await stateset.billofmaterialItems.del( 'bomi_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} created = stateset.billofmaterialItems.del( 'bomi_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} created = Stateset::BillofmaterialItems.del( 'bomi_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $created = $stateset->billofmaterialItems->del( 'bomi_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} created, err := stateset.BillofmaterialItems.Del( 'bomi_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} BillofmaterialItemsResponse created = stateset.billofmaterialItems.del( 'bomi_ODkRWQtx9NVsRX' ); ``` ```csharp C# theme={null} var created = stateset.BillofmaterialItems.Del( 'bomi_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "id": "bomi_1NXWPnCo6bFb1KQto6C8OWvE", "object": "bill_of_materials_line_item", "deleted": true } ``` # Get Bill of Materials Line Item Source: https://docs.stateset.com/api-reference/billofmaterialslineitem/get GET https://api.stateset.com/v1/bill_of_materials_line_items/:id This endpoint gets or creates a new bill of materials line item. ### Body This is the id of the bill of materials line item. If this is not provided, a new bill of materials line item will be created. ### Response This is the id of the bill of materials line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the name of the part or item included in the bill of materials. This is the number or code associated with the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/bill_of_materials_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ 'id': '1' }' ``` ```json Response theme={null} { { "id": "1", "bill_of_materials_number": "1", "line_type": "1", "part_name": "1", "part_number": "1", "purchase_supply_type": "1", "quantity": "1", "status": "1" } } ``` ### Bill Of Materials Line Item | Name | Type | Description | | --------------------------- | ------- | --------------------------------------------------------------------------- | | bill\_of\_materials\_number | Text | Number associated with the bill of materials to which the line item belongs | | id | Text | Unique identifier for the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the bill of materials | | part\_number | Text | Number or code associated with the part or item | | purchase\_supply\_type | Text | Type or category of the purchase/supply associated with the line item | | quantity | Numeric | Quantity of the part or item required in the bill of materials | | status | Text | Status or state of the line item | # Update Bill of Materials Line Item Source: https://docs.stateset.com/api-reference/billofmaterialslineitem/update PUT https://api.stateset.com/v1/bill_of_materials_line_items/:id This endpoint updates an existing bill of materials line item. ### Body This is the id of the bill of materials line item. This is the part number of the bill of materials line item. This is the part name of the bill of materials line item. This is the quantity of the bill of materials line item. This is the purchase supply type of the bill of materials line item. This is the bill of materials number of the bill of materials line item. ### Response This is the id of the bill of materials line item. This is the number of the bill of materials to which the line item belongs. This is the type or category of the line item. This is the name of the part or item included in the bill of materials. This is the number or code associated with the part or item. This is the type or category of the purchase/supply associated with the line item. This is the quantity of the part or item required in the bill of materials. This is the status or state of the line item. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/bill_of_materials_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```graphQL GraphQL theme={null} mutation ( $id: uuid $bill_of_material_line_item: bill_of_material_line_items_set_input! ) { update_bill_of_material_line_items( where: { id: { _eq: $id } } _set: $bill_of_material_line_item ) { returning { id } } } ``` ```javascript Node.js theme={null} const update = await stateset.billofmaterialItems.update( 'bomi_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} update = stateset.billofmaterialItems.update( 'bomi_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} update = Stateset::BillofmaterialItems.update( 'bomi_ODkRWQtx9NVsRX' ) ``` ```json Response theme={null} { "data": { "update_bill_of_material_line_items": { "returning": [ { "id": "bomi_ODkRWQtx9NVsRX" } ] } } } ``` # Add Item to Cart Source: https://docs.stateset.com/api-reference/cart/add-item POST https://api.stateset.com/v1/carts/:id/items Add a product to an existing cart This endpoint adds one or more items to a cart. If the item already exists, it updates the quantity. Inventory availability is checked in real-time. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart ## Request Body Product ID to add Product variant ID (required if product has variants) Quantity to add (must be positive) Custom price in cents (requires special permissions) Special instructions for this item Custom fields for the item Check inventory availability before adding Replace existing quantity instead of adding to it ### Response Returns the updated cart object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/items' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "product_id": "prod_789", "variant_id": "var_red_medium", "quantity": 1, "notes": "Gift wrap please" }' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.addItem( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { product_id: "prod_789", variant_id: "var_red_medium", quantity: 1, notes: "Gift wrap please" } ); ``` ```python Python theme={null} cart = stateset.carts.add_item( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', product_id="prod_789", variant_id="var_red_medium", quantity=1, notes="Gift wrap please" ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "quantity": 2, "unit_price": 9999, "subtotal": 19998 }, { "id": "ci_def456", "product_id": "prod_456", "product_name": "USB-C Cable", "quantity": 1, "unit_price": 1999, "subtotal": 1999 }, { "id": "ci_ghi789", "product_id": "prod_789", "variant_id": "var_red_medium", "product_name": "T-Shirt", "variant_name": "Red - Medium", "quantity": 1, "unit_price": 2499, "subtotal": 2499, "notes": "Gift wrap please", "inventory_status": "in_stock", "available_quantity": 15 } ], "item_count": 4, "unique_item_count": 3, "subtotal": 24496, "tax_amount": 0, "shipping_amount": 0, "discount_amount": 2000, "total": 22496, "updated_at": "2024-06-20T15:00:00Z", "last_activity": "2024-06-20T15:00:00Z", "messages": [ { "type": "info", "message": "Item added successfully" } ] } ``` # Apply Coupon Source: https://docs.stateset.com/api-reference/cart/apply-coupon POST https://api.stateset.com/v1/carts/:id/coupons Apply a coupon or promotion code to the cart This endpoint applies a coupon code to the cart. The system validates the coupon and calculates applicable discounts based on cart contents and customer eligibility. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart ## Request Body Coupon or promotion code to apply Only validate without applying (preview discount) ### Response Returns the updated cart with applied discount. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/coupons' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "code": "WELCOME10" }' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.applyCoupon( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { code: "WELCOME10" } ); ``` ```python Python theme={null} cart = stateset.carts.apply_coupon( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', code="WELCOME10" ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "quantity": 3, "unit_price": 9999, "subtotal": 29997, "discounts": [ { "promotion_id": "promo_welcome10", "code": "WELCOME10", "amount": 2999, "type": "percentage" } ], "final_price": 26997 }, { "id": "ci_ghi789", "product_id": "prod_789", "quantity": 1, "unit_price": 2499, "subtotal": 2499, "discounts": [ { "promotion_id": "promo_welcome10", "code": "WELCOME10", "amount": 250, "type": "percentage" } ], "final_price": 2249 } ], "subtotal": 32496, "discount_amount": 3249, "tax_amount": 2268, "shipping_amount": 599, "total": 32114, "applied_coupons": [ { "code": "WELCOME10", "promotion_id": "promo_welcome10", "promotion_name": "Welcome 10% Off", "discount_amount": 3249, "applied_at": "2024-06-20T16:30:00Z" } ], "messages": [ { "type": "success", "message": "Coupon applied successfully. You saved $32.49!" } ] } ``` # Checkout Cart Source: https://docs.stateset.com/api-reference/cart/checkout POST https://api.stateset.com/v1/carts/:id/checkout Convert a cart into an order and process payment This endpoint initiates the checkout process, converting a cart into an order. It validates inventory, calculates final totals, and processes payment. ## Authentication This endpoint requires a valid API key with `carts:write` and `orders:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart to checkout ## Request Body Payment method details Payment type: "card", "ach", "wire", "purchase\_order" Saved payment method ID Card details (if not using saved method) Card number Expiration month Expiration year CVC code Billing address Street address Apartment, suite, etc. City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Shipping address (uses billing if not provided) Same structure as billing address Selected shipping method ID Special instructions for the order Purchase order number (for B2B) Additional order metadata ### Response Returns the created order object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/checkout' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "payment_method": { "type": "card", "payment_method_id": "pm_saved_123" }, "billing_address": { "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "shipping_method_id": "ship_standard", "customer_note": "Please leave at front door" }' ``` ```javascript Node.js theme={null} const order = await stateset.carts.checkout( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { payment_method: { type: "card", payment_method_id: "pm_saved_123" }, billing_address: { line1: "123 Main St", city: "San Francisco", state: "CA", postal_code: "94105", country: "US" }, shipping_method_id: "ship_standard", customer_note: "Please leave at front door" } ); ``` ```python Python theme={null} order = stateset.carts.checkout( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', payment_method={ "type": "card", "payment_method_id": "pm_saved_123" }, billing_address={ "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, shipping_method_id="ship_standard", customer_note="Please leave at front door" ) ``` ```json Response theme={null} { "id": "order_123456", "object": "order", "cart_id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "order_number": "ORD-2024-123456", "customer_id": "cust_abc123", "status": "processing", "payment_status": "paid", "fulfillment_status": "unfulfilled", "items": [ { "id": "oi_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "sku": "WH-BL-L", "quantity": 3, "unit_price": 9999, "discount_amount": 2999, "subtotal": 26997 }, { "id": "oi_def456", "product_id": "prod_789", "variant_id": "var_red_medium", "product_name": "T-Shirt", "variant_name": "Red - Medium", "sku": "TS-RD-M", "quantity": 1, "unit_price": 2499, "discount_amount": 250, "subtotal": 2249 } ], "subtotal": 32496, "discount_amount": 3249, "tax_amount": 2268, "shipping_amount": 599, "total": 32114, "currency": "USD", "payment": { "id": "pay_xyz789", "method": "card", "last4": "4242", "brand": "visa", "status": "succeeded", "amount": 32114 }, "shipping_address": { "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "shipping_method": { "id": "ship_standard", "name": "Standard Shipping", "amount": 599, "estimated_delivery": "2024-06-25" }, "customer_note": "Please leave at front door", "created_at": "2024-06-20T17:00:00Z", "updated_at": "2024-06-20T17:00:00Z", "metadata": { "source": "web_checkout" } } ``` # Clear Cart Source: https://docs.stateset.com/api-reference/cart/clear POST https://api.stateset.com/v1/carts/:id/clear Remove all items from a cart This endpoint removes all items from a cart while preserving the cart itself, customer information, and applied settings. Useful for "Clear Cart" functionality. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart to clear ## Request Body Keep applied coupon codes Reason for clearing the cart (for analytics) ### Response Returns the cleared cart object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/clear' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "preserve_coupons": false, "reason": "customer_requested" }' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.clear( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { preserve_coupons: false, reason: "customer_requested" } ); ``` ```python Python theme={null} cart = stateset.carts.clear( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', preserve_coupons=False, reason="customer_requested" ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "session_id": "sess_xyz789", "channel": "web", "currency": "USD", "locale": "en-US", "status": "active", "items": [], "item_count": 0, "unique_item_count": 0, "subtotal": 0, "tax_amount": 0, "shipping_amount": 0, "discount_amount": 0, "total": 0, "shipping_address": { "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "applied_coupons": [], "applied_promotions": [], "expires_at": "2024-07-20T10:00:00Z", "created_at": "2024-06-20T10:00:00Z", "updated_at": "2024-06-20T17:30:00Z", "last_activity": "2024-06-20T17:30:00Z", "cleared_at": "2024-06-20T17:30:00Z", "metadata": { "clear_reason": "customer_requested", "items_cleared": 3 }, "messages": [ { "type": "info", "message": "Cart has been cleared" } ] } ``` # Create Cart Source: https://docs.stateset.com/api-reference/cart/create POST https://api.stateset.com/v1/carts Create a new shopping cart for a customer or guest session This endpoint creates a new shopping cart that persists across sessions. Carts can be associated with authenticated customers or anonymous sessions. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Customer ID to associate with the cart (for authenticated users) Session ID for guest carts (auto-generated if not provided) Sales channel: "web", "mobile", "pos", "api" ISO 4217 currency code Locale for the cart (e.g., "en-US") Initial items to add to the cart Product ID Product variant ID Quantity to add Override price in cents (for custom pricing) Custom fields for the item Shipping address for tax/shipping calculations Street address Apartment, suite, etc. City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Email for guest checkout and abandoned cart recovery Custom expiration date (ISO 8601, default: 30 days) Additional custom fields ### Response Returns the created cart object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/carts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "customer_id": "cust_abc123", "channel": "web", "currency": "USD", "locale": "en-US", "items": [ { "product_id": "prod_123", "variant_id": "var_blue_large", "quantity": 2 } ], "shipping_address": { "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } }' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.create({ customer_id: "cust_abc123", channel: "web", currency: "USD", locale: "en-US", items: [ { product_id: "prod_123", variant_id: "var_blue_large", quantity: 2 } ], shipping_address: { city: "San Francisco", state: "CA", postal_code: "94105", country: "US" } }); ``` ```python Python theme={null} cart = stateset.carts.create( customer_id="cust_abc123", channel="web", currency="USD", locale="en-US", items=[ { "product_id": "prod_123", "variant_id": "var_blue_large", "quantity": 2 } ], shipping_address={ "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "session_id": "sess_xyz789", "channel": "web", "currency": "USD", "locale": "en-US", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "sku": "WH-BL-L", "quantity": 2, "unit_price": 9999, "list_price": 9999, "subtotal": 19998, "discounts": [], "image_url": "https://images.stateset.com/products/wh-blue-large.jpg", "metadata": {} } ], "item_count": 2, "unique_item_count": 1, "subtotal": 19998, "tax_amount": 0, "shipping_amount": 0, "discount_amount": 0, "total": 19998, "shipping_address": { "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "available_shipping_methods": [], "applied_coupons": [], "applied_promotions": [], "expires_at": "2024-07-20T10:00:00Z", "created_at": "2024-06-20T10:00:00Z", "updated_at": "2024-06-20T10:00:00Z", "metadata": {} } ``` # Get Cart Source: https://docs.stateset.com/api-reference/cart/get GET https://api.stateset.com/v1/carts/:id Retrieve details of a specific shopping cart This endpoint retrieves the current state of a shopping cart, including all items, calculated totals, and applied discounts. ## Authentication This endpoint requires a valid API key with `carts:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart ## Query Parameters Expand related objects: "items.product", "customer", "shipping\_methods" Calculate available shipping methods (requires shipping address) Calculate tax amount (requires shipping address) ### Response Returns the cart object if found. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30?calculate_shipping=true&calculate_tax=true' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.retrieve( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { calculate_shipping: true, calculate_tax: true } ); ``` ```python Python theme={null} cart = stateset.carts.retrieve( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', calculate_shipping=True, calculate_tax=True ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "customer": { "id": "cust_abc123", "email": "john@example.com", "name": "John Doe" }, "session_id": "sess_xyz789", "channel": "web", "currency": "USD", "locale": "en-US", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "sku": "WH-BL-L", "quantity": 2, "unit_price": 9999, "list_price": 9999, "subtotal": 19998, "discounts": [ { "promotion_id": "promo_summer20", "code": "SUMMER20", "amount": 2000, "type": "percentage" } ], "final_price": 17998, "image_url": "https://images.stateset.com/products/wh-blue-large.jpg", "inventory_status": "in_stock", "available_quantity": 50, "metadata": {} }, { "id": "ci_def456", "product_id": "prod_456", "variant_id": null, "product_name": "USB-C Cable", "variant_name": null, "sku": "USBC-6FT", "quantity": 1, "unit_price": 1999, "list_price": 1999, "subtotal": 1999, "discounts": [], "final_price": 1999, "image_url": "https://images.stateset.com/products/usbc-cable.jpg", "inventory_status": "in_stock", "available_quantity": 200, "metadata": {} } ], "item_count": 3, "unique_item_count": 2, "subtotal": 21997, "discount_amount": 2000, "tax_amount": 1755, "tax_breakdown": [ { "name": "CA State Tax", "rate": 0.0725, "amount": 1450 }, { "name": "SF County Tax", "rate": 0.0175, "amount": 305 } ], "shipping_amount": 599, "total": 20351, "shipping_address": { "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "selected_shipping_method": { "id": "ship_standard", "name": "Standard Shipping", "amount": 599, "estimated_days": 5 }, "available_shipping_methods": [ { "id": "ship_standard", "name": "Standard Shipping", "amount": 599, "estimated_days": 5 }, { "id": "ship_express", "name": "Express Shipping", "amount": 1299, "estimated_days": 2 } ], "applied_coupons": [ { "code": "SUMMER20", "promotion_id": "promo_summer20", "discount_amount": 2000 } ], "applied_promotions": [ { "id": "promo_summer20", "name": "Summer Sale", "type": "percentage", "amount": 10 } ], "abandoned_at": null, "expires_at": "2024-07-20T10:00:00Z", "created_at": "2024-06-20T10:00:00Z", "updated_at": "2024-06-20T14:30:00Z", "last_activity": "2024-06-20T14:30:00Z", "metadata": { "source": "product_page", "utm_campaign": "summer_sale" } } ``` # List Carts Source: https://docs.stateset.com/api-reference/cart/list GET https://api.stateset.com/v1/carts List all carts with filtering and pagination options This endpoint returns a paginated list of carts. You can filter by customer, status, date range, and more. Useful for abandoned cart recovery and analytics. ## Authentication This endpoint requires a valid API key with `carts:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of carts to return (1-100) Number of carts to skip Filter by customer ID Filter by session ID Filter by status: "active", "abandoned", "converted", "expired" Filter by channel: "web", "mobile", "pos", "api" Filter carts created after date (ISO 8601) Filter carts created before date (ISO 8601) Filter carts updated after date (ISO 8601) Filter carts with email addresses (for recovery) Minimum cart value in cents Sort by field: "created\_at", "updated\_at", "total", "abandoned\_at" Sort order: "asc" or "desc" ### Response Returns a paginated list of cart objects. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/carts?status=abandoned&has_email=true&limit=20' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const carts = await stateset.carts.list({ status: 'abandoned', has_email: true, limit: 20 }); ``` ```python Python theme={null} carts = stateset.carts.list( status='abandoned', has_email=True, limit=20 ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "email": "john@example.com", "status": "abandoned", "channel": "web", "currency": "USD", "item_count": 3, "subtotal": 34495, "total": 37762, "abandoned_at": "2024-06-19T20:00:00Z", "last_activity": "2024-06-19T19:30:00Z", "created_at": "2024-06-19T18:00:00Z", "recovery_status": "not_attempted" }, { "id": "cart_1234f083-bb2d-54d6-bg6d-1b0e3gd75f41", "object": "cart", "customer_id": null, "email": "jane@example.com", "status": "abandoned", "channel": "mobile", "currency": "USD", "item_count": 1, "subtotal": 4999, "total": 5648, "abandoned_at": "2024-06-18T15:00:00Z", "last_activity": "2024-06-18T14:45:00Z", "created_at": "2024-06-18T14:00:00Z", "recovery_status": "email_sent" } ], "has_more": true, "total_count": 156, "url": "/v1/carts", "summary": { "total_abandoned_value": 2847532, "average_cart_value": 18252, "recovery_rate": 0.23, "status_breakdown": { "active": 45, "abandoned": 156, "converted": 1234, "expired": 89 } } } ``` # Merge Carts Source: https://docs.stateset.com/api-reference/cart/merge POST https://api.stateset.com/v1/carts/:id/merge Merge a guest cart with a customer cart after login This endpoint merges items from one cart (typically a guest cart) into another cart (typically the logged-in customer's cart). Useful when customers add items before logging in. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The target cart ID (cart to merge INTO) ## Request Body The source cart ID (cart to merge FROM) How to handle duplicate items: "combine" (add quantities), "keep\_source", "keep\_target" Whether to preserve metadata from source cart items Whether to delete the source cart after merge ### Response Returns the merged cart object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/carts/cart_customer_123/merge' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "source_cart_id": "cart_guest_456", "merge_strategy": "combine", "delete_source_cart": true }' ``` ```javascript Node.js theme={null} const mergedCart = await stateset.carts.merge( 'cart_customer_123', { source_cart_id: "cart_guest_456", merge_strategy: "combine", delete_source_cart: true } ); ``` ```python Python theme={null} merged_cart = stateset.carts.merge( 'cart_customer_123', source_cart_id="cart_guest_456", merge_strategy="combine", delete_source_cart=True ) ``` ```json Response theme={null} { "id": "cart_customer_123", "object": "cart", "customer_id": "cust_abc123", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "quantity": 5, "unit_price": 9999, "subtotal": 49995, "source": "merged", "metadata": { "original_cart": "cart_customer_123", "merged_quantity": 2, "merge_timestamp": "2024-06-20T18:00:00Z" } }, { "id": "ci_new789", "product_id": "prod_456", "product_name": "USB-C Cable", "quantity": 2, "unit_price": 1999, "subtotal": 3998, "source": "merged", "metadata": { "original_cart": "cart_guest_456", "merge_timestamp": "2024-06-20T18:00:00Z" } } ], "item_count": 7, "unique_item_count": 2, "subtotal": 53993, "total": 58792, "merge_details": { "source_cart_id": "cart_guest_456", "items_merged": 2, "items_combined": 1, "merge_timestamp": "2024-06-20T18:00:00Z", "source_cart_deleted": true }, "updated_at": "2024-06-20T18:00:00Z", "messages": [ { "type": "success", "message": "Successfully merged 2 items from guest cart" } ] } ``` # Remove Cart Item Source: https://docs.stateset.com/api-reference/cart/remove-item DELETE https://api.stateset.com/v1/carts/:id/items/:item_id Remove an item from the cart This endpoint removes a specific item from the cart completely. To update quantity instead, use the update item endpoint. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart The unique identifier of the cart item to remove ### Response Returns the updated cart object without the removed item. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/items/ci_def456' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.removeItem( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ci_def456' ); ``` ```python Python theme={null} cart = stateset.carts.remove_item( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ci_def456' ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "quantity": 3, "unit_price": 9999, "subtotal": 29997 }, { "id": "ci_ghi789", "product_id": "prod_789", "variant_id": "var_red_medium", "product_name": "T-Shirt", "variant_name": "Red - Medium", "quantity": 1, "unit_price": 2499, "subtotal": 2499 } ], "item_count": 4, "unique_item_count": 2, "subtotal": 32496, "discount_amount": 3000, "total": 29496, "updated_at": "2024-06-20T16:00:00Z", "last_activity": "2024-06-20T16:00:00Z", "messages": [ { "type": "info", "message": "Item removed from cart" } ] } ``` # Update Cart Item Source: https://docs.stateset.com/api-reference/cart/update-item PUT https://api.stateset.com/v1/carts/:id/items/:item_id Update quantity or properties of an item in the cart This endpoint updates an existing item in the cart. You can change quantity, add notes, or update metadata. Setting quantity to 0 removes the item. ## Authentication This endpoint requires a valid API key with `carts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the cart The unique identifier of the cart item ## Request Body New quantity (set to 0 to remove item) Update special instructions Update custom fields Validate inventory for quantity increase ### Response Returns the updated cart object. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/carts/cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/items/ci_abc123' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "quantity": 3, "notes": "Updated quantity" }' ``` ```javascript Node.js theme={null} const cart = await stateset.carts.updateItem( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ci_abc123', { quantity: 3, notes: "Updated quantity" } ); ``` ```python Python theme={null} cart = stateset.carts.update_item( 'cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ci_abc123', quantity=3, notes="Updated quantity" ) ``` ```json Response theme={null} { "id": "cart_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "cart", "customer_id": "cust_abc123", "status": "active", "items": [ { "id": "ci_abc123", "product_id": "prod_123", "variant_id": "var_blue_large", "product_name": "Wireless Headphones", "variant_name": "Blue - Large", "quantity": 3, "unit_price": 9999, "subtotal": 29997, "notes": "Updated quantity", "inventory_status": "in_stock", "available_quantity": 50 }, { "id": "ci_def456", "product_id": "prod_456", "product_name": "USB-C Cable", "quantity": 1, "unit_price": 1999, "subtotal": 1999 }, { "id": "ci_ghi789", "product_id": "prod_789", "variant_id": "var_red_medium", "product_name": "T-Shirt", "variant_name": "Red - Medium", "quantity": 1, "unit_price": 2499, "subtotal": 2499, "notes": "Gift wrap please" } ], "item_count": 5, "unique_item_count": 3, "subtotal": 34495, "updated_at": "2024-06-20T15:30:00Z", "last_activity": "2024-06-20T15:30:00Z", "messages": [ { "type": "info", "message": "Item quantity updated" } ] } ``` # Close Case Source: https://docs.stateset.com/api-reference/cases/close POST https://api.stateset.com/v1/cases/:id/close This endpoint updates an existing case. ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/cases/:id/close' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation caseCloseMutation { caseClose (id: "${caseId}") { case { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const cases = await stateset.cases.close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} cases = stateset.cases.close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} cases = Stateset::Return.close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} cases, err := stateset.cases.close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Return cases = stateset.cases.close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $cases = $stateset->cases->close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var cases = await stateset.cases.close({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "case", "closed": true } ``` # Create Case Source: https://docs.stateset.com/api-reference/cases/create POST https://api.stateset.com/v1/cases Create a new case record for tracking issues or requests This endpoint requires authentication with `cases:write` permission. ### Request Parameters The name or title of the case Detailed description of the case or issue Optional custom case number (auto-generated if not provided) Initial status of the case. Options: `new`, `in_progress`, `resolved`, `closed` Priority level. Options: `low`, `medium`, `high`, `urgent` ID or name of the person submitting the case ID or name of the assigned resolver (can be assigned later) ### Response Unique identifier for the newly created case The name or title of the case Detailed description of the case Assigned case number Current status of the case Priority level of the case Submitter of the case Assigned resolver (if any) Timestamp when the case was created Timestamp when the case was last updated ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/cases' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "caseName": "Network Connectivity Issue", "description": "Customer unable to connect to WiFi", "priority": "high", "submitter": "user_123" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.stateset.com/v1/cases', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY' }, body: JSON.stringify({ caseName: 'Network Connectivity Issue', description: 'Customer unable to connect to WiFi', priority: 'high', submitter: 'user_123' }) }); ``` ```python Python theme={null} import requests response = requests.post( 'https://api.stateset.com/v1/cases', headers={ 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY' }, json={ 'caseName': 'Network Connectivity Issue', 'description': 'Customer unable to connect to WiFi', 'priority': 'high', 'submitter': 'user_123' } ) ``` ```json Success Response theme={null} { "id": "case_001", "caseName": "Network Connectivity Issue", "description": "Customer unable to connect to WiFi", "caseNumber": "CASE-20240101-001", "caseStatus": "new", "priority": "high", "submitter": "user_123", "resolver": null, "createdDate": "2024-01-01T12:00:00Z", "updatedDate": "2024-01-01T12:00:00Z" } ``` ```json Error Response theme={null} { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Missing required field: caseName" } } ``` # Delete Case Source: https://docs.stateset.com/api-reference/cases/delete DELETE https://api.stateset.com/v1/cases:/id This endpoint deletes an existing case. ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/case' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteCase ($id: String!) { delete_cases(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const cases = await stateset.cases.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} cases = stateset.cases.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} cases, err := stateset.Cases.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case cases = stateset.cases.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const cases = await stateset.cases.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} cases = Stateset::Return.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $cases = $stateset->cases->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/case HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ca_1NXWPnCo6bFb1KQto6C8OWvE", "object": "case", "deleted": true } ``` # Escalate Case Source: https://docs.stateset.com/api-reference/cases/escalate POST https://api.stateset.com/v1/cases/:id/escalate This endpoint escalates an existing case. ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/cases/:id/escalate' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation caseEscalateMutation { caseEscalate (id: "${caseId}") { case { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const cases = await stateset.cases.escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} cases = stateset.cases.escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} cases = Stateset::Return.escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} cases, err := stateset.cases.escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Return cases = stateset.cases.escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $cases = $stateset->cases->escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var cases = await stateset.cases.escalate({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "case", "escalated": true } ``` # Get Cases Source: https://docs.stateset.com/api-reference/cases/get GET https://api.stateset.com/v1/cases/:id This endpoint gets a case. ### Body This is the id of the case ### Response This is the id of the case This is the name of the case This is the description of the case This is the number of the case This is the status of the case This is the priority of the case This is the submitter of the case This is the resolver of the case This is the date the case was created This is the date the case was updated ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/case' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query getMyCases { cases(order_by: {createdDate: desc}) { id caseName description caseNumber caseStatus priority submitter resolver createdDate } } ``` ```js Node.js theme={null} const cases= await stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} cases= stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} channel_threads, err := stateset.Messages.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} cases= Stateset::Messages.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Cases cases= Stateset.Cases.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Cases cases= Stateset.Cases.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $cases= Stateset\Cases::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/cases HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "case": { "id": "ca_1NXWPnCo6bFb1KQto6C8OWvE", "caseName": "Case Name", "description": "Case Description", "caseNumber": "Case Number", "caseStatus": "Case Status", "priority": "Priority", "submitter": "Submitter", "resolver": "Resolver", "createdDate": "2021-01-01T00:00:00.000Z" } } } ``` # List Cases Source: https://docs.stateset.com/api-reference/cases/list GET https://api.stateset.com/v1/cases/list This endpoint list cases. ### Body This is the limit of the cases. This is the offset of the cases. This is the order direction of the cases. ### Response This is the id of the case This is the name of the case This is the description of the case This is the number of the case This is the status of the case This is the priority of the case This is the submitter of the case This is the resolver of the case This is the date the case was created This is the date the case was updated ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/cases' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { cases(limit: $limit, offset: $offset, order_by: {createdDate: $order_direction}) { id caseName description caseNumber caseStatus priority submitter resolver createdDate } } ``` ```js Node.js theme={null} const cases= await stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} cases= stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} channel_threads, err := stateset.Messages.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} cases= Stateset::Messages.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Cases cases= Stateset.Cases.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Cases cases= Stateset.Cases.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $cases= Stateset\Cases::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/cases HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "case": { "id": "ca_1NXWPnCo6bFb1KQto6C8OWvE", "caseName": "Case Name", "description": "Case Description", "caseNumber": "Case Number", "caseStatus": "Case Status", "priority": "Priority", "submitter": "Submitter", "resolver": "Resolver", "createdDate": "2021-01-01T00:00:00.000Z" } } } ``` # Resolve Case Source: https://docs.stateset.com/api-reference/cases/resolve POST https://api.stateset.com/v1/cases/:id/resolve This endpoint resolves an existing case. ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/cases/:id/resolve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation caseResolveMutation { caseResolve (id: "${caseId}") { case { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const cases = await stateset.cases.resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} cases = stateset.cases.resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} cases = Stateset::Return.resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} cases, err := stateset.cases.resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Return cases = stateset.cases.resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $cases = $stateset->cases->resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var cases = await stateset.cases.resolve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "case", "resolved": true } ``` # Update Case Source: https://docs.stateset.com/api-reference/cases/update POST https://api.stateset.com/v1/cases This endpoint updates a cases ### Body This is the ID of the case to update. ### Response This is the id of the case This is the name of the case This is the description of the case This is the number of the case This is the status of the case This is the priority of the case This is the submitter of the case This is the resolver of the case This is the date the case was created This is the date the case was updated ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/case' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation ( $id: String $casex: cases_set_input! ) { update_cases ( where: { id : { _eq: $id }} _set: $casex ) { returning { id caseName caseNumber caseStatus description priority resolver submitter } } } ``` ```javascript Node.js theme={null} const created = await stateset.case.update({ id: "", }); ``` ```json Response theme={null} { "data": { "update_cases": { "returning": [ { "id": "0x0", "caseName": "Case Name", "caseNumber": "Case Number", "description": "Case Description", "caseStatus": "Case Status", "priority": "Case Priority", "submitter": "Submitter", "resolver": "Resolver" } ] } } } ``` # API Changelog Source: https://docs.stateset.com/api-reference/changelog Recent changes and updates to the StateSet API # API Changelog This page documents changes to the StateSet API, including new features, improvements, and breaking changes. We follow semantic versioning and announce changes in advance when possible. ## Version 1.0.0 (Current) ### 2024-01-15: Initial Release * Launched core endpoints for agents, conversations, knowledge bases, and workflows * Added support for REST and GraphQL interfaces * Implemented authentication and rate limiting * Released SDKs for Node.js, Python, Go, and Ruby ### 2024-02-01: Feature Update * Added webhook support for real-time events * Introduced cursor-based pagination for list endpoints * Enhanced filtering and sorting capabilities * Improved error responses with detailed codes and messages ## Previous Versions ### Version 0.9.0 (Beta) * Internal beta release with basic CRUD operations * Initial GraphQL schema implementation * Basic authentication support Subscribe to our [developer newsletter](https://stateset.com/newsletter) for advance notice of upcoming changes. # Create Channel Thread Source: https://docs.stateset.com/api-reference/channels/create POST https://api.stateset.com/v1/channel_thread This endpoint creates a new channel thread ### Body This is the ID of the channel thread to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation addChannelThread( $channel_thread: channel_thread_insert_input! ) { insert_channel_thread(objects: [$channel_thread]) { returning { id name uuid user_id } } } ``` ```javascript Node.js theme={null} const created = await stateset.channel.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_channel_thread": { "returning": [ { "id": "", "name": "", "uuid": "", "user_id": "" } ] } } } ``` # Delete Channel Thread Source: https://docs.stateset.com/api-reference/channels/delete DELETE https://api.stateset.com/v1/channel_thread This endpoint deletes an existing thread. ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteChannelThread ($id: String!) { delete_channel_thread(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const channelthead = await stateset.channelthread.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} channelthead = stateset.channelthead.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} channelthead, err := stateset.Cases.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case channelthead = stateset.channelthead.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const channelthead = await stateset.channelthead.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} channelthead = Stateset::Return.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $channelthead = $stateset->channelthead->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/channelthread HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "channel_thread", "deleted": true } ``` # Get Channel Threads Source: https://docs.stateset.com/api-reference/channels/get GET https://api.stateset.com/v1/channel_threads This endpoint gets a channel threads. ### Body This is the id of the channel thread. ### Response This is the id of the channel\_thread This is the name of the channel\_thread This is the uuid of the channel\_thread This is the user\_id of the channel\_thread ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/channelthread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MyChannelThread { channel_thread { id created_at name system_prompt user_id messages { id body channel_id chat_id created_at date deliveredReceipt from fromMe likes messageNumber points sentReceipt timestamp to } } } ``` ```js Node.js theme={null} const channel_threads = await stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} channel_threads = stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} channel_threads, err := stateset.Messages.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} channel_threads = Stateset::Messages.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} ChannelThread channel_threads = Stateset.ChannelThreads.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} ChannelThread channel_threads = Stateset.ChannelThreads.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $channel_threads = Stateset\ChannelThreads::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/channel_threads HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` # Update Channel Thread Source: https://docs.stateset.com/api-reference/channels/update PUT https://api.stateset.com/v1/channel_thread This endpoint creates a new channel thread ### Body This is the ID of the channel thread to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```javascript Node.js theme={null} const created = await stateset.channel.update({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_channel_thread": { "returning": [ { "id": "", "name": "", "uuid": "", "user_id": "" } ] } } } ``` # Cancel Checkout Source: https://docs.stateset.com/api-reference/checkouts/cancel POST https://api.stateset.com/v1/checkouts/:id/cancel Cancel an existing checkout session This endpoint cancels an active checkout session. Once canceled, the checkout cannot be completed or updated. This is useful when a customer abandons their cart or decides not to proceed with the purchase. ## Authentication This endpoint requires a valid API key with `checkouts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters Unique identifier for the checkout session ## Request Body Optional reason for canceling the checkout (e.g., "customer\_requested", "timeout", "inventory\_unavailable") Optional custom message about the cancellation ### Response Unique identifier for the Checkout Session Status will be `canceled` after successful cancellation Information about the buyer Line items from the canceled checkout Final totals before cancellation Array including cancellation message ISO 8601 timestamp of when the checkout was canceled ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/checkouts/checkout_abc123/cancel \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "customer_requested", "message": "Customer changed their mind" }' ``` ```javascript Node.js theme={null} const checkout = await stateset.checkouts.cancel('checkout_abc123', { reason: "customer_requested", message: "Customer changed their mind" }); ``` ```python Python theme={null} checkout = stateset.checkouts.cancel( 'checkout_abc123', reason="customer_requested", message="Customer changed their mind" ) ``` ```json Success Response theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "status": "canceled", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 3 }, "base_amount": 3000, "discount": 0, "total": 3000, "subtotal": 3000, "tax": 0 }, { "id": "item_456", "item": { "id": "item_456", "quantity": 1 }, "base_amount": 500, "discount": 0, "total": 500, "subtotal": 500, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 3500 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 3750 } ], "messages": [ { "type": "info", "content_type": "plain", "content": "Checkout cancelled: Customer changed their mind" } ], "links": [], "canceled_at": "2024-09-30T14:30:00Z" } ``` ```json Error Response - Already Completed theme={null} { "success": false, "error": { "type": "invalid_request", "code": "INVALID_STATUS", "message": "Cannot cancel a checkout that has already been completed", "param": "status" } } ``` ```json Error Response - Not Found theme={null} { "success": false, "error": { "type": "invalid_request", "code": "RESOURCE_NOT_FOUND", "message": "Checkout session not found", "param": "id" } } ``` # Complete Checkout Source: https://docs.stateset.com/api-reference/checkouts/complete POST https://api.stateset.com/v1/checkouts/:id/complete Complete the checkout process by processing payment and creating an order This endpoint finalizes the checkout session by processing the payment and converting it into an order. The checkout status will be updated to `completed` upon successful payment. ## Authentication This endpoint requires a valid API key with `checkouts:write` and `payments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters Unique identifier for the checkout session ## Request Body Payment method details for processing the transaction Secure reference to a payment credential (tokenized payment method) Payment provider: `stripe`, `paypal`, `square` Billing address for the payment method Billing name Street address line 1 Street address line 2 City name State or province code ISO 3166-1 alpha-2 country code Postal or ZIP code Additional buyer information if needed First name of the buyer Last name of the buyer Email address of the buyer Phone number of the buyer ### Response Unique identifier for the Checkout Session Status will be `completed` after successful payment ID of the created order Payment processing details and status Final line items with calculated amounts Final breakdown of all charges ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/checkouts/checkout_abc123/complete \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "payment_data": { "token": "spt_123", "provider": "stripe", "billing_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" } } }' ``` ```javascript Node.js theme={null} const checkout = await stateset.checkouts.complete('checkout_abc123', { payment_data: { token: "spt_123", provider: "stripe", billing_address: { name: "John Doe", line_one: "123 Main St", line_two: "Apt 4B", city: "San Francisco", state: "CA", country: "US", postal_code: "94105" } } }); ``` ```python Python theme={null} checkout = stateset.checkouts.complete( 'checkout_abc123', payment_data={ "token": "spt_123", "provider": "stripe", "billing_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" } } ) ``` ```json Success Response theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "status": "completed", "currency": "usd", "order_id": "order_xyz789", "payment": { "id": "pay_456", "status": "succeeded", "amount": 3750, "provider": "stripe" }, "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 3 }, "base_amount": 3000, "discount": 0, "total": 3000, "subtotal": 3000, "tax": 0 }, { "id": "item_456", "item": { "id": "item_456", "quantity": 1 }, "base_amount": 500, "discount": 0, "total": 500, "subtotal": 500, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 3500 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 3750 } ], "messages": [], "links": [] } ``` ```json Error Response - Payment Declined theme={null} { "success": false, "error": { "type": "processing_error", "code": "PAYMENT_DECLINED", "message": "Payment was declined by the payment processor", "details": { "decline_code": "insufficient_funds", "provider_message": "Card has insufficient funds" } } } ``` ```json Error Response - Invalid Status theme={null} { "success": false, "error": { "type": "invalid_request", "code": "INVALID_STATUS", "message": "Checkout must be in ready_for_payment status to complete", "param": "status" } } ``` # Create Checkout Session Source: https://docs.stateset.com/api-reference/checkouts/create POST https://api.stateset.com/v1/checkouts Create a new checkout session with buyer details, line items, and shipping information This endpoint creates a new Checkout Session for the Agentic Commerce Protocol, enabling AI agents to manage commerce transactions. The session tracks buyer information, cart items, and fulfillment options. ## Authentication This endpoint requires a valid API key with `checkouts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Array of items to purchase Unique identifier for the item Requested quantity of the item Information about the buyer First name of the buyer Last name of the buyer Email address of the buyer Phone number of the buyer (E.164 format recommended) Address where the order will ship Name of the person receiving the items Street address line 1 Street address line 2 (apartment, suite, etc.) City name State or province code ISO 3166-1 alpha-2 country code (e.g., "US", "CA") Postal or ZIP code ### Response Unique identifier for the Checkout Session Information about the buyer Payment provider configuration and supported payment methods Current status: `not_ready_for_payment`, `ready_for_payment`, `completed`, `canceled`, `in_progress` Three-letter ISO currency code in lowercase Array of line items in the checkout with calculated amounts Address where the order will ship Available shipping and fulfillment options ID of the currently selected fulfillment option Breakdown of charges including subtotal, tax, shipping, and total Array of messages or notifications related to the checkout Array of links related to policies and agreements ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/checkouts \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "id": "item_123", "quantity": 2 } ], "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "fulfillment_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" } }' ``` ```javascript Node.js theme={null} const checkout = await stateset.checkouts.create({ items: [ { id: "item_123", quantity: 2 } ], buyer: { first_name: "John", last_name: "Doe", email: "john.doe@example.com", phone_number: "+1234567890" }, fulfillment_address: { name: "John Doe", line_one: "123 Main St", line_two: "Apt 4B", city: "San Francisco", state: "CA", country: "US", postal_code: "94105" } }); ``` ```python Python theme={null} checkout = stateset.checkouts.create( items=[ { "id": "item_123", "quantity": 2 } ], buyer={ "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, fulfillment_address={ "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" } ) ``` ```json Success Response theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "payment_provider": { "provider": "stripe", "supported_payment_methods": ["card"] }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 2 }, "base_amount": 2000, "discount": 0, "total": 2000, "subtotal": 2000, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 2000 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 2250 } ], "messages": [], "links": [] } ``` ```json Error Response - Validation Error theme={null} { "success": false, "error": { "type": "invalid_request", "code": "VALIDATION_ERROR", "message": "Invalid request parameters", "details": { "items": "At least one item is required", "buyer.email": "Invalid email format" } } } ``` # Delete Checkout Source: https://docs.stateset.com/api-reference/checkouts/delete Delete an existing checkout. # Delete Checkout Use this endpoint to delete a checkout by ID. # Retrieve Checkout Session Source: https://docs.stateset.com/api-reference/checkouts/get GET https://api.stateset.com/v1/checkouts/:id Retrieve an existing checkout session by its unique identifier This endpoint retrieves the current state of a checkout session, including all items, totals, fulfillment options, and status information. ## Authentication This endpoint requires a valid API key with `checkouts:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters Unique identifier for the checkout session ### Response Unique identifier for the Checkout Session Information about the buyer Payment provider configuration and supported payment methods Current status: `not_ready_for_payment`, `ready_for_payment`, `completed`, `canceled`, `in_progress` Three-letter ISO currency code in lowercase Array of line items in the checkout with calculated amounts Address where the order will ship Available shipping and fulfillment options ID of the currently selected fulfillment option Breakdown of charges including subtotal, tax, shipping, and total Array of messages or notifications related to the checkout Array of links related to policies and agreements ```bash cURL theme={null} curl -X GET https://api.stateset.com/v1/checkouts/checkout_abc123 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript Node.js theme={null} const checkout = await stateset.checkouts.retrieve('checkout_abc123'); ``` ```python Python theme={null} checkout = stateset.checkouts.retrieve('checkout_abc123') ``` ```json Success Response theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "payment_provider": { "provider": "stripe", "supported_payment_methods": ["card"] }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 2 }, "base_amount": 2000, "discount": 0, "total": 2000, "subtotal": 2000, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "123 Main St", "line_two": "Apt 4B", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94105" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 2000 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 2250 } ], "messages": [], "links": [] } ``` ```json Error Response - Not Found theme={null} { "success": false, "error": { "type": "invalid_request", "code": "RESOURCE_NOT_FOUND", "message": "Checkout session not found", "param": "id" } } ``` # List Checkout Sessions Source: https://docs.stateset.com/api-reference/checkouts/list GET https://api.stateset.com/v1/checkouts Retrieve a list of checkout sessions with optional filters This endpoint returns a paginated list of checkout sessions. You can filter by status, buyer email, or date range. ## Authentication This endpoint requires a valid API key with `checkouts:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Filter by checkout status: `not_ready_for_payment`, `ready_for_payment`, `completed`, `canceled`, `in_progress` Filter by buyer's email address Filter checkouts created after this ISO 8601 timestamp Filter checkouts created before this ISO 8601 timestamp Number of results per page (default: 20, max: 100) Cursor for pagination - ID of the last item from the previous page ### Response Array of checkout session objects Whether there are more results available Total number of checkouts matching the filters ```bash cURL theme={null} curl -X GET 'https://api.stateset.com/v1/checkouts?status=ready_for_payment&limit=10' \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript Node.js theme={null} const checkouts = await stateset.checkouts.list({ status: 'ready_for_payment', limit: 10 }); ``` ```python Python theme={null} checkouts = stateset.checkouts.list( status='ready_for_payment', limit=10 ) ``` ```json Success Response theme={null} { "data": [ { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 2 }, "base_amount": 2000, "discount": 0, "total": 2000, "subtotal": 2000, "tax": 0 } ], "totals": [ { "type": "total", "display_text": "Total", "amount": 2250 } ], "created_at": "2024-09-30T10:00:00Z", "updated_at": "2024-09-30T10:05:00Z" }, { "id": "checkout_def456", "buyer": { "first_name": "Jane", "last_name": "Smith", "email": "jane.smith@example.com" }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_789", "item": { "id": "item_789", "quantity": 1 }, "base_amount": 5000, "discount": 500, "total": 4500, "subtotal": 4500, "tax": 0 } ], "totals": [ { "type": "total", "display_text": "Total", "amount": 4800 } ], "created_at": "2024-09-30T09:30:00Z", "updated_at": "2024-09-30T09:35:00Z" } ], "has_more": false, "total_count": 2 } ``` ```json Error Response - Invalid Parameter theme={null} { "success": false, "error": { "type": "invalid_request", "code": "INVALID_PARAMETER", "message": "Invalid status value provided", "param": "status" } } ``` # Update Checkout Session Source: https://docs.stateset.com/api-reference/checkouts/update PUT https://api.stateset.com/v1/checkouts/:id Update an existing checkout session by modifying items, shipping address, or fulfillment options This endpoint updates an existing Checkout Session. You can modify line items, buyer information, shipping address, or select different fulfillment options. The response will include recalculated totals. ## Authentication This endpoint requires a valid API key with `checkouts:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters Unique identifier for the checkout session ## Request Body Updated array of items to purchase Unique identifier for the item Updated quantity of the item Updated buyer information First name of the buyer Last name of the buyer Email address of the buyer Phone number of the buyer Updated fulfillment address Name of the person receiving the items Street address line 1 Street address line 2 City name State or province code ISO 3166-1 alpha-2 country code Postal or ZIP code Identifier for the selected fulfillment option ### Response Returns the updated checkout session with recalculated totals. ```bash cURL theme={null} curl -X PUT https://api.stateset.com/v1/checkouts/checkout_abc123 \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "id": "item_123", "quantity": 3 }, { "id": "item_456", "quantity": 1 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_option_id": "shipping_fast" }' ``` ```javascript Node.js theme={null} const checkout = await stateset.checkouts.update('checkout_abc123', { items: [ { id: "item_123", quantity: 3 }, { id: "item_456", quantity: 1 } ], fulfillment_address: { name: "John Doe", line_one: "456 Oak Ave", city: "Los Angeles", state: "CA", country: "US", postal_code: "90210" }, fulfillment_option_id: "shipping_fast" }); ``` ```python Python theme={null} checkout = stateset.checkouts.update( 'checkout_abc123', items=[ { "id": "item_123", "quantity": 3 }, { "id": "item_456", "quantity": 1 } ], fulfillment_address={ "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, fulfillment_option_id="shipping_fast" ) ``` ```json Success Response theme={null} { "id": "checkout_abc123", "buyer": { "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone_number": "+1234567890" }, "payment_provider": { "provider": "stripe", "supported_payment_methods": ["card"] }, "status": "ready_for_payment", "currency": "usd", "line_items": [ { "id": "item_123", "item": { "id": "item_123", "quantity": 3 }, "base_amount": 3000, "discount": 0, "total": 3000, "subtotal": 3000, "tax": 0 }, { "id": "item_456", "item": { "id": "item_456", "quantity": 1 }, "base_amount": 500, "discount": 0, "total": 500, "subtotal": 500, "tax": 0 } ], "fulfillment_address": { "name": "John Doe", "line_one": "456 Oak Ave", "city": "Los Angeles", "state": "CA", "country": "US", "postal_code": "90210" }, "fulfillment_options": [ { "type": "shipping", "id": "shipping_fast", "title": "Express Shipping", "subtitle": "2-3 business days", "carrier": "Shipping Co", "subtotal": 150, "tax": 0, "total": 150 } ], "fulfillment_option_id": "shipping_fast", "totals": [ { "type": "subtotal", "display_text": "Subtotal", "amount": 3500 }, { "type": "fulfillment", "display_text": "Shipping", "amount": 150 }, { "type": "tax", "display_text": "Tax", "amount": 100 }, { "type": "total", "display_text": "Total", "amount": 3750 } ], "messages": [], "links": [] } ``` ```json Error Response - Invalid Item theme={null} { "success": false, "error": { "type": "invalid_request", "code": "ITEM_UNAVAILABLE", "message": "One or more items are no longer available", "details": { "unavailable_items": ["item_456"] } } } ``` # Create COGS Entry Source: https://docs.stateset.com/api-reference/cogs/create POST https://api.stateset.com/v1/cogs_entries This endpoint creates a new COGS (Cost of Goods Sold) entry. ### Body The accounting period for the COGS entry The product associated with the COGS entry The quantity of the product sold The Cost of Goods Sold amount The average cost per unit The quantity of inventory remaining at the end of the period The value of the ending inventory The currency used for the financial calculations Identifier for the related exchange rate Identifier for the related sale transaction The selling price per unit The total gross sales amount The method used to calculate COGS The category of the product The channel through which the sale was made The segment of the customer who made the purchase The date of the sale Indicates whether this entry is for a return The reason for the return, if applicable The cost center associated with the COGS entry Identifier for the related supplier ### Response Unique identifier for the newly created COGS entry A success message confirming the creation of the COGS entry ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/cogs_entries' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "period": "2024-Q1", "product": "Widget A", "quantity_sold": 100, "cogs": 5000, "average_cost": 50, "ending_inventory_quantity": 500, "ending_inventory_value": 25000, "currency": "USD", "unit_selling_price": 75, "gross_sales": 7500, "cogs_method": "FIFO", "sale_date": "2024-03-15" }' ``` ```python theme={null} import requests import json url = "https://api.stateset.com/v1/cogs_entries" headers = { "Content-Type": "application/json", "Authorization": "Token " } data = { "period": "2024-Q1", "product": "Widget A", "quantity_sold": 100, "cogs": 5000, "average_cost": 50, "ending_inventory_quantity": 500, "ending_inventory_value": 25000, "currency": "USD", "unit_selling_price": 75, "gross_sales": 7500, "cogs_method": "FIFO", "sale_date": "2024-03-15" } response = requests.post(url, headers=headers, data=json.dumps(data)) print(response.json()) ``` ``` ``` # Get COGS Entry Source: https://docs.stateset.com/api-reference/cogs/get GET https://api.stateset.com/v1/cogs_entries/{id} This endpoint gets a COGS (Cost of Goods Sold) entry. ### Response Unique identifier for the COGS entry (primary key) ### Response Unique identifier for the COGS entry (primary key) The accounting period for the COGS entry The product associated with the COGS entry The quantity of the product sold The Cost of Goods Sold amount The average cost per unit The quantity of inventory remaining at the end of the period The value of the ending inventory The currency used for the financial calculations Identifier for the related exchange rate Identifier for the related sale transaction The selling price per unit The total gross sales amount The gross profit amount The gross margin percentage The COGS as a percentage of sales The method used to calculate COGS The category of the product The channel through which the sale was made The segment of the customer who made the purchase The date of the sale Indicates whether this entry is for a return The reason for the return, if applicable The cost center associated with the COGS entry Identifier for the related supplier ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/cogs_entries' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { cogs_entries(limit: $limit, offset: $offset, order_by: {id: $order_direction}) { id period product quantity_sold cogs average_cost ending_inventory_quantity ending_inventory_value currency exchange_rate_id sale_transaction_id unit_selling_price gross_sales gross_profit gross_margin_percentage cogs_percentage cogs_method product_category sales_channel customer_segment sale_date is_return return_reason cost_center supplier_id } } ``` # List COGS Entries Source: https://docs.stateset.com/api-reference/cogs/list GET https://api.stateset.com/v1/cogs_entries/list This endpoint lists COGS (Cost of Goods Sold) entries. ### Body This is the limit of the COGS entries to return. This is the offset of the COGS entries. This is the order direction of the COGS entries. ### Response Unique identifier for the COGS entry (primary key) The accounting period for the COGS entry The product associated with the COGS entry The quantity of the product sold The Cost of Goods Sold amount The average cost per unit The quantity of inventory remaining at the end of the period The value of the ending inventory The currency used for the financial calculations Identifier for the related exchange rate Identifier for the related sale transaction The selling price per unit The total gross sales amount The gross profit amount The gross margin percentage The COGS as a percentage of sales The method used to calculate COGS The category of the product The channel through which the sale was made The segment of the customer who made the purchase The date of the sale Indicates whether this entry is for a return The reason for the return, if applicable The cost center associated with the COGS entry Identifier for the related supplier ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/cogs_entries' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { cogs_entries(limit: $limit, offset: $offset, order_by: {id: $order_direction}) { id period product quantity_sold cogs average_cost ending_inventory_quantity ending_inventory_value currency exchange_rate_id sale_transaction_id unit_selling_price gross_sales gross_profit gross_margin_percentage cogs_percentage cogs_method product_category sales_channel customer_segment sale_date is_return return_reason cost_center supplier_id } } ``` # Update COGS Entry Source: https://docs.stateset.com/api-reference/cogs/update PUT https://api.stateset.com/v1/cogs_entries/{id} This endpoint updates an existing COGS (Cost of Goods Sold) entry. ### Path Parameters The unique identifier of the COGS entry to update ### Body The accounting period for the COGS entry The product associated with the COGS entry The quantity of the product sold The Cost of Goods Sold amount The average cost per unit The quantity of inventory remaining at the end of the period The value of the ending inventory The currency used for the financial calculations Identifier for the related exchange rate Identifier for the related sale transaction The selling price per unit The total gross sales amount The method used to calculate COGS The category of the product The channel through which the sale was made The segment of the customer who made the purchase The date of the sale Indicates whether this entry is for a return The reason for the return, if applicable The cost center associated with the COGS entry Identifier for the related supplier ### Response The unique identifier of the updated COGS entry A success message confirming the update of the COGS entry ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/cogs_entries/123' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "quantity_sold": 150, "cogs": 7500, "average_cost": 50, "ending_inventory_quantity": 450, "ending_inventory_value": 22500, "gross_sales": 11250 }' ``` # Create Contact Source: https://docs.stateset.com/api-reference/contacts/create POST https://api.stateset.com/v1/contacts This endpoint creates a new contacts ### Body This is the current user group token you have for the user group that you want to rotate. ### Response ### Response The ID of the contact. Name or details of the assistant associated with the contact. Phone number of the assistant. URL or path to the contact's avatar image. Date of birth of the contact. Name or details of the controller associated with the contact. Date and time when the contact was created. Name or details of the person who created the contact. Department or division associated with the contact. Description or additional details about the contact. Indicates whether the contact should not be called. Email address of the contact. Indicates whether the contact has opted out of email communication. Fax number of the contact. Indicates whether the contact has opted out of fax communication. First name of the contact. Handle or username associated with the contact. Indicates whether the contact is marked as invalid. Languages known or spoken by the contact. Last name of the contact. Last person who modified the contact. Source or origin of the lead/contact. City of the mailing address. Country of the mailing address. Geocoding accuracy of the mailing address. State or province of the mailing address. Street of the mailing address. Name or details of the owner of the contact. Phone number of the contact. URL or path to the contact's photo. Name or details of the processor associated with the contact. Title or position of the contact. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/contact' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Delete Contact Source: https://docs.stateset.com/api-reference/contacts/delete DELETE https://api.return.com/v1/contacts/:id This endpoint deletes an existing contact. ### Body The ID of the contact to delete. ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/contact/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "co_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```json Response theme={null} { "id": "co_1NXWPnCo6bFb1KQto6C8OWvE", "object": "contact", "deleted": true } ``` # Get Contact Source: https://docs.stateset.com/api-reference/contacts/get GET https://api.stateset.com/v1/contacts/:id This endpoint gets or creates a new contact. ### Body The ID of the user group to which the contact belongs. ### Response The ID of the contact. Name or details of the assistant associated with the contact. Phone number of the assistant. URL or path to the contact's avatar image. Date of birth of the contact. Name or details of the controller associated with the contact. Date and time when the contact was created. Name or details of the person who created the contact. Department or division associated with the contact. Description or additional details about the contact. Indicates whether the contact should not be called. Email address of the contact. Indicates whether the contact has opted out of email communication. Fax number of the contact. Indicates whether the contact has opted out of fax communication. First name of the contact. Handle or username associated with the contact. Indicates whether the contact is marked as invalid. Languages known or spoken by the contact. Last name of the contact. Last person who modified the contact. Source or origin of the lead/contact. City of the mailing address. Country of the mailing address. Geocoding accuracy of the mailing address. State or province of the mailing address. Street of the mailing address. Name or details of the owner of the contact. Phone number of the contact. URL or path to the contact's photo. Name or details of the processor associated with the contact. Title or position of the contact. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/contacts/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "example_1", }' ``` ```json Response theme={null} { "success": 1, "new_user_group": true, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` | Name | Type | Description | | ---------------------- | --------- | ------------------------------------------------------------------ | | id | Text | Unique identifier for the contact | | assistant | Text | Name or details of the assistant associated with the contact | | assistant\_phone | Text | Phone number of the assistant | | avatar | Text | URL or path to the contact's avatar image | | birthdate | Text | Date of birth of the contact | | controller | Text | Name or details of the controller associated with the contact | | created\_at | Date/Time | Date and time when the contact was created | | created\_by | Text | Name or details of the person who created the contact | | department | Text | Department or division associated with the contact | | description | Text | Description or additional details about the contact | | do\_not\_call | Boolean | Indicates whether the contact should not be called | | email | Text | Email address of the contact | | email\_opt\_out | Boolean | Indicates whether the contact has opted out of email communication | | fax | Text | Fax number of the contact | | fax\_opt\_out | Boolean | Indicates whether the contact has opted out of fax communication | | firstName | Text | First name of the contact | | handle | Text | Handle or username associated with the contact | | invalid\_contact | Boolean | Indicates whether the contact is marked as invalid | | languages | Text | Languages known or spoken by the contact | | lastName | Text | Last name of the contact | | last\_modified\_by | Text | Last person who modified the contact | | leadSource | Text | Source or origin of the lead/contact | | mailingCity | Text | City of the mailing address | | mailingCountry | Text | Country of the mailing address | | mailingGeocodeAccuracy | Text | Geocoding accuracy of the mailing address | | mailingState | Text | State or province of the mailing address | | mailingStreet | Text | Street address of the mailing address | | nextMeeting | Text | Details or date/time of the next scheduled meeting | | owner | Text | Owner or responsible person for the contact | | phone | Text | Phone number of the contact | | photoUrl | Text | URL or path to the contact's photo/image | | processor | Text | Name or details of the processor associated with the contact | | supplier\_id | Text | Supplier ID associated with the contact | | title | Text | Title or job position of the contact | # List Contact Source: https://docs.stateset.com/api-reference/contacts/list GET https://api.stateset.com/v1/contacts/list This endpoint list contacts. ### Body This is the limit of the contacts. This is the offset of the contacts. This is the order direction of the contacts. ### Response The ID of the contact. Name or details of the assistant associated with the contact. Phone number of the assistant. URL or path to the contact's avatar image. Date of birth of the contact. Name or details of the controller associated with the contact. Date and time when the contact was created. Name or details of the person who created the contact. Department or division associated with the contact. Description or additional details about the contact. Indicates whether the contact should not be called. Email address of the contact. Indicates whether the contact has opted out of email communication. Fax number of the contact. Indicates whether the contact has opted out of fax communication. First name of the contact. Handle or username associated with the contact. Indicates whether the contact is marked as invalid. Languages known or spoken by the contact. Last name of the contact. Last person who modified the contact. Source or origin of the lead/contact. City of the mailing address. Country of the mailing address. Geocoding accuracy of the mailing address. State or province of the mailing address. Street of the mailing address. Name or details of the owner of the contact. Phone number of the contact. URL or path to the contact's photo. Name or details of the processor associated with the contact. Title or position of the contact. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/contacts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "ASC" }' ``` ```json Response theme={null} { "contacts": [ { "id": "1", "assistant": "Assistant", "assistant_phone": "1234567890", "avatar": "https://www.stateset.com/avatar.png", "birthdate": "2020-01-01", "controller": "Controller", "created_at": "2020-01-01T00:00:00.000000Z", "created_by": "Created By", "department": "Department", "description": "Description", "do_not_call": false, } ``` # Update Contact Source: https://docs.stateset.com/api-reference/contacts/update PUT https://api.stateset.com/v1/contacts This endpoint updates an existing contact. ### Body This is the name of the user group. ### Response ### Response The ID of the contact. Name or details of the assistant associated with the contact. Phone number of the assistant. URL or path to the contact's avatar image. Date of birth of the contact. Name or details of the controller associated with the contact. Date and time when the contact was created. Name or details of the person who created the contact. Department or division associated with the contact. Description or additional details about the contact. Indicates whether the contact should not be called. Email address of the contact. Indicates whether the contact has opted out of email communication. Fax number of the contact. Indicates whether the contact has opted out of fax communication. First name of the contact. Handle or username associated with the contact. Indicates whether the contact is marked as invalid. Languages known or spoken by the contact. Last name of the contact. Last person who modified the contact. Source or origin of the lead/contact. City of the mailing address. Country of the mailing address. Geocoding accuracy of the mailing address. State or province of the mailing address. Street of the mailing address. Name or details of the owner of the contact. Phone number of the contact. URL or path to the contact's photo. Name or details of the processor associated with the contact. Title or position of the contact. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/contacts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "" }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # Create Customer Source: https://docs.stateset.com/api-reference/customer/create POST https://api.stateset.com/v1/customers Create a new customer record with comprehensive validation and optional integrations This endpoint creates a new customer and can optionally create associated accounts in integrated systems like Stripe. ## Request Body Customer's email address. Must be unique and valid format. **Example:** `customer@example.com` Customer's first name. Must be 1-50 characters. **Example:** `John` Customer's last name. Must be 1-50 characters. **Example:** `Doe` Customer's phone number in E.164 format (recommended) or local format. **Examples:** `+1-555-123-4567`, `(555) 123-4567` Customer's date of birth in ISO 8601 format (YYYY-MM-DD). **Example:** `1990-05-15` Customer's primary address information. Primary street address Secondary address line (apartment, suite, etc.) City name State or province code (e.g., "CA", "NY", "ON") ZIP or postal code ISO 3166-1 alpha-2 country code (e.g., "US", "CA", "GB") Whether the customer has consented to marketing communications. Customer tier for loyalty programs. Options: `bronze`, `silver`, `gold`, `platinum` How the customer found your business. **Options:** `organic`, `paid_search`, `social_media`, `referral`, `email`, `direct`, `other` Existing Stripe customer ID if you're syncing with an external Stripe account. **Note:** If not provided and Stripe integration is enabled, a new Stripe customer will be created automatically. Internal notes about the customer (not visible to customer). **Max length:** 1000 characters Array of tags for customer segmentation and organization. **Example:** `["vip", "wholesale", "early-adopter"]` Additional custom fields as key-value pairs. Keys must be alphanumeric with underscores. **Example:** ```json theme={null} { "company_name": "Acme Corp", "industry": "Technology", "employee_count": "50-100" } ``` Customer communication preferences. Allow email notifications Allow SMS notifications Preferred language (ISO 639-1 code) Customer's timezone (IANA timezone identifier) ## Response Unique identifier for the created customer **Example:** `cust_1NXWPnCo6bFb1KQto6C8OWvE` Customer's email address Customer's first name Customer's last name Customer's full name (computed field) Customer's phone number Customer's date of birth Customer's address information Customer's loyalty tier Marketing consent status Associated Stripe customer ID (if Stripe integration is enabled) ISO 8601 timestamp when the customer was created ISO 8601 timestamp when the customer was last updated Customer status: `active`, `inactive`, `suspended` Customer's lifetime value (computed from order history) Total number of orders placed by this customer Array of customer tags Custom field key-value pairs Customer communication preferences ```bash Basic Customer theme={null} curl -X POST https://api.stateset.com/v1/customers \ -H "Authorization: Bearer ${STATESET_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe", "phone": "+1-555-123-4567" }' ``` ```bash Complete Customer Profile theme={null} curl -X POST https://api.stateset.com/v1/customers \ -H "Authorization: Bearer ${STATESET_API_KEY}" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: customer-creation-12345" \ -d '{ "email": "sarah.wilson@techcorp.com", "first_name": "Sarah", "last_name": "Wilson", "phone": "+1-555-987-6543", "date_of_birth": "1985-12-03", "address": { "street1": "123 Innovation Drive", "street2": "Suite 200", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "marketing_consent": true, "customer_tier": "gold", "referral_source": "paid_search", "notes": "High-value enterprise customer", "tags": ["enterprise", "tech", "high-value"], "custom_fields": { "company_name": "Tech Corp", "job_title": "CTO", "industry": "Technology" }, "preferences": { "email_notifications": true, "sms_notifications": false, "language": "en", "timezone": "America/Los_Angeles" } }' ``` ```javascript Node.js SDK theme={null} import { StateSetClient } from 'stateset-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); try { const customer = await client.customers.create({ email: 'john.doe@example.com', first_name: 'John', last_name: 'Doe', phone: '+1-555-123-4567', address: { street1: '123 Main Street', city: 'New York', state: 'NY', postal_code: '10001', country: 'US' }, marketing_consent: true, customer_tier: 'silver', tags: ['newsletter-subscriber'] }); console.log('Customer created:', customer.id); // Optionally, create a welcome email workflow await client.workflows.trigger({ workflow_id: 'welcome_series', customer_id: customer.id }); } catch (error) { if (error.code === 'DUPLICATE_EMAIL') { console.log('Customer already exists with this email'); } else { console.error('Error creating customer:', error.message); } } ``` ```python Python SDK theme={null} from stateset import StateSet import os client = StateSet(api_key=os.getenv('STATESET_API_KEY')) try: customer = client.customers.create({ 'email': 'jane.smith@example.com', 'first_name': 'Jane', 'last_name': 'Smith', 'phone': '+1-555-234-5678', 'address': { 'street1': '456 Oak Avenue', 'city': 'Los Angeles', 'state': 'CA', 'postal_code': '90210', 'country': 'US' }, 'marketing_consent': False, 'customer_tier': 'bronze', 'referral_source': 'social_media', 'custom_fields': { 'how_did_you_hear': 'Instagram ad', 'interests': 'sustainability' } }) print(f'Customer created: {customer.id}') # Send welcome email client.emails.send({ 'template': 'welcome', 'to': customer.email, 'variables': { 'first_name': customer.first_name } }) except Exception as error: if hasattr(error, 'code') and error.code == 'DUPLICATE_EMAIL': print('Customer already exists') else: print(f'Error: {str(error)}') ``` ```ruby Ruby SDK theme={null} require 'stateset' client = StateSet::Client.new( api_key: ENV['STATESET_API_KEY'] ) begin customer = client.customers.create({ email: 'mike.johnson@example.com', first_name: 'Mike', last_name: 'Johnson', phone: '+1-555-345-6789', address: { street1: '789 Pine Street', city: 'Seattle', state: 'WA', postal_code: '98101', country: 'US' }, customer_tier: 'platinum', tags: ['vip', 'longtime-customer'] }) puts "Customer created: #{customer.id}" rescue StateSet::DuplicateEmailError puts "Customer already exists with this email" rescue StateSet::Error => e puts "Error creating customer: #{e.message}" end ``` ```go Go SDK theme={null} package main import ( "context" "fmt" "log" "os" "github.com/stateset/stateset-go" "github.com/stateset/stateset-go/option" ) func main() { client := stateset.NewClient( option.WithAPIKey(os.Getenv("STATESET_API_KEY")), ) customer, err := client.Customers.Create(context.Background(), &stateset.CustomerCreateParams{ Email: "alex.brown@example.com", FirstName: "Alex", LastName: "Brown", Phone: "+1-555-456-7890", Address: &stateset.AddressParams{ Street1: "321 Elm Street", City: "Austin", State: "TX", PostalCode: "73301", Country: "US", }, MarketingConsent: stateset.Bool(true), CustomerTier: stateset.String("gold"), Tags: []string{"referral", "premium"}, }) if err != nil { var apiErr *stateset.Error if errors.As(err, &apiErr) && apiErr.Code == "DUPLICATE_EMAIL" { fmt.Println("Customer already exists") return } log.Fatal(err) } fmt.Printf("Customer created: %s\n", customer.ID) } ``` ```php PHP SDK theme={null} $_ENV['STATESET_API_KEY'] ]); try { $customer = $client->customers->create([ 'email' => 'lisa.davis@example.com', 'first_name' => 'Lisa', 'last_name' => 'Davis', 'phone' => '+1-555-567-8901', 'address' => [ 'street1' => '654 Maple Drive', 'city' => 'Denver', 'state' => 'CO', 'postal_code' => '80202', 'country' => 'US' ], 'customer_tier' => 'silver', 'marketing_consent' => true, 'referral_source' => 'email' ]); echo "Customer created: " . $customer->id . "\n"; // Send welcome SMS if phone provided if ($customer->phone) { $client->sms->send([ 'to' => $customer->phone, 'message' => "Welcome to our store, {$customer->first_name}!" ]); } } catch (StateSetException $e) { if ($e->getCode() === 'DUPLICATE_EMAIL') { echo "Customer already exists\n"; } else { echo "Error: " . $e->getMessage() . "\n"; } } ?> ``` ```java Java SDK theme={null} import com.stateset.StateSetClient; import com.stateset.models.Customer; import com.stateset.models.CustomerCreateParams; import com.stateset.models.Address; import com.stateset.exception.StateSetException; public class CreateCustomerExample { public static void main(String[] args) { StateSetClient client = StateSetClient.builder() .apiKey(System.getenv("STATESET_API_KEY")) .build(); try { CustomerCreateParams params = CustomerCreateParams.builder() .email("tom.wilson@example.com") .firstName("Tom") .lastName("Wilson") .phone("+1-555-678-9012") .address(Address.builder() .street1("987 Oak Boulevard") .city("Miami") .state("FL") .postalCode("33101") .country("US") .build()) .customerTier("gold") .marketingConsent(true) .addTag("newsletter") .addTag("loyalty-program") .build(); Customer customer = client.customers().create(params); System.out.println("Customer created: " + customer.getId()); } catch (StateSetException e) { if ("DUPLICATE_EMAIL".equals(e.getCode())) { System.out.println("Customer already exists"); } else { System.err.println("Error: " + e.getMessage()); } } } } ``` ```graphql GraphQL Mutation theme={null} mutation CreateCustomer($input: CustomerCreateInput!) { createCustomer(input: $input) { id email firstName lastName fullName phone address { street1 street2 city state postalCode country } customerTier marketingConsent status createdAt stripeCustomerId tags customFields preferences { emailNotifications smsNotifications language timezone } } } # Variables: { "input": { "email": "emily.chen@example.com", "firstName": "Emily", "lastName": "Chen", "phone": "+1-555-789-0123", "address": { "street1": "159 Innovation Way", "city": "Boston", "state": "MA", "postalCode": "02101", "country": "US" }, "customerTier": "platinum", "marketingConsent": true, "tags": ["enterprise", "tech-executive"], "customFields": { "company": "Innovation Labs", "role": "VP Engineering" } } } ``` ```json Success Response (201 Created) theme={null} { "id": "cust_1NXWPnCo6bFb1KQto6C8OWvE", "email": "sarah.wilson@techcorp.com", "first_name": "Sarah", "last_name": "Wilson", "full_name": "Sarah Wilson", "phone": "+1-555-987-6543", "date_of_birth": "1985-12-03", "address": { "street1": "123 Innovation Drive", "street2": "Suite 200", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "customer_tier": "gold", "marketing_consent": true, "referral_source": "paid_search", "stripe_customer_id": "cus_ABC123DEF456", "status": "active", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "lifetime_value": 0.00, "total_orders": 0, "tags": ["enterprise", "tech", "high-value"], "custom_fields": { "company_name": "Tech Corp", "job_title": "CTO", "industry": "Technology" }, "preferences": { "email_notifications": true, "sms_notifications": false, "language": "en", "timezone": "America/Los_Angeles" } } ``` ```json Error Response (400 Bad Request) theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "errors": [ { "field": "email", "message": "Invalid email format", "value": "invalid-email" }, { "field": "first_name", "message": "First name is required", "value": null } ], "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE" } } ``` ```json Error Response (409 Conflict) theme={null} { "error": { "code": "DUPLICATE_EMAIL", "message": "A customer with this email already exists", "details": { "email": "sarah.wilson@techcorp.com", "existing_customer_id": "cust_2OYZRpEq8dHd3MSvq8E0QYwG" }, "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE" } } ``` ```json Error Response (422 Unprocessable Entity) theme={null} { "error": { "code": "BUSINESS_RULE_VIOLATION", "message": "Customer creation violates business rules", "errors": [ { "rule": "age_restriction", "message": "Customer must be at least 13 years old", "field": "date_of_birth" } ], "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE" } } ``` ## Additional Features ### Idempotency Use the `Idempotency-Key` header to safely retry customer creation requests: ```bash theme={null} curl -X POST https://api.stateset.com/v1/customers \ -H "Idempotency-Key: customer-signup-form-abc123" \ -H "Authorization: Bearer sk_live_..." \ -d '{"email": "customer@example.com", ...}' ``` ### Stripe Integration When Stripe integration is enabled: * A Stripe customer is automatically created if `stripe_customer_id` is not provided * Customer data is synced between StateSet and Stripe * Payment methods can be attached to the Stripe customer ### Webhook Events Creating a customer triggers these webhook events: * `customer.created` - Fired when customer is successfully created * `customer.stripe_synced` - Fired when Stripe customer is created (if integration enabled) ### Validation Rules | Field | Validation | | --------------- | -------------------------------------------------- | | `email` | Must be valid email format, unique across account | | `first_name` | 1-50 characters, letters and spaces only | | `last_name` | 1-50 characters, letters and spaces only | | `phone` | Valid phone number format | | `date_of_birth` | Valid date, customer must be at least 13 years old | | `postal_code` | Valid format for specified country | | `country` | Valid ISO 3166-1 alpha-2 country code | ### Rate Limiting Customer creation is subject to rate limits: * **Standard:** 100 customers/minute * **Enterprise:** 1000 customers/minute Consider using batch import for large datasets. # Delete Customer Source: https://docs.stateset.com/api-reference/customer/delete DELETE https://api.return.com/v1/customers/:id This endpoint deletes an existing customer. ### Body The ID of the customer to delete. ### Response The ID provided in the data tab may be used to identify the manufacture order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/customers/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```graphQL GraphQL theme={null} mutation { deleteCustomer( input: { id: "example_1" } ) { id object deleted } } ``` ```js Node.js theme={null} var deleted = await stateset.customers.del({ id: "example_1" }); ``` ```python Python theme={null} deleted = stateset.customers.del({ "id": "example_1" }) ``` ```ruby Ruby theme={null} deleted = stateset.customers.del({ "id": "example_1" }) ``` ```go Go theme={null} deleted, err := stateset.Customers.Delete( "example_1" ) ``` ```java Java theme={null} Customer deleted = stateset.customers.delete( "example_1" ); ``` ```php PHP theme={null} $deleted = $stateset->customers->delete([ "id" => "example_1" ]); ``` ```json Response theme={null} { "id": "cu_1NXWPnCo6bFb1KQto6C8OWvE", "object": "customer", "deleted": true } ``` # Get Customer Source: https://docs.stateset.com/api-reference/customer/get GET https://api.stateset.com/v1/customers/:id Retrieve a single customer by their unique identifier Returns the full customer object including profile, address, and integration details. ## Path Parameters The unique identifier (SSO ID) of the customer to retrieve. **Example:** `1234-5678-9012-3456` ### Response Unique identifier for the customer. Customer's email address. Customer's first name. Customer's last name. Customer's phone number. Associated Stripe customer ID for payment processing. ISO 8601 date when the customer account was activated. ISO 8601 timestamp of the last update to the customer record. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/customers/1234-5678-9012-3456' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' ``` ```graphql GraphQL theme={null} query getCustomer($sso_id: uuid!) { customers: customers_by_pk(sso_id: $sso_id) { sso_id activationDate email firstName lastName phone stripe_customer_id timestamp } } ``` ```javascript Node.js theme={null} const customer = await stateset.customers.retrieve( '1234-5678-9012-3456' ); ``` ```python Python theme={null} customer = stateset.customers.retrieve( '1234-5678-9012-3456' ) ``` ```ruby Ruby theme={null} customer = Stateset::Customers.retrieve( '1234-5678-9012-3456' ) ``` ```go Go theme={null} customer, err := stateset.Customers.Retrieve( "1234-5678-9012-3456", ) ``` ```php PHP theme={null} $customer = $stateset->customers->retrieve( '1234-5678-9012-3456' ); ``` ```java Java theme={null} Customer customer = stateset.customers().retrieve( "1234-5678-9012-3456" ); ``` ```json Response theme={null} { "customer": { "sso_id": "1234-5678-9012-3456", "email": "jane.doe@example.com", "firstName": "Jane", "lastName": "Doe", "phone": "+1-555-123-4567", "stripe_customer_id": "cus_1234567890", "activationDate": "2024-01-15T00:00:00.000Z", "timestamp": "2024-06-01T12:30:00.000Z" } } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Customer not found", "details": { "resource": "customer", "id": "1234-5678-9012-3456" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` # List Customers Source: https://docs.stateset.com/api-reference/customer/list GET https://api.stateset.com/v1/customers Retrieve a paginated list of customers with optional filtering and sorting Returns a paginated array of customer objects. Use query parameters to filter, sort, and paginate results. ## Query Parameters Maximum number of customers to return per page. Range: 1-100. **Example:** `50` Number of records to skip for pagination. **Example:** `20` Sort direction for results. Options: `asc`, `desc`. Filter customers by email address (exact match). **Example:** `jane.doe@example.com` Filter customers created after this ISO 8601 date. **Example:** `2024-01-01T00:00:00.000Z` ### Response Array of customer objects. Unique identifier for the customer. Customer's email address. Customer's first name. Customer's last name. Customer's phone number. Associated Stripe customer ID. ISO 8601 date when the customer account was activated. ISO 8601 timestamp of the last update. Total number of customers matching the query. Whether there are more results beyond the current page. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/customers?limit=20&offset=0&order_direction=desc' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' ``` ```graphql GraphQL theme={null} query listCustomers($limit: Int!, $offset: Int!) { customers(limit: $limit, offset: $offset, order_by: { timestamp: desc }) { sso_id activationDate email firstName lastName phone stripe_customer_id timestamp } customers_aggregate { aggregate { count } } } ``` ```javascript Node.js theme={null} const customers = await stateset.customers.list({ limit: 20, offset: 0, order_direction: 'desc', }); ``` ```python Python theme={null} customers = stateset.customers.list( limit=20, offset=0, order_direction='desc', ) ``` ```ruby Ruby theme={null} customers = Stateset::Customers.list( limit: 20, offset: 0, order_direction: 'desc', ) ``` ```go Go theme={null} customers, err := stateset.Customers.List(&CustomerListParams{ Limit: 20, Offset: 0, OrderDirection: "desc", }) ``` ```php PHP theme={null} $customers = $stateset->customers->list([ 'limit' => 20, 'offset' => 0, 'order_direction' => 'desc', ]); ``` ```java Java theme={null} CustomerCollection customers = stateset.customers().list( CustomerListParams.builder() .setLimit(20) .setOffset(0) .setOrderDirection("desc") .build() ); ``` ```json Response theme={null} { "customers": [ { "sso_id": "1234-5678-9012-3456", "email": "jane.doe@example.com", "firstName": "Jane", "lastName": "Doe", "phone": "+1-555-123-4567", "stripe_customer_id": "cus_1234567890", "activationDate": "2024-01-15T00:00:00.000Z", "timestamp": "2024-06-01T12:30:00.000Z" }, { "sso_id": "9876-5432-1098-7654", "email": "john.smith@example.com", "firstName": "John", "lastName": "Smith", "phone": "+1-555-987-6543", "stripe_customer_id": "cus_0987654321", "activationDate": "2024-02-20T00:00:00.000Z", "timestamp": "2024-05-28T09:15:00.000Z" } ], "total_count": 142, "has_more": true } ``` ```json Error Response (400 Bad Request) theme={null} { "error": { "code": "INVALID_PARAMETER", "message": "limit must be between 1 and 100", "details": { "parameter": "limit", "value": 500 }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` # Merge Customers Source: https://docs.stateset.com/api-reference/customer/merge POST https://api.stateset.com/v1/customers/merge This endpoint merges duplicate customer records into a single primary record. ### Body The customer ID that will be kept as the primary record Array of customer IDs to be merged into the primary record Strategy for handling conflicting data during merge How to merge contact info: "primary\_only", "merge\_all", "most\_recent" How to handle orders: "transfer\_all", "keep\_separate" How to merge addresses: "primary\_only", "merge\_unique", "keep\_all" How to merge preferences: "primary\_only", "merge\_all", "most\_recent" The reason for merging these customer records ### Response The ID of the primary customer record after merge Array of customer IDs that were merged Summary of what was merged Number of orders transferred Number of addresses merged Number of contacts merged Combined lifetime value of all merged customers List of conflicts that were resolved during merge Timestamp when the merge was completed User who performed the merge Indicates whether the merge was successful ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/customers/merge' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "primary_customer_id": "cust_primary_123", "duplicate_customer_ids": ["cust_dup_456", "cust_dup_789"], "merge_strategy": { "contacts": "merge_all", "orders": "transfer_all", "addresses": "merge_unique", "preferences": "most_recent" }, "reason": "Duplicate accounts identified during data cleanup" }' ``` ```graphQL GraphQL theme={null} mutation customerMergeMutation { customerMerge( primaryCustomerId: "${primaryCustomerId}", duplicateCustomerIds: ${duplicateCustomerIds}, mergeStrategy: ${mergeStrategy}, reason: "${reason}" ) { customer { id email merge_summary { orders_transferred addresses_merged total_lifetime_value } } userErrors { field message } } } ``` ```js Node.js theme={null} const mergedCustomer = await stateset.customers.merge({ primary_customer_id: 'cust_primary_123', duplicate_customer_ids: ['cust_dup_456', 'cust_dup_789'], merge_strategy: { contacts: 'merge_all', orders: 'transfer_all', addresses: 'merge_unique', preferences: 'most_recent' }, reason: 'Duplicate accounts identified during data cleanup' }); ``` ```python Python theme={null} merged_customer = stateset.customers.merge({ 'primary_customer_id': 'cust_primary_123', 'duplicate_customer_ids': ['cust_dup_456', 'cust_dup_789'], 'merge_strategy': { 'contacts': 'merge_all', 'orders': 'transfer_all', 'addresses': 'merge_unique', 'preferences': 'most_recent' }, 'reason': 'Duplicate accounts identified during data cleanup' }) ``` ```ruby Ruby theme={null} merged_customer = Stateset::Customer.merge({ primary_customer_id: 'cust_primary_123', duplicate_customer_ids: ['cust_dup_456', 'cust_dup_789'], merge_strategy: { contacts: 'merge_all', orders: 'transfer_all', addresses: 'merge_unique', preferences: 'most_recent' }, reason: 'Duplicate accounts identified during data cleanup' }) ``` ```go Go theme={null} mergedCustomer, err := stateset.Customers.merge({ PrimaryCustomerID: 'cust_primary_123', DuplicateCustomerIDs: []string{'cust_dup_456', 'cust_dup_789'}, MergeStrategy: MergeStrategy{ Contacts: 'merge_all', Orders: 'transfer_all', Addresses: 'merge_unique', Preferences: 'most_recent' }, Reason: 'Duplicate accounts identified during data cleanup' }) ``` ```java Java theme={null} Customer mergedCustomer = stateset.customers.merge({ primaryCustomerId: 'cust_primary_123', duplicateCustomerIds: ['cust_dup_456', 'cust_dup_789'], mergeStrategy: { contacts: 'merge_all', orders: 'transfer_all', addresses: 'merge_unique', preferences: 'most_recent' }, reason: 'Duplicate accounts identified during data cleanup' }); ``` ```php PHP theme={null} $merged_customer = $stateset->customers->merge([ 'primary_customer_id' => 'cust_primary_123', 'duplicate_customer_ids' => ['cust_dup_456', 'cust_dup_789'], 'merge_strategy' => [ 'contacts' => 'merge_all', 'orders' => 'transfer_all', 'addresses' => 'merge_unique', 'preferences' => 'most_recent' ], 'reason' => 'Duplicate accounts identified during data cleanup' ]); ``` ```csharp C# theme={null} var mergedCustomer = await stateset.Customers.Merge(new { PrimaryCustomerId = 'cust_primary_123', DuplicateCustomerIds = new[] { 'cust_dup_456', 'cust_dup_789' }, MergeStrategy = new { Contacts = 'merge_all', Orders = 'transfer_all', Addresses = 'merge_unique', Preferences = 'most_recent' }, Reason = 'Duplicate accounts identified during data cleanup' }); ``` ```json Response theme={null} { "id": "cust_primary_123", "merged_customer_ids": ["cust_dup_456", "cust_dup_789"], "merge_summary": { "orders_transferred": 15, "addresses_merged": 3, "contacts_merged": 2, "total_lifetime_value": 4567.89, "loyalty_points_combined": 2500 }, "conflicts_resolved": [ { "field": "email", "primary_value": "john@example.com", "duplicate_values": ["j.doe@example.com", "johndoe@example.com"], "resolution": "kept_primary" }, { "field": "phone", "primary_value": "+1-555-0123", "duplicate_values": ["+1-555-0124"], "resolution": "kept_all_as_secondary" } ], "merged_at": "2024-01-15T14:30:00Z", "merged_by": "user_admin_123", "success": true } ``` ```json Error Response theme={null} { "error": { "code": "merge_conflict", "message": "Cannot merge customers with active subscriptions. Please resolve subscriptions first.", "details": { "primary_customer_subscriptions": 1, "duplicate_customer_subscriptions": ["cust_dup_456"], "resolution_required": "cancel_or_transfer_subscriptions" } } } ``` # Tag Customer Source: https://docs.stateset.com/api-reference/customer/tag POST https://api.stateset.com/v1/customers/:id/tag This endpoint adds or removes tags from a customer for segmentation and categorization. ### Body The unique identifier of the customer Array of tags to add to the customer Array of tags to remove from the customer Optional metadata for tags Tag category (e.g., "loyalty", "segment", "preference", "behavior") Source of the tag (e.g., "manual", "automatic", "import", "rule\_based") Optional expiry date for time-limited tags ### Response The customer ID Array of all current tags on the customer Tags that were successfully added Tags that were successfully removed Total number of tags on the customer Customer segments based on current tags Timestamp when tags were last updated Indicates whether the operation was successful ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/customers/:id/tag' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "customer_id": "cust_123abc", "tags_to_add": ["vip", "high_value", "early_adopter"], "tags_to_remove": ["prospect"], "tag_metadata": { "category": "loyalty", "source": "manual", "expiry_date": "2024-12-31" } }' ``` ```graphQL GraphQL theme={null} mutation customerTagMutation { customerTag( customerId: "${customerId}", tagsToAdd: ${tagsToAdd}, tagsToRemove: ${tagsToRemove}, tagMetadata: ${tagMetadata} ) { customer { id current_tags segments tag_count } userErrors { field message } } } ``` ```js Node.js theme={null} const taggedCustomer = await stateset.customers.tag({ customer_id: 'cust_123abc', tags_to_add: ['vip', 'high_value', 'early_adopter'], tags_to_remove: ['prospect'], tag_metadata: { category: 'loyalty', source: 'manual', expiry_date: '2024-12-31' } }); ``` ```python Python theme={null} tagged_customer = stateset.customers.tag({ 'customer_id': 'cust_123abc', 'tags_to_add': ['vip', 'high_value', 'early_adopter'], 'tags_to_remove': ['prospect'], 'tag_metadata': { 'category': 'loyalty', 'source': 'manual', 'expiry_date': '2024-12-31' } }) ``` ```ruby Ruby theme={null} tagged_customer = Stateset::Customer.tag({ customer_id: 'cust_123abc', tags_to_add: ['vip', 'high_value', 'early_adopter'], tags_to_remove: ['prospect'], tag_metadata: { category: 'loyalty', source: 'manual', expiry_date: '2024-12-31' } }) ``` ```go Go theme={null} taggedCustomer, err := stateset.Customers.tag({ CustomerID: 'cust_123abc', TagsToAdd: []string{'vip', 'high_value', 'early_adopter'}, TagsToRemove: []string{'prospect'}, TagMetadata: TagMetadata{ Category: 'loyalty', Source: 'manual', ExpiryDate: '2024-12-31' } }) ``` ```java Java theme={null} Customer taggedCustomer = stateset.customers.tag({ customerId: 'cust_123abc', tagsToAdd: ['vip', 'high_value', 'early_adopter'], tagsToRemove: ['prospect'], tagMetadata: { category: 'loyalty', source: 'manual', expiryDate: '2024-12-31' } }); ``` ```php PHP theme={null} $tagged_customer = $stateset->customers->tag([ 'customer_id' => 'cust_123abc', 'tags_to_add' => ['vip', 'high_value', 'early_adopter'], 'tags_to_remove' => ['prospect'], 'tag_metadata' => [ 'category' => 'loyalty', 'source' => 'manual', 'expiry_date' => '2024-12-31' ] ]); ``` ```csharp C# theme={null} var taggedCustomer = await stateset.Customers.Tag(new { CustomerId = 'cust_123abc', TagsToAdd = new[] { 'vip', 'high_value', 'early_adopter' }, TagsToRemove = new[] { 'prospect' }, TagMetadata = new { Category = 'loyalty', Source = 'manual', ExpiryDate = '2024-12-31' } }); ``` ```json Response theme={null} { "id": "cust_123abc", "current_tags": [ "vip", "high_value", "early_adopter", "repeat_buyer", "email_subscriber" ], "tags_added": ["vip", "high_value", "early_adopter"], "tags_removed": ["prospect"], "tag_count": 5, "segments": [ { "id": "seg_premium", "name": "Premium Customers", "matched_by_tags": ["vip", "high_value"] }, { "id": "seg_engaged", "name": "Highly Engaged", "matched_by_tags": ["repeat_buyer", "email_subscriber"] } ], "updated_at": "2024-01-15T10:30:00Z", "updated_by": "user_123", "success": true } ``` ```json Error Response theme={null} { "error": { "code": "invalid_tag", "message": "Tag 'invalid-tag!' contains invalid characters. Tags must be alphanumeric with underscores only.", "details": { "invalid_tags": ["invalid-tag!"], "valid_pattern": "^[a-zA-Z0-9_]+$" } } } ``` # Update Customer Source: https://docs.stateset.com/api-reference/customer/update PUT https://api.stateset.com/v1/customers/:id This endpoint updates an existing customer. ### Body This is the sso\_id of the customer This is the customer object. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The contents of the user group Indicates whether a new user group was created. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the properties object if it was provided in the request body This is the environment tag of the user group. Possible values are 'Customer' and 'Testing' ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/customers/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "string", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "stripe_customer_id": "string", "timestamp": "string", "activationDate": "string" }' ``` ```json Response theme={null} { "id": "string", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "stripe_customer_id": "string", "timestamp": "string", "activationDate": "string" } ``` # Create Cycle Count Source: https://docs.stateset.com/api-reference/cyclecounts/create POST https://api.stateset.com/v1/cycle_counts This endpoint creates a new cycle count ### Body The id of the cycle count to be created. If not provided, a new id will be generated. The number of the cycle count to be created. If not provided, a new number will be generated. The status of the cycle count to be created. If not provided, the status will be set to "open". The part associated with the cycle count to be created. The standard tracking information associated with the cycle count to be created. The serialized tracking information associated with the cycle count to be created. The expected quantity of the part associated with the cycle count to be created. The actual quantity of the part counted during the cycle count to be created. The difference between the expected and actual quantity of the part. The difference in cost between the expected and actual quantity of the part. An explanation for any variances in the cycle count to be created. The site associated with the cycle count to be created. The location associated with the cycle count to be created. The bin associated with the cycle count to be created. The lot associated with the cycle count to be created. The start date associated with the cycle count to be created. The end date associated with the cycle count to be created. The completion date associated with the cycle count to be created. The user assigned to the cycle count to be created. The method used to count the part associated with the cycle count to be created. The status of the cycle count to be created. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/cycle_counts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.cyclecounts.create({ id: '' }); ``` ```python Python theme={null} created = stateset.cyclecounts.create({ 'id': '' }) ``` ```ruby Ruby theme={null} created = Stateset::CycleCount.create({ id: '' }) ``` ```php PHP theme={null} $created = $stateset->cyclecounts->create([ 'id' => '' ]); ``` ```go Go theme={null} created := cyclecounts.Create(&stateset.CycleCount{ ID: '' }) ``` ```java Java theme={null} CycleCount created = cyclecounts.create(new CycleCount(){ id: '' }); ``` ```json Response theme={null} ``` # Delete Cycle Count Source: https://docs.stateset.com/api-reference/cyclecounts/delete DELETE https://api.stateset.com/v1/cycle_counts/:id This endpoint deletes an existing cycle count. ### Body The id of the cycle count to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/cycle_counts/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "pl_ODkRWQtx9NVsRX" }' ``` ```javascript Node.js theme={null} const deleted = await stateset.cyclecounts.del( 'cc_ODkRWQtx9NVsRX' ); ``` ```graphQL GraphQL theme={null} mutation deleteCycleCounts ($pick_id: String!) { delete_cycle_counts(where: {id: {_eq: $cycle_count_id}}) { affected_rows } } ``` ```python Python theme={null} deleted = stateset.cyclecounts.del( 'pl_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} deleted = Stateset::cyclecounts.del( 'pl_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $deleted = $stateset->cyclecounts->del( 'pl_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} deleted, err := stateset.cyclecounts.Del( 'pl_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} cyclecounts deleted = stateset.cyclecounts.del( 'pl_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "id": "pi_1NXWPnCo6bFb1KQto6C8OWvE", "object": "cyclecounts", "deleted": true } ``` # Get Cycle Count Source: https://docs.stateset.com/api-reference/cyclecounts/get GET https://api.stateset.com/v1/cycle_counts This endpoint creates a new cycle count ### Body The id of the cycle count to be created. If not provided, a new id will be generated. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/cycle_counts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.cyclecounts.get({ id: '' }); ``` ```json Response theme={null} ``` # Get Cycle Count Source: https://docs.stateset.com/api-reference/cyclecounts/list GET https://api.stateset.com/v1/cycle_counts This endpoint creates a new cycle count ### Body This is the limit of the picks. This is the offset of the picks. This is the order direction of the picks. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/cycle_counts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.cyclecounts.list({ id: '' }); ``` ```json Response theme={null} ``` # Update Cycle Count Source: https://docs.stateset.com/api-reference/cyclecounts/update POST https://api.stateset.com/v1/cycle_counts This endpoint creates a new cycle count ### Body The id of the cycle count to be created. If not provided, a new id will be generated. The number of the cycle count to be created. If not provided, a new number will be generated. The status of the cycle count to be created. If not provided, the status will be set to "open". The part associated with the cycle count to be created. The standard tracking information associated with the cycle count to be created. The serialized tracking information associated with the cycle count to be created. The expected quantity of the part associated with the cycle count to be created. The actual quantity of the part counted during the cycle count to be created. The difference between the expected and actual quantity of the part. The difference in cost between the expected and actual quantity of the part. An explanation for any variances in the cycle count to be created. The site associated with the cycle count to be created. The location associated with the cycle count to be created. The bin associated with the cycle count to be created. The lot associated with the cycle count to be created. The start date associated with the cycle count to be created. The end date associated with the cycle count to be created. The completion date associated with the cycle count to be created. The user assigned to the cycle count to be created. The method used to count the part associated with the cycle count to be created. The status of the cycle count to be created. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/cycle_counts' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.cyclecounts.create({ id: '' }); ``` ```json Response theme={null} ``` # Error Handling Source: https://docs.stateset.com/api-reference/errors Comprehensive guide to API error responses and handling strategies StateSet API uses standard HTTP response codes and provides detailed error information to help you handle issues gracefully. ## Error Response Format All errors follow a consistent JSON structure to make error handling predictable: ```json theme={null} { "error": { "code": "ERROR_CODE", "message": "Human-readable error message", "type": "error_type", "details": { // Additional context-specific information }, "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE", "timestamp": "2024-01-15T10:30:00Z", "documentation_url": "https://docs.stateset.com/errors/ERROR_CODE" } } ``` ## HTTP Status Codes | Status Code | Meaning | Common Causes | | ----------- | --------------------- | ---------------------------------------------- | | **200** | OK | Request succeeded | | **201** | Created | Resource successfully created | | **202** | Accepted | Request accepted for async processing | | **204** | No Content | Request succeeded with no response body | | **400** | Bad Request | Invalid request parameters or malformed syntax | | **401** | Unauthorized | Missing or invalid authentication | | **403** | Forbidden | Valid auth but insufficient permissions | | **404** | Not Found | Resource doesn't exist | | **409** | Conflict | Resource conflict or duplicate | | **422** | Unprocessable Entity | Valid syntax but semantic errors | | **429** | Too Many Requests | Rate limit exceeded | | **500** | Internal Server Error | Server error - retry with backoff | | **502** | Bad Gateway | Upstream service error | | **503** | Service Unavailable | Temporary service outage | ## Error Types and Codes ### Authentication Errors (401) | Error Code | Description | Resolution | | ---------------------- | -------------------------------- | -------------------------- | | `INVALID_API_KEY` | API key is invalid or revoked | Check key in dashboard | | `EXPIRED_API_KEY` | API key has expired | Generate new API key | | `MISSING_AUTH_HEADER` | No Authorization header provided | Include Bearer token | | `INVALID_TOKEN_FORMAT` | Token format is incorrect | Use `Bearer sk_...` format | | `INACTIVE_ACCOUNT` | Account is suspended or inactive | Contact support | ### Authorization Errors (403) | Error Code | Description | Resolution | | -------------------------- | ------------------------------------- | -------------------------- | | `INSUFFICIENT_PERMISSIONS` | API key lacks required permissions | Use key with proper scopes | | `RESOURCE_ACCESS_DENIED` | Cannot access this specific resource | Check resource ownership | | `PLAN_LIMIT_EXCEEDED` | Feature not available on current plan | Upgrade plan | | `IP_NOT_ALLOWED` | Request from unauthorized IP | Add IP to allowlist | ### Validation Errors (400/422) | Error Code | Description | Resolution | | ------------------------ | ------------------------------------- | --------------------------- | | `VALIDATION_ERROR` | Request validation failed | Check field requirements | | `MISSING_REQUIRED_FIELD` | Required field not provided | Include all required fields | | `INVALID_FIELD_VALUE` | Field value doesn't meet requirements | Validate field format | | `INVALID_ENUM_VALUE` | Value not in allowed enum list | Use accepted values | | `FIELD_TOO_LONG` | Field exceeds maximum length | Truncate field value | | `INVALID_DATE_FORMAT` | Date format incorrect | Use ISO 8601 format | ### Resource Errors (404/409) | Error Code | Description | Resolution | | ------------------------- | ----------------------------------- | ----------------------------------- | | `RESOURCE_NOT_FOUND` | Requested resource doesn't exist | Verify resource ID | | `RESOURCE_ALREADY_EXISTS` | Duplicate resource creation attempt | Use existing resource | | `RESOURCE_LOCKED` | Resource is locked for editing | Wait and retry | | `RESOURCE_ARCHIVED` | Resource has been archived | Unarchive or use different resource | | `PARENT_NOT_FOUND` | Parent resource doesn't exist | Create parent first | ### Business Logic Errors (422) | Error Code | Description | Resolution | | -------------------------- | ------------------------------ | ------------------------------ | | `INSUFFICIENT_INVENTORY` | Not enough inventory available | Reduce quantity or check stock | | `PAYMENT_FAILED` | Payment processing failed | Verify payment details | | `INVALID_STATE_TRANSITION` | Invalid status change | Check allowed transitions | | `OUTSIDE_RETURN_WINDOW` | Return period expired | Check return policy | | `DUPLICATE_REQUEST` | Duplicate request detected | Use idempotency key | ### Rate Limiting Errors (429) ```json theme={null} { "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded", "type": "rate_limit_error", "details": { "limit": 100, "remaining": 0, "reset_at": "2024-01-15T10:35:00Z", "retry_after": 300 } } } ``` ## Error Handling Best Practices ### 1. Implement Exponential Backoff ```javascript Node.js theme={null} class APIClient { async requestWithRetry(url, options, maxRetries = 3) { let lastError; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const response = await fetch(url, options); if (response.status === 429) { const retryAfter = response.headers.get('X-RateLimit-Retry-After'); const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.min(1000 * Math.pow(2, attempt), 32000); if (attempt < maxRetries) { await new Promise(resolve => setTimeout(resolve, delay)); continue; } } if (!response.ok) { const error = await response.json(); throw new APIError(error); } return response.json(); } catch (error) { lastError = error; if (attempt < maxRetries && this.isRetryable(error)) { const delay = Math.min(1000 * Math.pow(2, attempt), 32000); await new Promise(resolve => setTimeout(resolve, delay)); continue; } throw error; } } throw lastError; } isRetryable(error) { const retryableCodes = [429, 500, 502, 503, 504]; return error.status && retryableCodes.includes(error.status); } } ``` ```python Python theme={null} import time import requests from typing import Optional, Dict, Any class APIClient: def __init__(self, api_key: str): self.api_key = api_key self.base_url = "https://api.stateset.com/v1" def request_with_retry( self, method: str, endpoint: str, data: Optional[Dict] = None, max_retries: int = 3 ) -> Dict[str, Any]: url = f"{self.base_url}{endpoint}" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } last_exception = None for attempt in range(max_retries + 1): try: response = requests.request( method, url, json=data, headers=headers ) if response.status_code == 429: retry_after = response.headers.get('X-RateLimit-Retry-After', 1) delay = min( int(retry_after), 2 ** attempt ) if attempt < max_retries: time.sleep(delay) continue response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: last_exception = e if attempt < max_retries and self._is_retryable(e): delay = min(2 ** attempt, 32) time.sleep(delay) continue raise raise last_exception def _is_retryable(self, error: Exception) -> bool: if hasattr(error, 'response'): retryable_codes = {429, 500, 502, 503, 504} return error.response.status_code in retryable_codes return False ``` ### 2. Handle Specific Error Types ```javascript theme={null} class ErrorHandler { handle(error) { switch (error.code) { case 'INVALID_API_KEY': // Refresh API key or prompt for new one return this.refreshApiKey(); case 'INSUFFICIENT_PERMISSIONS': // Inform user about permission requirements return this.showPermissionError(error.details); case 'VALIDATION_ERROR': // Show field-specific errors return this.showValidationErrors(error.details); case 'RATE_LIMITED': // Implement backoff and queue return this.queueRequest(error.details.retry_after); case 'INSUFFICIENT_INVENTORY': // Update UI with available quantity return this.updateInventory(error.details); default: // Generic error handling return this.showGenericError(error.message); } } } ``` ### 3. Implement Circuit Breaker Pattern ```javascript theme={null} class CircuitBreaker { constructor(threshold = 5, timeout = 60000) { this.failureCount = 0; this.failureThreshold = threshold; this.timeout = timeout; this.state = 'CLOSED'; this.nextAttempt = Date.now(); } async call(fn) { if (this.state === 'OPEN') { if (Date.now() < this.nextAttempt) { throw new Error('Circuit breaker is OPEN'); } this.state = 'HALF_OPEN'; } try { const result = await fn(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { this.failureCount = 0; this.state = 'CLOSED'; } onFailure() { this.failureCount++; if (this.failureCount >= this.failureThreshold) { this.state = 'OPEN'; this.nextAttempt = Date.now() + this.timeout; } } } ``` ### 4. Log and Monitor Errors ```javascript theme={null} class ErrorLogger { log(error, context) { const errorData = { timestamp: new Date().toISOString(), request_id: error.request_id, error_code: error.code, message: error.message, context: { user_id: context.userId, endpoint: context.endpoint, method: context.method, ...context }, stack_trace: error.stack }; // Send to logging service logger.error(errorData); // Track in analytics analytics.track('API_ERROR', errorData); // Alert on critical errors if (this.isCritical(error)) { alerting.notify(errorData); } } isCritical(error) { const criticalCodes = [ 'PAYMENT_FAILED', 'SERVICE_UNAVAILABLE', 'DATABASE_ERROR' ]; return criticalCodes.includes(error.code); } } ``` ## Error Recovery Strategies ### Idempotency for Safe Retries ```javascript theme={null} // Use idempotency keys to safely retry requests const createOrder = async (orderData) => { const idempotencyKey = `order-${uuidv4()}`; try { return await api.post('/orders', orderData, { headers: { 'Idempotency-Key': idempotencyKey } }); } catch (error) { if (error.code === 'DUPLICATE_REQUEST') { // Return existing order from previous request return error.details.existing_resource; } throw error; } }; ``` ### Graceful Degradation ```javascript theme={null} class ResilientClient { async getProductWithFallback(productId) { try { // Try primary API return await this.api.get(`/products/${productId}`); } catch (error) { if (error.code === 'SERVICE_UNAVAILABLE') { // Fall back to cache const cached = await this.cache.get(`product:${productId}`); if (cached) { return { ...cached, from_cache: true }; } // Fall back to secondary service return await this.secondaryApi.get(`/products/${productId}`); } throw error; } } } ``` ## Common Error Scenarios ### Handling Validation Errors ```json theme={null} // Request POST /v1/orders { "customer_email": "invalid-email", "items": [] } // Response (422) { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "type": "validation_error", "details": { "errors": [ { "field": "customer_email", "message": "Invalid email format", "expected": "valid email address" }, { "field": "items", "message": "At least one item is required", "expected": "non-empty array" } ] }, "request_id": "req_abc123" } } ``` ### Handling Resource Conflicts ```json theme={null} // Request POST /v1/customers { "email": "existing@example.com" } // Response (409) { "error": { "code": "RESOURCE_ALREADY_EXISTS", "message": "Customer with this email already exists", "type": "conflict_error", "details": { "existing_id": "cus_123abc", "field": "email", "value": "existing@example.com" }, "request_id": "req_def456" } } ``` ## Error Webhooks Configure error webhooks to receive notifications for critical failures: ```json theme={null} { "event": "api.error", "created": "2024-01-15T10:30:00Z", "data": { "error_code": "PAYMENT_FAILED", "request_id": "req_xyz789", "customer_id": "cus_123", "order_id": "ord_456", "amount": 9999, "currency": "usd" } } ``` ## SDK Error Handling Our SDKs provide built-in error handling: ```javascript Node.js SDK theme={null} try { const order = await stateset.orders.create({ customer_email: 'customer@example.com', items: [...] }); } catch (error) { if (error.code === 'INSUFFICIENT_INVENTORY') { // Handle inventory shortage const available = error.details.available_items; console.log(`Only ${available} items available`); } else if (error.code === 'VALIDATION_ERROR') { // Handle validation errors error.details.errors.forEach(err => { console.log(`${err.field}: ${err.message}`); }); } else { // Generic error handling console.error('Unexpected error:', error.message); } } ``` ```python Python SDK theme={null} from stateset import StatesetError, ValidationError, RateLimitError try: order = stateset.orders.create( customer_email='customer@example.com', items=[...] ) except ValidationError as e: # Handle validation errors for error in e.errors: print(f"{error['field']}: {error['message']}") except RateLimitError as e: # Handle rate limiting print(f"Rate limited. Retry after {e.retry_after} seconds") except StatesetError as e: # Handle other API errors print(f"API error: {e.code} - {e.message}") ``` ## Testing Error Scenarios Use test mode to simulate error conditions: ```bash theme={null} # Trigger specific error in test mode curl -X POST https://api.sandbox.stateset.com/v1/orders \ -H "Authorization: Bearer sk_test_..." \ -H "X-Test-Error-Code: INSUFFICIENT_INVENTORY" \ -d '{...}' ``` ## Support If you encounter persistent errors or need help with error handling: * **API Status**: Check [status.stateset.com](https://status.stateset.com) * **Support**: Contact [api-support@stateset.com](mailto:api-support@stateset.com) * **Discord**: Join our [developer community](https://discord.gg/VfcaqgZywq) *** **Related:** [Rate Limiting](/api-reference/rate-limiting) | [Authentication](/api-reference/authentication) | [Webhooks](/api-reference/webhooks) # Event-Driven APIs with StateSet One Source: https://docs.stateset.com/api-reference/events Build autonomous commerce applications with StateSet's event-driven API. # Event-Driven APIs with StateSet One StateSet One provides a powerful event-driven API, designed to empower developers to build autonomous and responsive commerce applications. This approach allows systems to react in real-time to changes, creating more dynamic and efficient processes. ## Core Architecture Principles StateSet's architecture follows a Three-Factor App model integrated with a Durable Execution OS. This design prioritizes scalability, reliability, and maintainability. ### Three-Factor App Architecture with Durable Execution OS * **Single-Point GraphQL API:** A unified interface for data interactions, providing remote data joins. * **Event Triggers and Webhooks:** Enable seamless integrations and automation through event-driven logic. * **Realtime Search:** Provides customer service and warehouse operations with efficient data access. * **Data Validation and Synchronization:** Maintains data integrity and consistency. * **Workflow Orchestration:** Manages complex business processes using Temporal. * **Automated Processes:** Automates routine tasks such as label printing and refund processing. * **Comprehensive Testing:** Ensures quality through rigorous QA testing for all serverless functions. ### Three Factors of StateSet Architecture #### Factor #1: Realtime GraphQL API StateSet uses GraphQL as a flexible and efficient way for clients to interact with its data. * **Low-Latency Responses:** GraphQL ensures that state changes provide immediate feedback to the user. * **GraphQL Subscriptions:** Enables real-time data streaming, eliminating the need for polling and improving scalability. ```mermaid theme={null} graph LR A[Client App] <--> B(GraphQL API) B --> C[Data Source] ``` > A client application sends a GraphQL query to the API which then fetches the data from its underlying data sources. #### Factor #2: Reliable Eventing System StateSet is built on an event-driven architecture where state changes trigger events. * **Atomic Operations:** State changes and event generation are atomic, ensuring consistency. * **At-Least-Once Delivery:** Guarantees that events are delivered to consumers, allowing a complete state history for observability. ```mermaid theme={null} graph LR A[State Change] --> B(Event Bus); B --> C[Event Handlers]; ``` > When a state change happens, it is sent to the event bus and then picked up by the configured event handlers. #### Factor #3: Asynchronous Serverless Functions StateSet uses serverless functions to handle events, providing scalability and cost-efficiency. * **Idempotent Functions:** Functions can handle duplicate events without creating inconsistencies. * **Out-of-Order Event Handling:** Functions handle events reliably, regardless of the order of arrival. ```mermaid theme={null} graph LR A[Event] --> B(Serverless Function); B --> C[Action]; ``` > An event is received by a serverless function which then executes an action. ### Detailed Architecture Components Here's a deeper look at the core components: #### Three-Factor App with Durable Execution OS StateSet's architecture promotes: * **Modular Design:** Business domains are separated into distinct services, allowing independent development and deployment. * **Durable Execution OS:** Ensures workflows and state transitions are reliable, preventing data loss, and enabling recovery from failures. #### Single-Point GraphQL API The GraphQL API offers: * **Remote Data Joins:** Combines data from multiple sources into a single API request, reducing network calls. * **Flexible Queries:** Clients can request specific data, optimizing performance. ```mermaid theme={null} graph LR A[Client App] <--> B(GraphQL API) B --> C[Data Source 1] B --> D[Data Source 2] ``` > The GraphQL API combines data from multiple sources into a single response. #### Event Triggers and Webhooks StateSet leverages: * **Seamless Integrations:** Connects with external systems and services. * **Automated Workflows:** Enables event-driven automated processes. #### Realtime Search Capabilities StateSet provides powerful search functionalities for: * **Customer Service:** Enables quick access to customer information for support teams. * **Warehouse Operations:** Facilitates efficient inventory and order management. #### Data Validation and Synchronization StateSet maintains data integrity with: * **Comprehensive Validation:** Validates incoming data to prevent errors. * **Synchronization Mechanisms:** Keeps data consistent across all systems. #### Workflow Orchestration with Temporal StateSet uses Temporal for: * **Complex Workflow Management:** Orchestrates intricate business processes with ease. * **Automated Execution:** Ensures workflows are reliably executed and can recover from failures. ```mermaid theme={null} graph LR A[Event Trigger] --> B(Temporal Workflow); B --> C[Activity 1]; B --> D[Activity 2]; ``` > An event triggers a temporal workflow. The workflow then coordinates multiple activities #### Automated Processes StateSet automates critical operations: * **Label Printing:** Automatically generates and prints shipping labels for various regions. * **Refund Processing:** Streamlines refund handling for quick and accurate transactions. #### Comprehensive Testing and QA StateSet ensures reliability through: * **Test QA Paths:** Rigorous testing for all serverless functions. ## Event Handling Here's a simple example of how event handling might be implemented in a serverless function: ```javascript theme={null} exports.handler = async (event) => { console.log('Received event:', JSON.stringify(event, null, 2)); try { // Extract event data const { type, payload } = event; if (type === 'order.created') { // Process Order Created Event console.log('Processing order creation:', payload); // Add business logic to perform when order is created // ... } else if (type === 'return.created') { // Process Return Created Event console.log('Processing return creation:', payload); // Add business logic to perform when return is created // ... } else if (type === 'inventory.updated') { // Process Inventory Updated Event console.log('Processing inventory update:', payload); // Add business logic to perform when inventory is updated // ... } else { console.log('Unknown Event Type') } return { statusCode: 200, body: JSON.stringify({ message: 'Event processed successfully' }), }; } catch (error) { console.error('Error processing event:', error); return { statusCode: 500, body: JSON.stringify({ message: 'Error processing event' }), }; } }; ``` > This is an example of a serverless function that can handle multiple different events. The function will check for the event type, extract the payload, perform the business logic, and then return a response. ```mermaid theme={null} graph TD A[StateSet One Web App] <--> B[Realtime GraphQL API] B --> C[(State)] C --> D[Event system] D --> B D --> T[StateSet Cloud Platform] subgraph StateSet_Cloud_Platform[StateSet Cloud Platform] T --> H[Workflows] H --> I[Generate Label] H --> J[Create Order] H --> K[Process Refund] end ``` > The diagram shows the high level interactions between the different parts of the system. ## Conclusion StateSet's event-driven API provides a powerful foundation for building modern commerce applications that are responsive, scalable, and reliable. This framework enables developers to build autonomous systems that react in real-time to changes in their environment. # Features Source: https://docs.stateset.com/api-reference/features Explore the powerful features of the StateSet Platform for agentic commerce operations. # StateSet: Features for Agentic Commerce StateSet is an AI-powered platform designed for direct-to-consumer businesses, warehouses, suppliers, and their developer partners. It's built to automate your commerce operations, providing the scalability and efficiency of major brands. ## Core Benefits StateSet empowers you to: * **Revolutionize Business Operations:** Move beyond manual tasks and embrace automated processes. * **Scale Operations Seamlessly:** Handle increased demand without sacrificing efficiency. * **Improve Efficiency and Productivity:** Streamline workflows to achieve more with less. * **Access Cutting-Edge Technology:** Leverage the latest advancements in web development, AI, and workflow automation. * **Enhance Customer Experience:** Provide superior service and build stronger relationships. ## Key Features ### 1. Streamlined Operations for Enhanced Efficiency StateSet is a comprehensive platform that streamlines your entire operation, from order fulfillment to reverse logistics. * **Simplified Workflows:** Automate routine tasks, allowing your team to focus on strategic initiatives. * **Reverse Logistics:** Efficiently manage returns, exchanges, and warranty processes. * **Automated Label Printing:** Generate shipping labels for regions such as US and Canada with ease. > Spend less time on manual operations and more time on growing your business. ### 2. Enhanced Customer Experience with Intelligent Notifications Keep your customers informed with real-time notifications. * **Real-Time Updates:** Automated event-driven system ensures customers receive updates at every step of their order journey. * **Personalized Notifications:** Tailor notifications to individual customer preferences and needs. * **Reduced Support Overhead:** Proactive communication reduces customer inquiries and support tickets. ```mermaid theme={null} graph LR A[Order Event] --> B(Notification Service); B --> C[Customer]; ``` > The customer gets notified whenever there is an event on their order. > Build trust and loyalty through seamless and transparent communication. ### 3. AI-Powered Customer Support Stateset's AI-powered chat utilizes GPT-5.2 to deliver exceptional support: * **Instant Responses:** Provide immediate answers to customer inquiries, significantly improving response times. * **Automated Support:** Handle FAQs and common issues, freeing up your support team. * **Leverage Existing Data:** Use your FAQ and customer data to personalize responses. > Provide fast, reliable, and intelligent support to boost customer satisfaction. ### 4. Automated Refunds Automate your refund process to provide a frictionless experience. * **Automated Calculations:** Calculate refunds based on order history and return policies without manual intervention. * **Faster Refund Processing:** Process refunds quickly, enhancing customer satisfaction and loyalty. > Process refunds quickly and accurately every time. ### 5. Event-Driven Workflows Orchestrate workflows using Stateset's integrated platform. * **Seamless Workflows:** Build and execute custom workflows tailored to your specific needs. * **Autonomous Operations:** Automate complex business processes from order processing to fulfillment. * **Unified Platform:** Bring together your e-commerce, warehouse, and development teams. ```mermaid theme={null} graph LR A[Event] --> B(Stateset Workflows); B --> C[Action 1] B --> D[Action 2] ``` > StateSet Workflows make it easy to build and orchestrate business operations. > Streamline your operations with a platform that brings together your teams and processes. ### 6. Modern and Agile Technology Stateset uses cutting-edge technologies for a modern platform: * **Web Development Frameworks:** Leverages modern web development frameworks for high performance. * **Distributed Consensus Protocols:** Ensures reliability and consistency in the platform. * **Eliminate Legacy Systems:** Say goodbye to legacy ERP and CRM systems, reducing technical debt. > Harness modern technology to propel your business forward. ### 7. Seamless Developer Collaboration Our platform facilitates seamless integration: * **Interconnected Systems:** Promote collaboration and data flow between different systems and teams. * **Custom Integrations:** Integrate and customize the platform to fit your unique needs. * **Developer-Friendly Environment:** Empower your developer teams to deliver exceptional results. > Collaborate with your developer partners easily with our intuitive platform. ### 8. Robust API Build custom integrations and extend functionality: * **Custom Integrations:** Build custom integrations using our powerful API. * **Streamlined Processes:** Automate your business processes, increasing efficiency. * **Unlock Limitless Possibilities:** Extend the platform to meet your specific requirements. > Unlock the full potential of your data and streamline your operations. ### 9. Reliable Infrastructure Built on proven technology for reliable performance: * **Cloud Services:** Built on proven cloud technologies ensuring high availability and performance. * **Secure Platform:** Prioritizes security and data protection for all users. * **Flexible Solution:** Designed to scale and adapt to your changing business needs. > You can focus on your business and leave the technical details to us. ### 10. Composable Commerce in Minutes Grow faster and scale easier: * **Fast Implementation:** Get started in minutes with easy to use setup tools. * **Scalable Platform:** Grow your business without worrying about infrastructure limitations. * **Collaboration:** Connect with developers through the powerful API and developer friendly documentation. > Embrace the future of commerce automation with StateSet. ## Conclusion StateSet offers a powerful set of features designed to help your business thrive in today's fast-paced market. Our platform enables you to automate, scale, and enhance your operations, leading to increased efficiency, improved customer experience, and business growth. # Web Framework Source: https://docs.stateset.com/api-reference/framework Building modern web applications with React Server Components (RSC) # Framework ## Introduction React Server Components (RSC) is an experimental approach to building server-rendered React applications. By running components directly on the server, developers can simplify data fetching, reduce client-side JavaScript, and maintain a more seamless, modular architecture. This guide explores how RSC can integrate with GraphQL queries and mutations to create modern, scalable web apps—without the complexity of legacy approaches like wrapping entire layouts in providers or managing extensive client-side state. React Server Components ## Getting Started With React Server Components, you can call server actions directly from the UI while leveraging your existing GraphQL operations. This approach sidesteps the need for client-side wrappers like Apollo providers or libraries such as Axios within React components. Instead, RSC enables a more intuitive pattern: server components make direct GraphQL calls, and server actions expose these calls to the client for efficient data fetching and updates. Consider the following example, where server actions trigger GraphQL mutations without requiring additional layers or complex setups: ```typescript theme={null} export const closeReturnAction = async (returnId: string): Promise => { try { await closeReturn(returnId); } catch (e) { return 'Error closing return'; } }; export const reopenReturnAction = async (returnId: string): Promise => { try { await reopenReturn(returnId); } catch (e) { return 'Error reopening return'; } }; export const cancelReturnAction = async (returnId: string): Promise => { try { await cancelReturn(returnId); } catch (e) { return 'Error closing return'; } }; ``` By integrating these actions directly, we retain a clean, modular, and type-safe architecture. The result is a more maintainable codebase that can easily evolve as the application grows. ## Data Fetching with `statesetFetch` RSC excels at server-side data fetching. Below is an example of fetching a return object directly from the server, allowing your page component to receive fully-hydrated data without additional round trips: ```typescript theme={null} export async function getReturn(returnId: string): Promise { const res = await statesetFetch({ cache: 'no-store', query: getReturnQuery, variables: { returnId }, }); return res.body.data.returns_by_pk; } ``` In this example, we use a typed operation (`StatesetReturnOperation`) to ensure end-to-end type safety. The server component (e.g. `page.tsx`) can directly call `getReturn`, removing the complexity of managing GraphQL queries in individual React components. ## GraphQL Operations and Fragments Keep your codebase organized and consistent by centralizing GraphQL queries, mutations, and fragments. This approach ensures you can quickly adapt your data schema without hunting through multiple files. **Query Example:** ```graphql theme={null} export const getReturnQuery = /* GraphQL */ ` query getReturn($returnId: String!) { returns_by_pk(id: $returnId) { ...returnFields } } ${returnFragment} `; ``` **Fragment Example:** ```graphql theme={null} export const returnFragment = /* GraphQL */ ` fragment returnFields on returns { id created_date amount action_needed condition customerEmail customer_id description enteredBy flat_rate_shipping order_date order_id reason_category reported_condition requested_date rma serial_number scanned_serial_number shipped_date status tax_refunded total_refunded tracking_number warehouse_received_date warehouse_condition_date refunded_date } `; ``` Because all operations and fragments are stored in a centralized `lib/stateset` directory, you maintain a single source of truth, minimizing duplication and improving consistency. ## Integrating Server Actions Server actions call these GraphQL operations and return typed data. This approach provides a clearly defined interface for the UI to request data, enabling a smooth integration with server components and client-side interactivity: ```typescript theme={null} export async function getReturns({ limit, offset, order_direction }: { limit?: number; offset?: number; order_direction?: string; }): Promise { const res = await statesetFetch({ query: getReturnsQuery, variables: { limit, offset, order_direction }, cache: 'no-store' }); return res.body.data.returns; } ``` ## From Server Component to Client In your server-rendered pages, you can now retrieve data before sending it to the client. The component below demonstrates how data can be fetched with RSC and then hydrated in the browser for client-side interaction where necessary: ```typescript theme={null} export default function ReturnPage({ returnId }: { returnId: string }) { const [returnData, setReturnData] = useState(undefined); useEffect(() => { const fetchData = async () => { const res = await getReturnAction(returnId); setReturnData(res); }; fetchData(); }, [returnId]); return ( <>
); } ``` By combining server components with server actions and a well-structured GraphQL strategy, you gain the best of both worlds—server-rendered efficiency and client-side responsiveness—without overly complicated data management layers. For a deeper understanding of React Server Components, explore [this article](https://vercel.com/blog/understanding-react-server-components). # Getting Started Source: https://docs.stateset.com/api-reference/getting-started Building intelligent commerce operations with the StateSet API # Getting Started with StateSet API Welcome to StateSet API! This guide will help you get up and running with our comprehensive backend system for order management, inventory control, returns processing, and more. ## Table of Contents * [Prerequisites](#prerequisites) * [Installation](#installation) * [Configuration](#configuration) * [Database Setup](#database-setup) * [Building the Project](#building-the-project) * [Running the API](#running-the-api) * [Development Workflow](#development-workflow) * [Testing](#testing) * [API Documentation](#api-documentation) * [Troubleshooting](#troubleshooting) ## Prerequisites Before you begin, ensure you have the following installed on your development machine: ### Required Software * **Rust** (latest stable version) ```bash theme={null} # Install Rust via rustup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Verify installation rustc --version cargo --version ``` * **Database** (Choose one): * **SQLite** (default for development) * Automatically created when running the API * **PostgreSQL 14+** (recommended for production) ```bash theme={null} # macOS brew install postgresql@14 # Ubuntu/Debian sudo apt-get install postgresql-14 # Verify installation psql --version ``` ### Optional Tools * **Redis** (for caching, optional) ```bash theme={null} # macOS brew install redis # Ubuntu/Debian sudo apt-get install redis-server ``` * **Protocol Buffer Compiler** (for gRPC development) ```bash theme={null} # macOS brew install protobuf # Ubuntu/Debian sudo apt-get install protobuf-compiler ``` ## Installation 1. **Clone the Repository** ```bash theme={null} git clone https://github.com/stateset/stateset-api.git cd stateset-api ``` 2. **Install Rust Dependencies** ```bash theme={null} # This will download and compile all dependencies cargo fetch ``` ## Configuration StateSet API uses environment variables and configuration files for setup. ### 1. Environment Variables (.env) Create a `.env` file in the project root: ```bash theme={null} cp .env.example .env ``` Edit `.env` with your configuration: ```env theme={null} # Database Configuration DATABASE_URL=sqlite:stateset.db?mode=rwc # For SQLite (development) # DATABASE_URL=postgres://username:password@localhost/stateset_db # For PostgreSQL # JWT Configuration JWT_SECRET=your_secure_jwt_secret_key_change_in_production JWT_EXPIRATION=3600 # 1 hour in seconds JWT_REFRESH_EXPIRATION=604800 # 7 days in seconds # Server Configuration PORT=8080 HOST=0.0.0.0 APP_ENV=development # Logging RUST_LOG=stateset_api=debug,tower_http=debug,sea_orm=debug,info # Optional: Redis (if using caching) # REDIS_URL=redis://localhost:6379 ``` ### 2. Configuration File (config/default.toml) The TOML configuration file provides additional settings: ```toml theme={null} # Database database_url = "sqlite:stateset.db?mode=rwc" auto_migrate = true # Automatically run migrations on startup # Server host = "0.0.0.0" port = 8080 # Cache (optional) [cache] cache_type = "memory" # or "redis" if Redis is configured capacity = 1000 default_ttl_secs = 300 ``` ## Database Setup ### SQLite (Default for Development) SQLite requires no additional setup. The database file will be created automatically when you first run the application. ### PostgreSQL (Production) 1. **Create Database** ```bash theme={null} # Connect to PostgreSQL psql -U postgres # Create database and user CREATE DATABASE stateset_db; CREATE USER stateset_user WITH ENCRYPTED PASSWORD 'your_password'; GRANT ALL PRIVILEGES ON DATABASE stateset_db TO stateset_user; \q ``` 2. **Update DATABASE\_URL in .env** ```env theme={null} DATABASE_URL=postgres://stateset_user:your_password@localhost/stateset_db ``` ### Running Migrations Migrations are handled automatically on startup if `auto_migrate = true` in your config. To run them manually: ```bash theme={null} # Using the migration binary cargo run --bin migration # Or using SQLx CLI (if installed) sqlx migrate run ``` ## Building the Project StateSet API provides several build options: ### Development Build ```bash theme={null} # Quick build for development cargo build # Or using the Makefile make build ``` ### Release Build (Optimized) ```bash theme={null} # Optimized build for production cargo build --release # Or using the Makefile make build-release ``` ### Build Specific Components ```bash theme={null} # Build only the main API server cargo build --bin stateset-api # Build the minimal server (lightweight version) cargo build --bin minimal-server # Build the gRPC server cargo build --bin grpc-server # Build performance testing tools cargo build --bin orders-bench cargo build --bin orders-mock-server ``` ## Running the API ### Main API Server ```bash theme={null} # Run in development mode cargo run # Or using the Makefile make run # Run with specific binary cargo run --bin stateset-api # Run release build ./target/release/stateset-api ``` ### Alternative Servers ```bash theme={null} # Run minimal server (lightweight, fewer features) cargo run --bin minimal-server # Run gRPC server cargo run --bin grpc-server # Run mock server for testing cargo run --bin orders-mock-server ``` ### Verify the Server is Running ```bash theme={null} # Health check curl http://localhost:8080/health # Should return: # {"status":"healthy"} ``` ## Development Workflow ### 1. Code Organization ``` src/ ├── commands/ # Write operations (Command pattern) ├── queries/ # Read operations (Query pattern) ├── handlers/ # HTTP request handlers ├── services/ # Business logic ├── entities/ # Database entities (SeaORM) ├── models/ # Domain models ├── repositories/ # Data access layer └── main.rs # Application entry point ``` ### 2. Adding New Features 1. **Create Command/Query** ```rust theme={null} // src/commands/orders/create_order_command.rs pub struct CreateOrderCommand { pub customer_id: Uuid, pub items: Vec, } ``` 2. **Implement Service** ```rust theme={null} // src/services/orders.rs impl OrderService { pub async fn create_order(&self, cmd: CreateOrderCommand) -> Result { // Business logic here } } ``` 3. **Add Handler** ```rust theme={null} // src/handlers/orders.rs pub async fn create_order( State(state): State, Json(payload): Json, ) -> Result> { // Handle HTTP request } ``` ### 3. Hot Reloading (Development) Use `cargo-watch` for automatic recompilation: ```bash theme={null} # Install cargo-watch cargo install cargo-watch # Run with auto-reload cargo watch -x run ``` ### 4. Code Quality Tools ```bash theme={null} # Format code cargo fmt # Run linter cargo clippy # Check for security issues cargo audit # Generate documentation cargo doc --open ``` ## Testing ### Running Tests ```bash theme={null} # Run all tests cargo test # Run specific test cargo test test_create_order # Run tests with output cargo test -- --nocapture # Run tests with backtrace RUST_BACKTRACE=1 cargo test # Run integration tests only cargo test --test '*' # Using Makefile make test ``` ### Writing Tests ```rust theme={null} #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_create_order() { // Test implementation let service = OrderService::new(db_pool); let order = service.create_order(cmd).await.unwrap(); assert_eq!(order.status, "pending"); } } ``` ### Performance Testing ```bash theme={null} # Run order throughput benchmark cargo run --bin orders-bench # Start mock server for load testing cargo run --bin orders-mock-server # In another terminal, run benchmarks ab -n 1000 -c 10 http://localhost:8080/orders ``` ## API Documentation ### REST API Endpoints The API provides comprehensive endpoints for all operations: #### Authentication * `POST /auth/register` - Register new user * `POST /auth/login` - Login and receive JWT token * `POST /auth/refresh` - Refresh JWT token #### Orders * `GET /orders` - List all orders * `GET /orders/:id` - Get order by ID * `POST /orders` - Create new order * `PUT /orders/:id` - Update order * `DELETE /orders/:id` - Delete order * `POST /orders/:id/cancel` - Cancel order * `POST /orders/:id/hold` - Put order on hold #### Inventory * `GET /inventory` - Get inventory levels * `POST /inventory/adjust` - Adjust inventory * `POST /inventory/allocate` - Allocate inventory * `POST /inventory/reserve` - Reserve inventory #### Returns * `POST /returns` - Create return * `GET /returns/:id` - Get return details * `POST /returns/:id/approve` - Approve return * `POST /returns/:id/reject` - Reject return ### OpenAPI/Swagger Documentation When running in development mode, interactive API documentation is available at: ``` http://localhost:8080/swagger-ui ``` ### gRPC API For gRPC clients, proto files are located in `proto/` directory. Generate client code: ```bash theme={null} # Generate Rust code from proto files cargo build # Automatically generates during build # For other languages, use protoc directly protoc --go_out=. --go-grpc_out=. proto/*.proto ``` ## Troubleshooting ### Common Issues and Solutions #### 1. Build Errors ```bash theme={null} # Clear build cache cargo clean # Update dependencies cargo update # Check for specific errors cargo build 2>&1 | tee build_errors.log ``` #### 2. Database Connection Issues ```bash theme={null} # Test database connection psql $DATABASE_URL -c "SELECT 1" # For SQLite, check file permissions ls -la stateset.db # Reset database rm stateset.db # For SQLite # OR DROP DATABASE stateset_db; CREATE DATABASE stateset_db; # For PostgreSQL ``` #### 3. Port Already in Use ```bash theme={null} # Find process using port 8080 lsof -i :8080 # Kill the process kill -9 # Or use a different port PORT=3000 cargo run ``` #### 4. Migration Failures ```bash theme={null} # Reset migrations cargo run --bin migration -- reset # Run migrations step by step cargo run --bin migration -- up ``` ### Debugging ```bash theme={null} # Enable debug logging RUST_LOG=debug cargo run # Enable backtrace for errors RUST_BACKTRACE=1 cargo run # Use debugger (VS Code or IntelliJ Rust) # Add breakpoints and run in debug mode ``` ### Performance Issues ```bash theme={null} # Profile the application cargo build --release valgrind --tool=callgrind ./target/release/stateset-api # Check database queries RUST_LOG=sea_orm=debug cargo run # Monitor resource usage htop # While application is running ``` ## Next Steps 1. **Explore the Codebase** * Review `src/handlers/` for API endpoints * Check `src/services/` for business logic * Look at `tests/` for usage examples 2. **Customize Configuration** * Modify `config/default.toml` for your needs * Set up proper JWT secrets for security * Configure database connections 3. **Set Up Development Environment** * Install VS Code with rust-analyzer extension * Configure your IDE for Rust development * Set up pre-commit hooks for code quality 4. **Learn the Architecture** * Read about CQRS pattern used in commands/queries * Understand the event-driven architecture * Review the domain models and entities 5. **Contribute** * Check out open issues on GitHub * Read CONTRIBUTING.md for guidelines * Join our community discussions ## Getting Help * **Documentation**: Full docs at [docs.stateset.com](https://docs.stateset.com) * **GitHub Issues**: [github.com/stateset/stateset-api/issues](https://github.com/stateset/stateset-api/issues) * **Discord Community**: Join our Discord for real-time help * **API Reference**: Check `/swagger-ui` when running locally ## License StateSet API is licensed under the MIT License. See [LICENSE](LICENSE) for details. *** Happy coding! Welcome to the StateSet community! 🚀 # Check Gift Card Balance Source: https://docs.stateset.com/api-reference/gift-cards/check-balance POST https://api.stateset.com/v1/gift-cards/balance Check the balance and validity of a gift card This endpoint checks the current balance and status of a gift card. It's commonly used at checkout or in customer portals. ## Authentication This endpoint requires a valid API key with `gift_cards:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Gift card code to check Gift card PIN (required for some gift cards) ### Response Returns gift card balance and status information. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/gift-cards/balance' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "code": "GIFT-XMAS-A3B7C9D2" }' ``` ```javascript Node.js theme={null} const balance = await stateset.giftCards.checkBalance({ code: "GIFT-XMAS-A3B7C9D2" }); ``` ```python Python theme={null} balance = stateset.gift_cards.check_balance( code="GIFT-XMAS-A3B7C9D2" ) ``` ```json Response theme={null} { "valid": true, "gift_card": { "id": "gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "code": "GIFT-XMAS-A3B7C9D2", "status": "active", "current_balance": 3750, "initial_balance": 5000, "currency": "USD", "expires_at": "2025-02-14T23:59:59Z", "is_expired": false, "days_until_expiry": 390 }, "transactions": { "total_redeemed": 1250, "redemption_count": 2, "last_redemption": { "date": "2024-01-15T14:30:00Z", "amount": 750, "order_id": "order_456789" } }, "restrictions": { "minimum_purchase": null, "product_restrictions": false, "category_restrictions": false }, "can_be_used": true, "messages": [] } ``` # Create Gift Card Source: https://docs.stateset.com/api-reference/gift-cards/create POST https://api.stateset.com/v1/gift-cards Create a new gift card with a specified balance This endpoint creates a new gift card that can be purchased or issued to customers. Gift cards support both physical and digital delivery, custom designs, and flexible redemption rules. ## Authentication This endpoint requires a valid API key with `gift_cards:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Gift card type: "physical", "digital", "both" Initial balance in cents (e.g., 5000 for \$50.00) ISO 4217 currency code Gift card recipient information Recipient email for digital delivery Recipient name Personal message to recipient Scheduled delivery date (ISO 8601) Gift card purchaser information Existing customer ID Purchaser email Purchaser name Gift card design customization Design template ID Custom image URL Theme: "birthday", "holiday", "thank\_you", "congratulations", "custom" Gift card validity settings Expiration date (ISO 8601) Activation date for future use (ISO 8601) Usage restrictions Restricted to specific products Restricted to specific categories Cannot be used on sale items Minimum purchase amount in cents Custom gift card code (auto-generated if not provided) Associated order ID if purchased Additional custom fields ### Response Returns the created gift card object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/gift-cards' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "type": "digital", "initial_balance": 5000, "currency": "USD", "recipient": { "email": "recipient@example.com", "name": "Jane Smith", "message": "Happy Birthday! Enjoy your shopping.", "delivery_date": "2024-02-14T09:00:00Z" }, "purchaser": { "customer_id": "cust_abc123", "email": "purchaser@example.com", "name": "John Doe" }, "design": { "template_id": "tmpl_birthday_001", "theme": "birthday" }, "validity": { "expires_at": "2025-02-14T23:59:59Z" }, "order_id": "order_789012" }' ``` ```javascript Node.js theme={null} const giftCard = await stateset.giftCards.create({ type: "digital", initial_balance: 5000, currency: "USD", recipient: { email: "recipient@example.com", name: "Jane Smith", message: "Happy Birthday! Enjoy your shopping.", delivery_date: "2024-02-14T09:00:00Z" }, purchaser: { customer_id: "cust_abc123", email: "purchaser@example.com", name: "John Doe" }, design: { template_id: "tmpl_birthday_001", theme: "birthday" }, validity: { expires_at: "2025-02-14T23:59:59Z" }, order_id: "order_789012" }); ``` ```python Python theme={null} gift_card = stateset.gift_cards.create( type="digital", initial_balance=5000, currency="USD", recipient={ "email": "recipient@example.com", "name": "Jane Smith", "message": "Happy Birthday! Enjoy your shopping.", "delivery_date": "2024-02-14T09:00:00Z" }, purchaser={ "customer_id": "cust_abc123", "email": "purchaser@example.com", "name": "John Doe" }, design={ "template_id": "tmpl_birthday_001", "theme": "birthday" }, validity={ "expires_at": "2025-02-14T23:59:59Z" }, order_id="order_789012" ) ``` ```json Response theme={null} { "id": "gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "gift_card", "code": "GIFT-XMAS-A3B7C9D2", "type": "digital", "status": "active", "initial_balance": 5000, "current_balance": 5000, "currency": "USD", "recipient": { "email": "recipient@example.com", "name": "Jane Smith", "message": "Happy Birthday! Enjoy your shopping.", "delivery_date": "2024-02-14T09:00:00Z", "delivery_status": "scheduled" }, "purchaser": { "customer_id": "cust_abc123", "email": "purchaser@example.com", "name": "John Doe" }, "design": { "template_id": "tmpl_birthday_001", "theme": "birthday", "preview_url": "https://gift-cards.stateset.com/preview/gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, "validity": { "activated_at": "2024-01-20T12:00:00Z", "expires_at": "2025-02-14T23:59:59Z", "is_expired": false, "days_until_expiry": 390 }, "restrictions": { "product_ids": [], "category_ids": [], "exclude_sale_items": false, "minimum_purchase": null }, "redemption_url": "https://shop.example.com/gift-card/GIFT-XMAS-A3B7C9D2", "order_id": "order_789012", "created_at": "2024-01-20T12:00:00Z", "updated_at": "2024-01-20T12:00:00Z", "transactions": [], "metadata": { "campaign": "birthday_promo_2024" } } ``` # Get Gift Card Source: https://docs.stateset.com/api-reference/gift-cards/get GET https://api.stateset.com/v1/gift-cards/:id Retrieve details of a specific gift card This endpoint retrieves detailed information about a specific gift card, including balance, transaction history, and redemption details. ## Authentication This endpoint requires a valid API key with `gift_cards:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the gift card ### Response Returns the gift card object if found. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/gift-cards/gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const giftCard = await stateset.giftCards.retrieve( 'gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} gift_card = stateset.gift_cards.retrieve( 'gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "gift_card", "code": "GIFT-XMAS-A3B7C9D2", "type": "digital", "status": "active", "initial_balance": 5000, "current_balance": 3750, "currency": "USD", "recipient": { "email": "recipient@example.com", "name": "Jane Smith", "message": "Happy Birthday! Enjoy your shopping.", "delivery_date": "2024-02-14T09:00:00Z", "delivery_status": "delivered", "delivered_at": "2024-02-14T09:00:05Z" }, "purchaser": { "customer_id": "cust_abc123", "email": "purchaser@example.com", "name": "John Doe" }, "design": { "template_id": "tmpl_birthday_001", "theme": "birthday", "preview_url": "https://gift-cards.stateset.com/preview/gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, "validity": { "activated_at": "2024-02-14T09:00:05Z", "expires_at": "2025-02-14T23:59:59Z", "is_expired": false, "days_until_expiry": 328 }, "restrictions": { "product_ids": [], "category_ids": [], "exclude_sale_items": false, "minimum_purchase": null }, "redemption_url": "https://shop.example.com/gift-card/GIFT-XMAS-A3B7C9D2", "order_id": "order_789012", "created_at": "2024-01-20T12:00:00Z", "updated_at": "2024-03-15T10:30:00Z", "transactions": [ { "id": "txn_123", "type": "redemption", "amount": 750, "balance_after": 4250, "order_id": "order_456789", "created_at": "2024-03-01T14:20:00Z" }, { "id": "txn_124", "type": "redemption", "amount": 500, "balance_after": 3750, "order_id": "order_567890", "created_at": "2024-03-15T10:30:00Z" } ], "metadata": { "campaign": "birthday_promo_2024" } } ``` # Redeem Gift Card Source: https://docs.stateset.com/api-reference/gift-cards/redeem POST https://api.stateset.com/v1/gift-cards/redeem Redeem a gift card for an order This endpoint redeems a gift card, deducting the specified amount from the card's balance. It validates the card and checks all restrictions before processing. ## Authentication This endpoint requires a valid API key with `gift_cards:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Gift card code to redeem Gift card PIN (if required) Amount to redeem in cents Order ID to apply the gift card to Customer ID making the redemption ### Response Returns the redemption transaction details. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/gift-cards/redeem' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "code": "GIFT-XMAS-A3B7C9D2", "amount": 2500, "order_id": "order_987654", "customer_id": "cust_def456" }' ``` ```javascript Node.js theme={null} const redemption = await stateset.giftCards.redeem({ code: "GIFT-XMAS-A3B7C9D2", amount: 2500, order_id: "order_987654", customer_id: "cust_def456" }); ``` ```python Python theme={null} redemption = stateset.gift_cards.redeem( code="GIFT-XMAS-A3B7C9D2", amount=2500, order_id="order_987654", customer_id="cust_def456" ) ``` ```json Response theme={null} { "id": "txn_125", "object": "gift_card_transaction", "type": "redemption", "gift_card_id": "gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "code": "GIFT-XMAS-A3B7C9D2", "amount": 2500, "currency": "USD", "balance_before": 3750, "balance_after": 1250, "order_id": "order_987654", "customer_id": "cust_def456", "status": "completed", "created_at": "2024-06-20T16:00:00Z", "gift_card": { "id": "gc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "current_balance": 1250, "expires_at": "2025-02-14T23:59:59Z", "is_expired": false, "status": "active" }, "metadata": { "pos_terminal_id": null, "cashier_id": null } } ``` # gRPC Framework Source: https://docs.stateset.com/api-reference/grpc-framework Building modern web apps with the gRPC framework # Framework ## Introduction gRPC is a high-performance, open-source universal RPC framework that puts data first. It provides a simple, efficient, and scalable way to build distributed systems. ## Getting Started ```protobuf theme={null} syntax = "proto3"; package stateset.return_order; import "google/protobuf/timestamp.proto"; import "common.proto"; message Return { string id = 1; string order_id = 2; string customer_id = 3; repeated ReturnItem items = 4; string status = 5; string reason = 6; google.protobuf.Timestamp created_at = 7; google.protobuf.Timestamp updated_at = 8; } message ReturnItem { string product_id = 1; int32 quantity = 2; string reason = 3; } message CreateReturnRequest { Return return = 1; } message CreateReturnResponse { string return_id = 1; string status = 2; } message GetReturnRequest { string return_id = 1; } message GetReturnResponse { Return return = 1; } message UpdateReturnStatusRequest { string return_id = 1; string new_status = 2; } message UpdateReturnStatusResponse { string return_id = 1; string status = 2; } message ListReturnsRequest { string customer_id = 1; string order_id = 2; string status = 3; google.protobuf.Timestamp start_date = 4; google.protobuf.Timestamp end_date = 5; common.PaginationRequest pagination = 6; } message ListReturnsResponse { repeated Return returns = 1; common.PaginationResponse pagination = 2; } service ReturnService { rpc CreateReturn (CreateReturnRequest) returns (CreateReturnResponse); rpc GetReturn (GetReturnRequest) returns (GetReturnResponse); rpc UpdateReturnStatus (UpdateReturnStatusRequest) returns (UpdateReturnStatusResponse); rpc ListReturns (ListReturnsRequest) returns (ListReturnsResponse); } ``` We can now build our handlers and services to handle the requests and responses. To learn more about Protocol Buffers, check out [this article](https://protobuf.dev/). # Integrations Source: https://docs.stateset.com/api-reference/integrations Overview of the Stateset One Platform Integrations # Integrations ## Overview The StateSet One Platform integrates with a wide range of third-party services and systems to provide a comprehensive and seamless experience for users. These integrations enable users to leverage existing tools and services while extending the capabilities of the StateSet One Platform. # API Reference Source: https://docs.stateset.com/api-reference/introduction Complete reference for the StateSet API - Build powerful autonomous business applications # StateSet API Reference Welcome to the StateSet API. Our comprehensive REST and GraphQL APIs enable you to build powerful autonomous business applications that scale with your needs. **API Version:** v1 (Current) **SDK Versions:** Node.js v3.2.0 | Python v2.1.0 | Go v1.4.0 | Ruby v2.0.0 **Last Updated:** January 2026 RESTful endpoints for all StateSet resources Flexible queries with real-time subscriptions Official SDKs for popular languages Real-time event notifications **Production Environment:** * Base URL: `https://api.stateset.com/v1` * GraphQL: `https://api.stateset.com/graphql` * WebSocket: `wss://api.stateset.com/v1/ws` **Sandbox Environment:** * Base URL: `https://api.sandbox.stateset.com/v1` * GraphQL: `https://api.sandbox.stateset.com/graphql` * WebSocket: `wss://api.sandbox.stateset.com/v1/ws` ## Quick Start 1. Sign up at [stateset.com](https://stateset.com) 2. Navigate to **Settings** → **API Keys** 3. Generate a new API key with appropriate scopes Store your API key securely and never expose it in client-side code. Test the connection with a simple API call: ```bash theme={null} curl https://api.stateset.com/v1/orders \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" ``` Browse our comprehensive API reference to discover all available endpoints and capabilities. ## Authentication StateSet API uses API key authentication with support for multiple authentication methods to suit different use cases. ### API Key Types | Key Type | Prefix | Environment | Usage | | ------------------- | ---------- | ----------- | -------------------------- | | **Live Key** | `sk_live_` | Production | Real transactions and data | | **Test Key** | `sk_test_` | Sandbox | Development and testing | | **Restricted Key** | `rk_live_` | Production | Limited scope access | | **Publishable Key** | `pk_live_` | Client-side | Public operations only | ### API Key Authentication ```bash cURL theme={null} curl https://api.stateset.com/v1/orders \ -H "Authorization: Bearer ${STATESET_API_KEY}" ``` ```javascript JavaScript/Node.js theme={null} // Using fetch const response = await fetch('https://api.stateset.com/v1/orders', { headers: { 'Authorization': `Bearer ${process.env.STATESET_API_KEY}`, 'Content-Type': 'application/json' } }); // Using our SDK import { StateSetClient } from 'stateset-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); ``` ```python Python theme={null} import requests import os # Using requests response = requests.get( 'https://api.stateset.com/v1/orders', headers={ 'Authorization': f'Bearer {os.getenv("STATESET_API_KEY")}', 'Content-Type': 'application/json' } ) # Using our SDK from stateset import StateSet client = StateSet(api_key=os.getenv("STATESET_API_KEY")) ``` ```go Go theme={null} package main import ( "net/http" "os" ) func main() { client := &http.Client{} req, _ := http.NewRequest("GET", "https://api.stateset.com/v1/orders", nil) req.Header.Add("Authorization", "Bearer " + os.Getenv("STATESET_API_KEY")) req.Header.Add("Content-Type", "application/json") resp, _ := client.Do(req) } ``` ### Environment Variables We recommend storing your API keys as environment variables: ```bash theme={null} # .env.development STATESET_API_KEY=sk_test_your_actual_key_here STATESET_WEBHOOK_SECRET=whsec_test_... STATESET_ENVIRONMENT=sandbox # .env.production STATESET_API_KEY=sk_live_your_actual_key_here STATESET_WEBHOOK_SECRET=whsec_live_... STATESET_ENVIRONMENT=production ``` Never commit API keys to version control. Use environment variables or secure key management services. ## Rate Limits **Rate Limits by Plan:** * **Starter:** 100 requests/minute, 10,000 requests/day * **Growth:** 1,000 requests/minute, 100,000 requests/day * **Scale:** 5,000 requests/minute, 500,000 requests/day * **Enterprise:** Custom limits up to 10,000 requests/minute **Rate limit headers included in responses:** * `X-RateLimit-Limit`: Maximum requests allowed in current window * `X-RateLimit-Remaining`: Requests remaining in current window * `X-RateLimit-Reset`: Unix timestamp when limit resets * `X-RateLimit-Retry-After`: Seconds to wait before retrying (when limited) ### Handling Rate Limits When you exceed rate limits, you'll receive a `429 Too Many Requests` response: ```json theme={null} { "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded. Please retry after 60 seconds.", "retry_after": 60, "limit": 1000, "remaining": 0, "reset_at": "2024-01-15T12:00:00Z" } } ``` **Best practices for handling rate limits:** ```javascript Exponential Backoff theme={null} async function apiRequestWithRetry(url, options, maxRetries = 3) { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const response = await fetch(url, options); if (response.status === 429) { const retryAfter = response.headers.get('X-RateLimit-Retry-After'); const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000; if (attempt < maxRetries) { await new Promise(resolve => setTimeout(resolve, delay)); continue; } } return response; } catch (error) { if (attempt === maxRetries) throw error; await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000)); } } } ``` ```python Python Retry Logic theme={null} import time import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def create_session_with_retries(): session = requests.Session() retry_strategy = Retry( total=3, status_forcelist=[429, 500, 502, 503, 504], backoff_factor=1, respect_retry_after_header=True ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter) return session # Usage session = create_session_with_retries() response = session.get('https://api.stateset.com/v1/orders', headers={'Authorization': 'Bearer your_key'}) ``` ## Error Handling StateSet API uses conventional HTTP response codes and returns detailed error information in JSON format with consistent error structures. ### HTTP Status Codes | Code | Meaning | | ----- | -------------------------------------------------------------- | | `200` | **OK** - Request succeeded | | `201` | **Created** - Resource created successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `403` | **Forbidden** - Insufficient permissions | | `404` | **Not Found** - Resource doesn't exist | | `409` | **Conflict** - Resource already exists or constraint violation | | `422` | **Unprocessable Entity** - Validation errors | | `429` | **Too Many Requests** - Rate limit exceeded | | `500` | **Internal Server Error** - Something went wrong on our end | ### Error Response Format ```json theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "details": { "field": "email", "issue": "Invalid email format", "expected": "valid email address", "received": "invalid-email" }, "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE", "timestamp": "2024-01-15T10:30:00Z", "documentation_url": "https://docs.stateset.com/errors/VALIDATION_ERROR" } } ``` ### Common Error Codes * `INVALID_API_KEY`: API key is invalid or expired * `MISSING_API_KEY`: No API key provided * `INSUFFICIENT_PERMISSIONS`: API key doesn't have required permissions * `VALIDATION_ERROR`: Request data failed validation * `MISSING_REQUIRED_FIELD`: Required field not provided * `INVALID_FIELD_FORMAT`: Field format is incorrect * `RESOURCE_NOT_FOUND`: Requested resource doesn't exist * `RESOURCE_ALREADY_EXISTS`: Resource with same identifier exists * `RESOURCE_CONFLICT`: Operation conflicts with current resource state ## Pagination List endpoints support both offset-based and cursor-based pagination. We recommend cursor-based pagination for better performance and consistency. ### Pagination Parameters | Parameter | Type | Default | Max | Description | | --------- | ------- | ------- | ----- | ---------------------------------- | | `limit` | integer | 10 | 100 | Number of items per page | | `cursor` | string | null | - | Cursor for next page (recommended) | | `offset` | integer | 0 | 10000 | Number of items to skip | | `page` | integer | 1 | - | Page number (deprecated) | ### Offset-Based Pagination ```bash theme={null} GET /v1/orders?limit=20&offset=40 ``` ### Cursor-Based Pagination (Recommended) More efficient for large datasets and handles real-time data changes: ```bash theme={null} GET /v1/orders?limit=20&cursor=eyJpZCI6Im9yZF8xMjM0NSJ9 ``` **Response format:** ```json theme={null} { "data": [...], "pagination": { "has_more": true, "next_cursor": "eyJpZCI6Im9yZF82Nzg5MCJ9", "previous_cursor": "eyJpZCI6Im9yZF8wMTIzNCJ9", "total_count": 1250, "page_count": 63, "current_page": 3 }, "meta": { "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE", "response_time_ms": 142 } } ``` ## Filtering and Sorting Most list endpoints support powerful filtering and sorting capabilities using a consistent query syntax. ### Filter Operators | Operator | Description | Example | | ---------- | --------------------- | ---------------------------------------- | | `_eq` | Equals | `?status_eq=shipped` | | `_ne` | Not equals | `?status_ne=cancelled` | | `_gt` | Greater than | `?amount_gt=100` | | `_gte` | Greater than or equal | `?amount_gte=100` | | `_lt` | Less than | `?amount_lt=500` | | `_lte` | Less than or equal | `?amount_lte=500` | | `_in` | In array | `?status_in=pending,processing` | | `_like` | Pattern match | `?email_like=%@example.com` | | `_between` | Range | `?created_between=2024-01-01,2024-01-31` | ### Common Filter Patterns ```bash theme={null} # Exact match GET /v1/orders?status=shipped # Multiple values GET /v1/orders?status_in=pending,processing,shipped # Range queries GET /v1/orders?created_after=2024-01-01T00:00:00Z GET /v1/orders?total_amount_gte=100.00&total_amount_lte=500.00 # Search GET /v1/orders?search=john@example.com # Complex filtering GET /v1/orders?status=shipped&created_after=2024-01-01&customer_tier=gold ``` ### Sorting ```bash theme={null} # Sort by field (default: ascending) GET /v1/orders?sort=created_at # Specify direction GET /v1/orders?sort=total_amount&order=desc # Multiple sort fields GET /v1/orders?sort=status,created_at&order=asc,desc ``` ## Official SDKs ```bash theme={null} npm install stateset-node ``` ```bash theme={null} pip install stateset-python ``` ```bash theme={null} gem install stateset-ruby ``` ```bash theme={null} go get github.com/stateset/stateset-go ``` ### SDK Quick Example ```javascript Node.js theme={null} import { StateSetClient } from 'stateset-node'; // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: 'production' // or 'sandbox' }); // Create an order const order = await client.orders.create({ customer_email: 'customer@example.com', items: [ { sku: 'WIDGET-001', quantity: 2, price: 29.99 } ] }); logger.info('Order created', { orderId: order.id }); ``` ```python Python theme={null} from stateset import StateSet client = StateSet( api_key=os.getenv('STATESET_API_KEY'), environment='production' ) # Create an order order = client.orders.create({ 'customer_email': 'customer@example.com', 'items': [ {'sku': 'WIDGET-001', 'quantity': 2, 'price': 29.99} ] }) print(f'Order created: {order.id}') ``` ## GraphQL API StateSet offers a powerful GraphQL API for flexible data querying and real-time subscriptions. ### GraphQL Endpoint ``` POST https://api.stateset.com/graphql ``` ### Basic Query Example ```graphql theme={null} query GetOrdersWithItems { orders(limit: 10, where: {status: {_eq: "shipped"}}) { id order_number status total_amount customer { id email first_name last_name } line_items { id sku quantity price product { name category } } } } ``` ### Real-time Subscriptions ```graphql theme={null} subscription OrderUpdates { orders(where: {status: {_in: ["processing", "shipped"]}}) { id status updated_at } } ``` ## Webhooks StateSet can send webhook notifications for important events in your account. Webhooks enable real-time integrations and automated workflows. ### Webhook Configuration 1. Configure endpoints in Dashboard → Settings → Webhooks 2. Select events to subscribe to 3. Add webhook signing secret to verify authenticity 4. Test with webhook simulator ### Webhook Events * `order.created` - New order placed * `order.updated` - Order details modified * `order.paid` - Payment confirmed * `order.processing` - Order processing started * `order.shipped` - Shipment created * `order.delivered` - Delivery confirmed * `order.cancelled` - Order cancelled * `order.refunded` - Refund processed * `return.created` - Return initiated * `return.approved` - Return approved * `return.received` - Items received * `return.processed` - Return completed * `return.rejected` - Return rejected * `inventory.low_stock` - Stock below threshold * `inventory.out_of_stock` - Item out of stock * `inventory.updated` - Stock levels changed * `inventory.transfer` - Stock transferred * `customer.created` - New customer registered * `customer.updated` - Customer profile updated * `customer.deleted` - Customer deleted * `customer.subscription.created` - Subscription started * `customer.subscription.cancelled` - Subscription cancelled ### Webhook Payload Structure ```json theme={null} { "id": "evt_1NXWPnCo6bFb1KQto6C8OWvE", "type": "order.created", "created": "2024-01-15T10:30:00Z", "data": { "object": { /* Full object data */ } }, "previous_attributes": { /* For update events */ }, "metadata": { "workspace_id": "ws_123", "user_id": "usr_456", "api_version": "2024-01-01" } } ``` ### Webhook Security & Verification ```javascript theme={null} // Production-ready webhook verification const crypto = require('crypto'); // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; function verifyWebhook(payload, signature, secret) { // Extract timestamp and signatures const elements = signature.split(' '); const timestamp = elements.find(e => e.startsWith('t=')).slice(2); const signatures = elements.filter(e => e.startsWith('v1=')).map(e => e.slice(3)); // Verify timestamp is within 5 minutes const currentTime = Math.floor(Date.now() / 1000); if (currentTime - parseInt(timestamp) > 300) { throw new Error('Webhook timestamp too old'); } // Compute expected signature const signedPayload = `${timestamp}.${payload}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex'); // Verify signature matches const valid = signatures.some(sig => crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expectedSignature)) ); if (!valid) { throw new Error('Invalid webhook signature'); } return true; } // Express.js webhook handler app.post('/webhooks/stateset', express.raw({type: 'application/json'}), (req, res) => { const signature = req.headers['stateset-signature']; const secret = process.env.STATESET_WEBHOOK_SECRET; try { verifyWebhook(req.body, signature, secret); const event = JSON.parse(req.body); // Process webhook event switch(event.type) { case 'order.created': handleOrderCreated(event.data.object); break; case 'return.approved': handleReturnApproved(event.data.object); break; // ... handle other events } res.json({received: true}); } catch (error) { logger.error('Webhook error', { message: error.message }); res.status(400).json({error: 'Webhook verification failed'}); } }); ``` ## Testing ### Sandbox Environment The sandbox environment provides a complete testing environment that mirrors production: ```bash theme={null} # Sandbox endpoints REST API: https://api.sandbox.stateset.com/v1 GraphQL: https://api.sandbox.stateset.com/graphql Webhooks: https://webhooks.sandbox.stateset.com # Test API keys Authorization: Bearer ${STATESET_API_KEY} ``` ### Test Data | Card Number | Scenario | Result | | --------------------- | ------------------ | ------------------------------ | | `4242 4242 4242 4242` | Successful payment | Always succeeds | | `4000 0000 0000 0002` | Card declined | Always fails | | `4000 0000 0000 9995` | Insufficient funds | Fails with insufficient\_funds | | `4000 0000 0000 0127` | Incorrect CVC | Fails CVC check | ```javascript theme={null} // Test order scenarios const testScenarios = { // Successful order success: { customer_email: 'test-success@example.com', items: [{sku: 'TEST-SUCCESS', quantity: 1}] }, // Inventory shortage out_of_stock: { customer_email: 'test-oos@example.com', items: [{sku: 'TEST-OOS', quantity: 1}] }, // Payment failure payment_fail: { customer_email: 'test-fail@example.com', payment: {test_mode: 'fail'} } }; ``` Use the webhook simulator to test your endpoint: ```bash theme={null} # Trigger test webhook curl -X POST https://api.sandbox.stateset.com/v1/webhooks/simulate \ -H "Authorization: Bearer sk_test_..." \ -d event_type="order.created" \ -d endpoint_url="https://your-app.com/webhooks" ``` ### Idempotency StateSet API supports idempotency for safely retrying requests without side effects: **Idempotency Keys:** * Valid for 24 hours after first request * Must be unique per API key * Recommended format: `{resource}-{uuid}` (e.g., `order-550e8400-e29b-41d4-a716`) ```bash theme={null} # Using idempotency for safe retries curl -X POST https://api.stateset.com/v1/orders \ -H "Idempotency-Key: order-550e8400-e29b-41d4-a716" \ -H "Authorization: Bearer sk_test_..." \ -d @order.json ``` ```javascript theme={null} // Node.js with automatic retry and idempotency const { v4: uuidv4 } = require('uuid'); async function createOrderSafely(orderData) { const idempotencyKey = `order-${uuidv4()}`; return await stateset.orders.create(orderData, { idempotencyKey, maxRetries: 3, retryDelay: 1000 }); } ``` ## API Limits & Quotas ### Request Limits by Plan | Plan | Requests/Min | Requests/Day | Burst Limit | Concurrent Connections | | -------------- | ------------ | ------------ | ----------- | ---------------------- | | **Free** | 60 | 1,000 | 100/sec | 10 | | **Starter** | 100 | 10,000 | 200/sec | 25 | | **Growth** | 1,000 | 100,000 | 1,000/sec | 100 | | **Scale** | 5,000 | 500,000 | 5,000/sec | 500 | | **Enterprise** | Custom | Unlimited | Custom | Unlimited | ### Resource Limits | Resource | Limit | Notes | | ----------------- | ----------- | ------------------------------------ | | Max request size | 10 MB | Increase available for Enterprise | | Max response size | 50 MB | Paginate for larger datasets | | Webhook timeout | 30 seconds | Retry up to 3 times | | File upload size | 100 MB | Direct upload to S3 for larger files | | Batch operations | 1,000 items | Use async jobs for larger batches | ## Support and Community Get help with integration issues Join our developer community Check API status and uptime ### Additional Resources * [API Changelog](/api-reference/changelog) - Latest updates and changes * [Postman Collection](https://www.postman.com/stateset/workspace/stateset-api) - Ready-to-use API collection * [OpenAPI Specification](/spec/openapi.yaml) - Machine-readable API spec * [Code Examples](https://github.com/stateset/examples) - Sample implementations *** Ready to get started? Check out our [5-minute quickstart guide](/quickstart) or explore the API reference sections below. # Adjust Inventory Source: https://docs.stateset.com/api-reference/inventory/adjust POST https://api.stateset.com/v1/inventory_items/:id/adjust This endpoint adjusts inventory levels for stock reconciliation, damage, or other reasons. ### Body The unique identifier of the inventory item to adjust The type of adjustment (e.g., "reconciliation", "damage", "theft", "expiration", "return", "manual") The quantity to adjust (positive for increase, negative for decrease) Detailed reason for the adjustment The warehouse where the adjustment is being made The specific location within the warehouse Reference number for tracking (e.g., count sheet number, incident report) The cost impact of this adjustment for accounting purposes ### Response The unique identifier of the adjustment record The inventory item that was adjusted The type of adjustment performed The quantity before adjustment The quantity after adjustment The actual quantity change applied The financial impact of this adjustment The user who performed the adjustment Timestamp when the adjustment was made Indicates whether the adjustment was successful ### Error Responses Error object containing details about what went wrong Error code (e.g., "insufficient\_stock", "invalid\_quantity", "warehouse\_not\_found") Human-readable error message Additional error details ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/inventory_items/:id/adjust' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "inventory_item_id": "inv_abc123", "adjustment_type": "reconciliation", "quantity_change": -5, "reason": "Physical count showed 5 less than system", "warehouse_id": "wh_east_01", "location_id": "loc_a1_shelf_3", "reference_number": "COUNT_2024_001", "cost_adjustment": -125.00 }' ``` ```graphQL GraphQL theme={null} mutation inventoryAdjustMutation { inventoryAdjust( inventoryItemId: "${inventoryItemId}", adjustmentType: "${adjustmentType}", quantityChange: ${quantityChange}, reason: "${reason}", warehouseId: "${warehouseId}", locationId: "${locationId}", referenceNumber: "${referenceNumber}", costAdjustment: ${costAdjustment} ) { adjustment { id quantity_before quantity_after quantity_change cost_impact } userErrors { field message } } } ``` ```js Node.js theme={null} const adjustment = await stateset.inventory.adjust({ inventory_item_id: 'inv_abc123', adjustment_type: 'reconciliation', quantity_change: -5, reason: 'Physical count showed 5 less than system', warehouse_id: 'wh_east_01', location_id: 'loc_a1_shelf_3', reference_number: 'COUNT_2024_001', cost_adjustment: -125.00 }); ``` ```python Python theme={null} adjustment = stateset.inventory.adjust({ 'inventory_item_id': 'inv_abc123', 'adjustment_type': 'reconciliation', 'quantity_change': -5, 'reason': 'Physical count showed 5 less than system', 'warehouse_id': 'wh_east_01', 'location_id': 'loc_a1_shelf_3', 'reference_number': 'COUNT_2024_001', 'cost_adjustment': -125.00 }) ``` ```ruby Ruby theme={null} adjustment = Stateset::Inventory.adjust({ inventory_item_id: 'inv_abc123', adjustment_type: 'reconciliation', quantity_change: -5, reason: 'Physical count showed 5 less than system', warehouse_id: 'wh_east_01', location_id: 'loc_a1_shelf_3', reference_number: 'COUNT_2024_001', cost_adjustment: -125.00 }) ``` ```go Go theme={null} adjustment, err := stateset.Inventory.adjust({ InventoryItemID: 'inv_abc123', AdjustmentType: 'reconciliation', QuantityChange: -5, Reason: 'Physical count showed 5 less than system', WarehouseID: 'wh_east_01', LocationID: 'loc_a1_shelf_3', ReferenceNumber: 'COUNT_2024_001', CostAdjustment: -125.00 }) ``` ```java Java theme={null} InventoryAdjustment adjustment = stateset.inventory.adjust({ inventoryItemId: 'inv_abc123', adjustmentType: 'reconciliation', quantityChange: -5, reason: 'Physical count showed 5 less than system', warehouseId: 'wh_east_01', locationId: 'loc_a1_shelf_3', referenceNumber: 'COUNT_2024_001', costAdjustment: -125.00 }); ``` ```php PHP theme={null} $adjustment = $stateset->inventory->adjust([ 'inventory_item_id' => 'inv_abc123', 'adjustment_type' => 'reconciliation', 'quantity_change' => -5, 'reason' => 'Physical count showed 5 less than system', 'warehouse_id' => 'wh_east_01', 'location_id' => 'loc_a1_shelf_3', 'reference_number' => 'COUNT_2024_001', 'cost_adjustment' => -125.00 ]); ``` ```csharp C# theme={null} var adjustment = await stateset.Inventory.Adjust(new { InventoryItemId = 'inv_abc123', AdjustmentType = 'reconciliation', QuantityChange = -5, Reason = 'Physical count showed 5 less than system', WarehouseId = 'wh_east_01', LocationId = 'loc_a1_shelf_3', ReferenceNumber = 'COUNT_2024_001', CostAdjustment = -125.00 }); ``` ```json Response theme={null} { "id": "adj_xyz789", "inventory_item_id": "inv_abc123", "adjustment_type": "reconciliation", "quantity_before": 100, "quantity_after": 95, "quantity_change": -5, "cost_impact": -125.00, "reason": "Physical count showed 5 less than system", "warehouse_id": "wh_east_01", "location_id": "loc_a1_shelf_3", "reference_number": "COUNT_2024_001", "adjusted_by": "user_123", "adjusted_at": "2024-01-15T14:30:00Z", "success": true } ``` ```json Error Response theme={null} { "error": { "code": "insufficient_stock", "message": "Cannot adjust inventory below zero. Current quantity: 3, requested change: -5", "details": { "current_quantity": 3, "requested_change": -5, "minimum_allowed": 0 } } } ``` # Inventory Analytics Source: https://docs.stateset.com/api-reference/inventory/analytics GET /api/v1/inventory/analytics Retrieve comprehensive analytics and insights about your inventory performance The Analytics API provides real-time insights into inventory performance, trends, and optimization opportunities. ## Query Parameters Type of analytics to retrieve: * `overview` - General inventory metrics * `turnover` - Inventory turnover analysis * `aging` - Stock aging report * `performance` - SKU performance metrics * `forecast_accuracy` - Forecast vs actual comparison Filter analytics for specific SKU Filter by specific location Start date for analytics period (ISO 8601) End date for analytics period (ISO 8601) Group results by: `sku`, `category`, `location`, `supplier` Include historical trend data. Default: false ## Response Type of analytics returned Analytics time period Start date (ISO 8601) End date (ISO 8601) Core metrics based on metric\_type Total inventory value Total units in stock Number of unique SKUs Average inventory turnover rate Percentage of SKUs out of stock Percentage of overstocked items Value of non-moving inventory Total inventory carrying cost Detailed breakdown by grouping Group identifier (SKU, category, etc.) Group name Group-specific metrics Units in stock Inventory value Turnover rate Days of supply on hand Movement velocity: `fast`, `medium`, `slow`, `non-moving` Historical trend data (if requested) Time series of inventory values Time series of turnover rates Historical stockout events AI-generated insights and recommendations Insight type: `opportunity`, `warning`, `recommendation` Severity level: `high`, `medium`, `low` Insight description List of affected SKUs Estimated savings if actioned ```bash cURL theme={null} curl -X GET "https://api.stateset.com/api/v1/inventory/analytics?metric_type=overview&include_trends=true" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript Node.js theme={null} const analytics = await stateset.inventory.analytics.get({ metric_type: 'overview', date_from: '2024-01-01', date_to: '2024-11-15', include_trends: true }); ``` ```python Python theme={null} analytics = stateset.inventory.analytics.get( metric_type='overview', date_from='2024-01-01', date_to='2024-11-15', include_trends=True ) ``` ```json Response theme={null} { "metric_type": "overview", "period": { "from": "2024-01-01T00:00:00Z", "to": "2024-11-15T23:59:59Z" }, "metrics": { "total_value": 485750.00, "total_units": 12500, "unique_skus": 256, "average_turnover": 8.5, "stockout_rate": 0.03, "overstock_rate": 0.12, "dead_stock_value": 15000.00, "carrying_cost": 121437.50 }, "breakdown": [ { "group": "Electronics", "name": "Electronics Category", "metrics": { "units": 3500, "value": 175000.00, "turnover_rate": 12.5, "days_of_supply": 29.2, "velocity": "fast" } }, { "group": "Accessories", "name": "Accessories Category", "metrics": { "units": 5000, "value": 75000.00, "turnover_rate": 6.0, "days_of_supply": 60.8, "velocity": "medium" } } ], "trends": { "inventory_value": [ { "date": "2024-01-01", "value": 450000 }, { "date": "2024-02-01", "value": 465000 }, { "date": "2024-03-01", "value": 478000 } ], "turnover_rate": [ { "date": "2024-01-01", "rate": 7.5 }, { "date": "2024-02-01", "rate": 8.0 }, { "date": "2024-03-01", "rate": 8.5 } ] }, "insights": [ { "type": "opportunity", "severity": "high", "message": "15 SKUs have been non-moving for 180+ days", "affected_items": ["OLD-001", "OLD-002", "OLD-003"], "potential_savings": 15000.00 }, { "type": "warning", "severity": "medium", "message": "Electronics category showing 25% increase in stockouts", "affected_items": ["ELEC-101", "ELEC-102"], "potential_savings": 5000.00 }, { "type": "recommendation", "severity": "low", "message": "Consider implementing ABC classification for better control", "affected_items": [], "potential_savings": 8000.00 } ] } ``` ## Metric Types ### Overview Analytics General inventory health metrics and KPIs. ```javascript theme={null} const overview = await stateset.inventory.analytics.get({ metric_type: 'overview', group_by: 'category' }); ``` ### Turnover Analysis Detailed inventory turnover rates and velocity metrics. ```javascript theme={null} const turnover = await stateset.inventory.analytics.get({ metric_type: 'turnover', group_by: 'sku', date_from: '2024-01-01' }); ``` ### Aging Report Analysis of stock age and identification of slow-moving items. ```javascript theme={null} const aging = await stateset.inventory.analytics.get({ metric_type: 'aging', location_id: 'loc_warehouse_001' }); ``` ### Performance Metrics SKU-level performance including sales velocity and profitability. ```javascript theme={null} const performance = await stateset.inventory.analytics.get({ metric_type: 'performance', sku: 'WIDGET-001', include_trends: true }); ``` ### Forecast Accuracy Compare forecasted demand with actual sales to improve planning. ```javascript theme={null} const accuracy = await stateset.inventory.analytics.get({ metric_type: 'forecast_accuracy', date_from: '2024-06-01', date_to: '2024-11-01' }); ``` ## Exporting Analytics Export analytics data in various formats: ```javascript theme={null} // Export as CSV const csvExport = await stateset.inventory.analytics.export({ metric_type: 'overview', format: 'csv' }); // Export as PDF report const pdfReport = await stateset.inventory.analytics.export({ metric_type: 'performance', format: 'pdf', include_charts: true }); ``` ## Scheduling Reports Set up automated analytics reports: ```javascript theme={null} const schedule = await stateset.inventory.analytics.schedule({ name: 'Weekly Inventory Report', metric_type: 'overview', frequency: 'weekly', recipients: ['ops@company.com'], format: 'pdf' }); ``` ## Related Endpoints * [Inventory Planning](/api-reference/inventory/planning) - Generate inventory plans * [List Inventory](/api-reference/inventory/get) - View current inventory * [Inventory Webhooks](/api-reference/webhooks/inventory) - Real-time inventory events # Batch Operations Source: https://docs.stateset.com/api-reference/inventory/batch POST /api/v1/inventory/batch Perform bulk inventory operations for efficient management at scale Batch operations allow you to update multiple inventory items in a single API call, significantly improving performance for large-scale operations. ## Request Body Type of batch operation: * `update` - Update multiple items * `adjust` - Bulk quantity adjustments * `transfer` - Multi-item transfers * `cycle_count` - Batch cycle counting * `import` - Import inventory data Array of items to process (max 1000 per request) SKU of the inventory item Operation-specific data (varies by operation type) Batch operation options Validate without executing. Default: false Continue processing on errors. Default: false Email for completion notification ## Response Unique identifier for this batch operation Batch status: `processing`, `completed`, `failed`, `partial` Operation summary Total items in batch Successfully processed items Failed items Skipped items Individual item results Item SKU Item status: `success`, `error`, `skipped` Status message or error details Operation result data ```bash cURL theme={null} curl -X POST https://api.stateset.com/api/v1/inventory/batch \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operation": "adjust", "items": [ { "sku": "WIDGET-001", "data": { "adjustment_type": "absolute", "quantity": 150, "reason": "Cycle count correction" } }, { "sku": "GADGET-002", "data": { "adjustment_type": "relative", "quantity": -25, "reason": "Damaged goods" } } ], "options": { "continue_on_error": true } }' ``` ```javascript Node.js theme={null} const batchResult = await stateset.inventory.batch.create({ operation: 'adjust', items: [ { sku: 'WIDGET-001', data: { adjustment_type: 'absolute', quantity: 150, reason: 'Cycle count correction' } }, { sku: 'GADGET-002', data: { adjustment_type: 'relative', quantity: -25, reason: 'Damaged goods' } } ], options: { continue_on_error: true } }); ``` ```python Python theme={null} batch_result = stateset.inventory.batch.create( operation='adjust', items=[ { 'sku': 'WIDGET-001', 'data': { 'adjustment_type': 'absolute', 'quantity': 150, 'reason': 'Cycle count correction' } }, { 'sku': 'GADGET-002', 'data': { 'adjustment_type': 'relative', 'quantity': -25, 'reason': 'Damaged goods' } } ], options={ 'continue_on_error': True } ) ``` ```json Response theme={null} { "batch_id": "batch_1a2b3c4d5e", "status": "completed", "summary": { "total_items": 2, "processed": 2, "failed": 0, "skipped": 0 }, "results": [ { "sku": "WIDGET-001", "status": "success", "message": "Inventory adjusted successfully", "data": { "previous_quantity": 125, "new_quantity": 150, "adjustment": 25 } }, { "sku": "GADGET-002", "status": "success", "message": "Inventory adjusted successfully", "data": { "previous_quantity": 200, "new_quantity": 175, "adjustment": -25 } } ] } ``` ## Operation Types ### Bulk Update Update multiple inventory item properties at once. ```javascript theme={null} const updates = await stateset.inventory.batch.create({ operation: 'update', items: [ { sku: 'WIDGET-001', data: { reorder_point: 100, price: 29.99, category: 'Electronics' } }, { sku: 'WIDGET-002', data: { reorder_point: 150, price: 34.99, category: 'Electronics' } } ] }); ``` ### Bulk Adjust Adjust quantities for multiple items simultaneously. ```javascript theme={null} const adjustments = await stateset.inventory.batch.create({ operation: 'adjust', items: cycleCountResults.map(result => ({ sku: result.sku, data: { adjustment_type: 'absolute', quantity: result.counted_quantity, reason: 'Monthly cycle count', reference: `CC-${Date.now()}` } })) }); ``` ### Bulk Transfer Transfer multiple items between locations. ```javascript theme={null} const transfers = await stateset.inventory.batch.create({ operation: 'transfer', items: [ { sku: 'WIDGET-001', data: { from_location: 'warehouse_001', to_location: 'warehouse_002', quantity: 50 } }, { sku: 'GADGET-002', data: { from_location: 'warehouse_001', to_location: 'warehouse_002', quantity: 100 } } ] }); ``` ### Import Inventory Import inventory data from external systems. ```javascript theme={null} const importResult = await stateset.inventory.batch.create({ operation: 'import', items: csvData.map(row => ({ sku: row.sku, data: { name: row.product_name, description: row.description, quantity: parseInt(row.quantity), price: parseFloat(row.price), cost: parseFloat(row.cost), location_id: row.warehouse, category: row.category, reorder_point: parseInt(row.reorder_point) } })), options: { validate_only: true // Test import first } }); ``` ## Async Operations For large batches, operations are processed asynchronously: ```javascript theme={null} // Start batch operation const batch = await stateset.inventory.batch.create({ operation: 'update', items: largeItemArray, // 10,000+ items options: { notification_email: 'ops@company.com' } }); // Check status const status = await stateset.inventory.batch.get(batch.batch_id); // Poll for completion const checkStatus = async () => { const current = await stateset.inventory.batch.get(batch.batch_id); if (current.status === 'completed') { console.log('Batch completed:', current.summary); } else if (current.status === 'failed') { console.error('Batch failed:', current.error); } else { // Still processing setTimeout(checkStatus, 5000); // Check again in 5 seconds } }; ``` ## Error Handling Handle batch operation errors gracefully: ```javascript theme={null} try { const batch = await stateset.inventory.batch.create({ operation: 'adjust', items: adjustmentItems, options: { continue_on_error: false // Stop on first error } }); // Check for partial failures const failedItems = batch.results.filter(r => r.status === 'error'); if (failedItems.length > 0) { console.log('Failed items:', failedItems); // Retry failed items const retryBatch = await stateset.inventory.batch.create({ operation: 'adjust', items: failedItems.map(item => ({ sku: item.sku, data: adjustmentItems.find(a => a.sku === item.sku).data })) }); } } catch (error) { console.error('Batch operation failed:', error); } ``` ## Performance Tips * Batch operations can process up to 1,000 items per request * For larger datasets, use async operations * Group similar operations together * Use `validate_only` to test before executing * Monitor rate limits for optimal throughput ## Related Endpoints * [Inventory Planning](/api-reference/inventory/planning) - Plan inventory levels * [Inventory Analytics](/api-reference/inventory/analytics) - Analyze inventory data * [Adjust Inventory](/api-reference/inventory/adjust) - Single item adjustments * [Transfer Inventory](/api-reference/inventory/transfer) - Single item transfers # Create Inventory Source: https://docs.stateset.com/api-reference/inventory/create POST https://api.stateset.com/v1/inventory_items This endpoint creates a new inventory item ### Body This is the ID of the inventory item. This is the SKU of the inventory item. This is the UPC of the inventory item. This is the description of the inventory item. This is the size of the inventory item. This is the color of the inventory item. This is the incoming quantity of the inventory item. This is the available quantity of the inventory item. This is the warehouse ID of the inventory item. This is the arrival date of the inventory item. This is the delivery date of the inventory item. This is the purchase order ID of the inventory item. This is the created date of the inventory item. This is the updated date of the inventory item. ### Response This is the ID of the inventory item. This is the SKU of the inventory item. This is the UPC of the inventory item. This is the description of the inventory item. This is the size of the inventory item. This is the color of the inventory item. This is the incoming quantity of the inventory item. This is the available quantity of the inventory item. This is the warehouse ID of the inventory item. This is the arrival date of the inventory item. This is the delivery date of the inventory item. This is the purchase order ID of the inventory item. This is the created date of the inventory item. This is the updated date of the inventory item. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/inventory_items' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```graphQL GraphQL theme={null} mutation InsertNewInventoryItem( $inventory_item: inventory_items_insert_input! ) { insert_inventory_items ( objects: [$inventory_item] ) { returning { id sku upc description size color incoming available warehouse arrivalDate deliveryDate } } } ``` ```javascript Node.js theme={null} var created = await stateset.inventoryItems.create({ sku: "SKU-123", upc: "UPC-123", description: "This is a description", size: "Large", color: "Red", incoming: 10, available: 10, warehouse: 1, arrivalDate: "2021-01-01", deliveryDate: "2021-01-01", }); ``` ```python Python theme={null} created = stateset.inventory_items.create( sku="SKU-123", upc="UPC-123", description="This is a description", size="Large", color="Red", incoming=10, available=10, warehouse=1, arrivalDate="2021-01-01", deliveryDate="2021-01-01", ) ``` ```ruby Ruby theme={null} created = Stateset::InventoryItem.create( sku: "SKU-123", upc: "UPC-123", description: "This is a description", size: "Large", color: "Red", incoming: 10, available: 10, warehouse: 1, arrivalDate: "2021-01-01", deliveryDate: "2021-01-01", ) ``` ```php PHP theme={null} $created = $stateset->inventoryItems->create( array( "sku" => "SKU-123", "upc" => "UPC-123", "description" => "This is a description", "size" => "Large", "color" => "Red", "incoming" => 10, "available" => 10, "warehouse" => 1, "arrivalDate" => "2021-01-01", "deliveryDate" => "2021-01-01", ) ); ``` ```go Go theme={null} created, err := stateset.InventoryItems.Create( "SKU-123", "UPC-123", "This is a description", "Large", "Red", 10, 10, 1, "2021-01-01", "2021-01-01", ) ``` ```java Java theme={null} InventoryItem created = stateset.inventoryItems.create( "SKU-123", "UPC-123", "This is a description", "Large", "Red", 10, 10, 1, "2021-01-01", "2021-01-01", ); ``` ```json Response theme={null} { "inventory_items": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "SKU-123", "description": "This is a description", "size": "Large", "incoming": 10, "color": "Red", "warehouse": 1, "available": 10, "arriving": "2021-01-01", "purchase_order_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, ] } ``` # Delete Inventory Item Source: https://docs.stateset.com/api-reference/inventory/delete DELETE https://api.return.com/v1/inventory_items/:id This endpoint deletes an existing inventory item. ### Body The ID of the inventory item to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/inventory_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "ii_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteInventoryItem ($inventory_item_id: String) { delete_inventory_item(where: {id: {_eq: $inventory_item_id}}) { affected_rows } } ``` ```javascript Node.js theme={null} const deleted = await stateset.inventoryItems.del( 'ii_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} deleted = stateset.inventory_items.del( 'ii_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} deleted = Stateset::InventoryItems.del( 'ii_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $deleted = $stateset->inventoryItems->del( 'ii_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} deleted, err := stateset.InventoryItems.Del( "ii_ODkRWQtx9NVsRX" ) ``` ```java Java theme={null} InventoryItem deleted = stateset.inventoryItems.del( "ii_ODkRWQtx9NVsRX" ); ``` ```json Response theme={null} { "id": "ii_1NXWPnCo6bFb1KQto6C8OWvE", "object": "inventory_item", "deleted": true } ``` # Get Inventory Item Source: https://docs.stateset.com/api-reference/inventory/get GET https://api.stateset.com/v1/inventory_items/:id This endpoint gets or creates a new inventory item. ### Body This is the unique identifier for the inventory item. ### Response This is the unique identifier for the inventory item. This is the stock keeping unit (SKU) for the inventory item. This is the description for the inventory item. This is the size for the inventory item. This is the number of items incoming for the inventory item. This is the color for the inventory item. This is the identifier for the warehouse for the inventory item. This is the number of items available for the inventory item. This is the date when the items are expected to arrive for the inventory item. This is the identifier for the purchase order associated with the inventory item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/inventory_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", }' ``` ```graphQL GraphQL theme={null} query { inventory_item { id sku upc description size color incoming available warehouse arrivalDate deliveryDate } } ``` ```javascript Node.js theme={null} var inventoryItems = await stateset.inventoryItems.retreive({ id: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }); ``` ```python Python theme={null} inventoryItems = stateset.inventoryItems.retreive({ id: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }) ``` ```ruby Ruby theme={null} inventoryItems = Stateset::InventoryItems.retreive({ id: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }) ``` ```php PHP theme={null} $inventoryItems = $stateset->inventoryItems->retreive([ "id" => "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ]); ``` ```go Go theme={null} inventoryItems, err := stateset.InventoryItems.Retreive( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ) ``` ```java Java theme={null} InventoryItems inventoryItems = stateset.inventoryItems.retreive( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ); ``` ```json Response theme={null} { "inventory_item": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "SKU-123", "description": "This is a description", "size": "Large", "incoming": 10, "color": "Red", "warehouse": 1, "available": 10, "arriving": "2021-01-01", "purchase_order_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, ] } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Inventory item not found", "details": { "resource": "inventory_item", "id": "inv_abc123" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` ### Inventory Item | Name | Type | Description | | ------------------- | -------------------------- | ----------------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the entry | | sku | Text (Nullable) | Stock Keeping Unit (SKU) for the entry | | description | Text (Nullable) | Description or additional details about the entry | | size | Text (Nullable) | Size of the item | | incoming | Integer (Nullable) | Number of items incoming | | color | Text (Nullable) | Color of the item | | warehouse | Integer (Nullable) | Identifier for the warehouse | | available | Integer (Nullable) | Number of items available | | arriving | Date (Nullable) | Date when the items are expected to arrive | | purchase\_order\_id | Text (Nullable) | Identifier for the purchase order associated with the entry | # Inventory Planning Source: https://docs.stateset.com/api-reference/inventory/planning POST /api/v1/inventory/planning Generate intelligent inventory planning recommendations based on demand forecasting and optimization algorithms The Inventory Planning API uses machine learning to forecast demand and optimize stock levels across your inventory. ## Request Body Type of planning to generate. Options: * `demand_forecast` - Predict future demand * `reorder_optimization` - Calculate optimal reorder points * `seasonal_planning` - Plan for seasonal variations * `abc_analysis` - Categorize inventory by value/velocity Specific SKU to plan for. If omitted, plans all inventory items. Location ID for location-specific planning Planning time horizon Number of time units Time unit: `days`, `weeks`, `months`, `quarters` Planning-specific parameters Target service level (0-1). Default: 0.95 Supplier lead time in days Annual holding cost as percentage of item value Fixed cost per order Include seasonal patterns in forecast. Default: true ## Response Unique identifier for this planning run Type of planning performed ISO 8601 timestamp of when the plan was generated Array of planning results per inventory item SKU of the inventory item Name of the inventory item Current available stock level Demand forecast details Predicted demand for the time horizon 95% confidence interval Lower bound of prediction Upper bound of prediction Demand trend: `increasing`, `decreasing`, `stable` Current seasonal adjustment factor Planning recommendations Recommended reorder point Recommended safety stock level Optimal order quantity (EOQ) Maximum recommended stock level Recommended date for next order Recommended quantity for next order Performance metrics Annual inventory turnover rate Probability of stockout (0-1) Estimated annual carrying cost ABC classification: `A`, `B`, or `C` Overall planning summary Number of items planned Total inventory value Items currently below reorder point List of SKUs requiring immediate reorder Estimated annual savings from optimization ```bash cURL theme={null} curl -X POST https://api.stateset.com/api/v1/inventory/planning \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "planning_type": "demand_forecast", "time_horizon": { "value": 3, "unit": "months" }, "parameters": { "service_level": 0.95, "include_seasonality": true } }' ``` ```javascript Node.js theme={null} const planning = await stateset.inventory.planning.create({ planning_type: 'demand_forecast', time_horizon: { value: 3, unit: 'months' }, parameters: { service_level: 0.95, include_seasonality: true } }); ``` ```python Python theme={null} planning = stateset.inventory.planning.create( planning_type='demand_forecast', time_horizon={ 'value': 3, 'unit': 'months' }, parameters={ 'service_level': 0.95, 'include_seasonality': True } ) ``` ```json Response theme={null} { "planning_id": "plan_1a2b3c4d5e", "planning_type": "demand_forecast", "generated_at": "2024-11-15T10:30:00Z", "items": [ { "sku": "WIDGET-001", "item_name": "Premium Widget", "current_stock": 150, "forecast": { "predicted_demand": 450, "confidence_interval": { "lower": 380, "upper": 520 }, "trend": "increasing", "seasonality_factor": 1.2 }, "recommendations": { "reorder_point": 200, "safety_stock": 50, "economic_order_quantity": 300, "max_stock_level": 500, "next_order_date": "2024-11-20", "next_order_quantity": 300 }, "metrics": { "turnover_rate": 12.5, "stockout_risk": 0.02, "carrying_cost": 1250.00, "abc_category": "A" } }, { "sku": "GADGET-002", "item_name": "Standard Gadget", "current_stock": 75, "forecast": { "predicted_demand": 180, "confidence_interval": { "lower": 150, "upper": 210 }, "trend": "stable", "seasonality_factor": 1.0 }, "recommendations": { "reorder_point": 80, "safety_stock": 20, "economic_order_quantity": 150, "max_stock_level": 250, "next_order_date": "2024-11-18", "next_order_quantity": 150 }, "metrics": { "turnover_rate": 8.0, "stockout_risk": 0.05, "carrying_cost": 450.00, "abc_category": "B" } } ], "summary": { "total_items": 2, "total_value": 15750.00, "items_below_reorder": 1, "urgent_orders": ["GADGET-002"], "optimization_savings": 2500.00 } } ``` ## Planning Types ### Demand Forecast Predicts future demand using historical sales data and machine learning algorithms. ```javascript theme={null} const forecast = await stateset.inventory.planning.create({ planning_type: 'demand_forecast', sku: 'WIDGET-001', time_horizon: { value: 6, unit: 'months' }, parameters: { include_seasonality: true, service_level: 0.98 } }); ``` ### Reorder Optimization Calculates optimal reorder points and quantities based on demand patterns and costs. ```javascript theme={null} const reorderPlan = await stateset.inventory.planning.create({ planning_type: 'reorder_optimization', parameters: { holding_cost_rate: 0.25, ordering_cost: 50, lead_time_days: 14 } }); ``` ### Seasonal Planning Plans inventory levels for seasonal demand variations. ```javascript theme={null} const seasonalPlan = await stateset.inventory.planning.create({ planning_type: 'seasonal_planning', time_horizon: { value: 1, unit: 'quarters' }, parameters: { service_level: 0.95 } }); ``` ### ABC Analysis Categorizes inventory based on value and velocity for prioritized management. ```javascript theme={null} const abcAnalysis = await stateset.inventory.planning.create({ planning_type: 'abc_analysis', location_id: 'loc_warehouse_001' }); ``` ## Error Handling Planning operations may fail if: * Insufficient historical data (less than 30 days) * Invalid parameters or constraints * SKU not found * Location not authorized ```javascript theme={null} try { const planning = await stateset.inventory.planning.create({ planning_type: 'demand_forecast', sku: 'INVALID-SKU' }); } catch (error) { if (error.code === 'sku_not_found') { console.error('SKU does not exist'); } else if (error.code === 'insufficient_data') { console.error('Not enough historical data for forecast'); } } ``` ## Webhooks Subscribe to planning events to automate your inventory workflows: * `inventory.planning.completed` - Planning run completed * `inventory.reorder.required` - Item below reorder point * `inventory.stockout.predicted` - Stockout risk detected ## Related Endpoints * [Create Inventory Item](/api-reference/inventory/create) - Add items to inventory * [Adjust Inventory](/api-reference/inventory/adjust) - Make stock adjustments * [Transfer Inventory](/api-reference/inventory/transfer) - Move stock between locations * [Get Inventory Analytics](/api-reference/inventory/analytics) - View inventory metrics # Transfer Inventory Source: https://docs.stateset.com/api-reference/inventory/transfer POST https://api.stateset.com/v1/inventory_items/:id/transfer This endpoint transfers inventory between warehouses or locations. ### Body The unique identifier of the inventory item to transfer The quantity to transfer The source warehouse ID The source location within the warehouse The destination warehouse ID The destination location within the warehouse The reason for the transfer (e.g., "rebalancing", "fulfillment", "returns\_processing") Transfer priority (e.g., "standard", "expedited", "urgent") Expected arrival date at destination ### Response The unique identifier of the transfer record The system-generated transfer number for tracking The inventory item being transferred The quantity being transferred Source warehouse details Warehouse ID Warehouse name Location within warehouse Destination warehouse details Warehouse ID Warehouse name Location within warehouse Transfer status (e.g., "pending", "in\_transit", "completed", "cancelled") Timestamp when the transfer was created Indicates whether the transfer was initiated successfully ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/inventory_items/:id/transfer' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "inventory_item_id": "inv_abc123", "quantity": 50, "from_warehouse_id": "wh_east_01", "from_location_id": "loc_a1_shelf_3", "to_warehouse_id": "wh_west_01", "to_location_id": "loc_b2_shelf_1", "transfer_reason": "rebalancing", "priority": "standard", "expected_arrival": "2024-01-20" }' ``` ```graphQL GraphQL theme={null} mutation inventoryTransferMutation { inventoryTransfer( inventoryItemId: "${inventoryItemId}", quantity: ${quantity}, fromWarehouseId: "${fromWarehouseId}", fromLocationId: "${fromLocationId}", toWarehouseId: "${toWarehouseId}", toLocationId: "${toLocationId}", transferReason: "${transferReason}", priority: "${priority}", expectedArrival: "${expectedArrival}" ) { transfer { id transfer_number quantity status from_warehouse { id name } to_warehouse { id name } } userErrors { field message } } } ``` ```js Node.js theme={null} const transfer = await stateset.inventory.transfer({ inventory_item_id: 'inv_abc123', quantity: 50, from_warehouse_id: 'wh_east_01', from_location_id: 'loc_a1_shelf_3', to_warehouse_id: 'wh_west_01', to_location_id: 'loc_b2_shelf_1', transfer_reason: 'rebalancing', priority: 'standard', expected_arrival: '2024-01-20' }); ``` ```python Python theme={null} transfer = stateset.inventory.transfer({ 'inventory_item_id': 'inv_abc123', 'quantity': 50, 'from_warehouse_id': 'wh_east_01', 'from_location_id': 'loc_a1_shelf_3', 'to_warehouse_id': 'wh_west_01', 'to_location_id': 'loc_b2_shelf_1', 'transfer_reason': 'rebalancing', 'priority': 'standard', 'expected_arrival': '2024-01-20' }) ``` ```ruby Ruby theme={null} transfer = Stateset::Inventory.transfer({ inventory_item_id: 'inv_abc123', quantity: 50, from_warehouse_id: 'wh_east_01', from_location_id: 'loc_a1_shelf_3', to_warehouse_id: 'wh_west_01', to_location_id: 'loc_b2_shelf_1', transfer_reason: 'rebalancing', priority: 'standard', expected_arrival: '2024-01-20' }) ``` ```go Go theme={null} transfer, err := stateset.Inventory.transfer({ InventoryItemID: 'inv_abc123', Quantity: 50, FromWarehouseID: 'wh_east_01', FromLocationID: 'loc_a1_shelf_3', ToWarehouseID: 'wh_west_01', ToLocationID: 'loc_b2_shelf_1', TransferReason: 'rebalancing', Priority: 'standard', ExpectedArrival: '2024-01-20' }) ``` ```java Java theme={null} InventoryTransfer transfer = stateset.inventory.transfer({ inventoryItemId: 'inv_abc123', quantity: 50, fromWarehouseId: 'wh_east_01', fromLocationId: 'loc_a1_shelf_3', toWarehouseId: 'wh_west_01', toLocationId: 'loc_b2_shelf_1', transferReason: 'rebalancing', priority: 'standard', expectedArrival: '2024-01-20' }); ``` ```php PHP theme={null} $transfer = $stateset->inventory->transfer([ 'inventory_item_id' => 'inv_abc123', 'quantity' => 50, 'from_warehouse_id' => 'wh_east_01', 'from_location_id' => 'loc_a1_shelf_3', 'to_warehouse_id' => 'wh_west_01', 'to_location_id' => 'loc_b2_shelf_1', 'transfer_reason' => 'rebalancing', 'priority' => 'standard', 'expected_arrival' => '2024-01-20' ]); ``` ```csharp C# theme={null} var transfer = await stateset.Inventory.Transfer(new { InventoryItemId = 'inv_abc123', Quantity = 50, FromWarehouseId = 'wh_east_01', FromLocationId = 'loc_a1_shelf_3', ToWarehouseId = 'wh_west_01', ToLocationId = 'loc_b2_shelf_1', TransferReason = 'rebalancing', Priority = 'standard', ExpectedArrival = '2024-01-20' }); ``` ```json Response theme={null} { "id": "trans_xyz456", "transfer_number": "TRF-2024-0001", "inventory_item_id": "inv_abc123", "quantity": 50, "from_warehouse": { "id": "wh_east_01", "name": "East Coast Warehouse", "location_id": "loc_a1_shelf_3" }, "to_warehouse": { "id": "wh_west_01", "name": "West Coast Warehouse", "location_id": "loc_b2_shelf_1" }, "transfer_reason": "rebalancing", "priority": "standard", "status": "in_transit", "expected_arrival": "2024-01-20", "created_at": "2024-01-15T10:00:00Z", "created_by": "user_123", "success": true } ``` ```json Error Response theme={null} { "error": { "code": "insufficient_inventory", "message": "Not enough inventory available for transfer. Available: 30, Requested: 50", "details": { "available_quantity": 30, "requested_quantity": 50, "warehouse_id": "wh_east_01" } } } ``` # Update Inventory Item Source: https://docs.stateset.com/api-reference/inventory/update PUT https://api.stateset.com/v1/inventory_items/:id This endpoint updates an existing inventory item. ### Body This is the unique identifier for the inventory item. This is the stock keeping unit (SKU) for the inventory item. This is the description for the inventory item. This is the size for the inventory item. This is the number of items incoming for the inventory item. This is the color for the inventory item. This is the identifier for the warehouse for the inventory item. This is the number of items available for the inventory item. This is the date when the items are expected to arrive for the inventory item. This is the identifier for the purchase order associated with the inventory item. ### Response This is the unique identifier for the inventory item. This is the stock keeping unit (SKU) for the inventory item. This is the description for the inventory item. This is the size for the inventory item. This is the number of items incoming for the inventory item. This is the color for the inventory item. This is the identifier for the warehouse for the inventory item. This is the number of items available for the inventory item. This is the date when the items are expected to arrive for the inventory item. This is the identifier for the purchase order associated with the inventory item. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/inventory_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation: gql` mutation ( $id: String $inventory_item: inventory_item_set_input! ) { update_inventory_item ( where: { id : { _eq: $id }} _set: $inventory_item ) { returning { id sku upc description size color incoming warehouse available } } } ``` ```javascript Node.js theme={null} var updated = await stateset.inventoryItem.update({ id: "example_1", inventory_item: { name: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", } }) ``` ```python Python theme={null} updated = stateset.inventory_item.modify( id="example_1", inventory_item={ "name": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", } ) ``` ```ruby Ruby theme={null} updated = Stateset::InventoryItem.update( id: "example_1", inventory_item: { name: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", } ) ``` ```php PHP theme={null} $updated = $stateset->inventoryItem->update([ "id" => "example_1", "inventory_item" => [ "name" => "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", ] ]); ``` ```go Golang theme={null} inventory_item := stateset.InventoryItem{ Name: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", } updated, err := stateset.InventoryItem.Update( "example_1", inventory_item, ) ``` ```java Java theme={null} InventoryItem inventory_item = new InventoryItem(); inventory_item.setName("0901f083-aa1c-43c5-af5c-0a9d2fc64e30"); InventoryItem updated = stateset.inventoryItem.update( "example_1", inventory_item ); ``` ```json Response theme={null} { "inventory_items": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "SKU-123", "description": "This is a description", "size": "Large", "incoming": 10, "color": "Red", "warehouse": 1, "available": 10, "arriving": "2021-01-01", "purchase_order_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, ] } ``` # Create Invoice Source: https://docs.stateset.com/api-reference/invoices/create POST https://api.stateset.com/v1/invoices Create an invoice for billing customers This endpoint creates a new invoice for billing customers. Invoices can be sent immediately or scheduled for future delivery. ## Authentication This endpoint requires a valid API key with `invoices:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Customer ID to bill Custom invoice number (auto-generated if not provided) Invoice issue date (ISO 8601) Payment due date (ISO 8601) ISO 4217 currency code Invoice line items Item description Quantity Unit price in cents Associated product ID Tax rate as decimal (e.g., 0.08 for 8%) Discount rate as decimal Accounting code Billing address Street address Apartment/Suite City State/Province Postal code Country code Payment terms (e.g., "Net 30", "Due on receipt") Invoice notes or memo Whether to email invoice to customer (default: false) Additional custom fields ### Response Returns the created invoice. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/invoices' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "customer_id": "cust_abc123", "issue_date": "2024-01-19", "due_date": "2024-02-18", "currency": "USD", "line_items": [ { "description": "Professional Services - January 2024", "quantity": 40, "unit_price": 15000, "tax_rate": 0.08 }, { "description": "Software License", "quantity": 5, "unit_price": 9900, "product_id": "prod_xyz789" } ], "payment_terms": "Net 30", "send_email": true }' ``` ```javascript Node.js theme={null} const invoice = await stateset.invoices.create({ customer_id: "cust_abc123", issue_date: "2024-01-19", due_date: "2024-02-18", currency: "USD", line_items: [ { description: "Professional Services - January 2024", quantity: 40, unit_price: 15000, tax_rate: 0.08 }, { description: "Software License", quantity: 5, unit_price: 9900, product_id: "prod_xyz789" } ], payment_terms: "Net 30", send_email: true }); ``` ```json Response theme={null} { "id": "inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "invoice", "invoice_number": "INV-2024-0001", "status": "sent", "customer_id": "cust_abc123", "issue_date": "2024-01-19", "due_date": "2024-02-18", "currency": "USD", "subtotal": 649500, "tax_amount": 48000, "total_amount": 697500, "amount_due": 697500, "amount_paid": 0, "line_items": [ { "id": "li_123456", "description": "Professional Services - January 2024", "quantity": 40, "unit_price": 15000, "amount": 600000, "tax_rate": 0.08, "tax_amount": 48000 }, { "id": "li_123457", "description": "Software License", "quantity": 5, "unit_price": 9900, "amount": 49500, "product_id": "prod_xyz789", "tax_rate": 0, "tax_amount": 0 } ], "payment_terms": "Net 30", "created_at": "2024-01-19T10:00:00Z", "sent_at": "2024-01-19T10:01:00Z", "pdf_url": "https://invoices.stateset.com/inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30.pdf" } ``` # Get Invoice Source: https://docs.stateset.com/api-reference/invoices/get GET https://api.stateset.com/v1/invoices/:id Retrieve a specific invoice by ID This endpoint retrieves detailed information about a specific invoice including line items, payments, and status. ## Authentication This endpoint requires a valid API key with `invoices:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the invoice ## Query Parameters Expand related objects. Options: "customer", "payments", "credit\_notes", "events" ### Response Unique invoice identifier Object type, always "invoice" Human-readable invoice number Invoice status: "draft", "sent", "viewed", "partially\_paid", "paid", "overdue", "voided" Total invoice amount in cents Outstanding amount in cents Array of invoice line items ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/invoices/inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const invoice = await stateset.invoices.retrieve( 'inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} invoice = stateset.invoices.retrieve( 'inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "invoice", "invoice_number": "INV-2024-0001", "status": "sent", "customer_id": "cust_abc123", "customer": { "id": "cust_abc123", "name": "Acme Corporation", "email": "billing@acme.com" }, "issue_date": "2024-01-19", "due_date": "2024-02-18", "currency": "USD", "subtotal": 649500, "tax_amount": 48000, "discount_amount": 0, "total_amount": 697500, "amount_paid": 0, "amount_due": 697500, "line_items": [ { "id": "li_123456", "description": "Professional Services - January 2024", "quantity": 40, "unit_price": 15000, "amount": 600000, "tax_rate": 0.08, "tax_amount": 48000, "account_code": "4000" }, { "id": "li_123457", "description": "Software License", "quantity": 5, "unit_price": 9900, "amount": 49500, "product_id": "prod_xyz789", "tax_rate": 0, "tax_amount": 0, "account_code": "4100" } ], "billing_address": { "line1": "123 Business St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "payment_terms": "Net 30", "notes": "Thank you for your business!", "created_at": "2024-01-19T10:00:00Z", "sent_at": "2024-01-19T10:01:00Z", "viewed_at": "2024-01-19T14:30:00Z", "pdf_url": "https://invoices.stateset.com/inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30.pdf", "public_url": "https://pay.stateset.com/inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "metadata": { "po_number": "PO-12345", "project_code": "PROJ-2024-001" } } ``` # List Invoices Source: https://docs.stateset.com/api-reference/invoices/list GET https://api.stateset.com/v1/invoices List all invoices with filtering and pagination This endpoint retrieves a paginated list of invoices. Use filters to narrow results by status, customer, date range, and more. ## Authentication This endpoint requires a valid API key with `invoices:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of items to return (default: 20, max: 100) Cursor for pagination (invoice ID) Filter by status: "draft", "sent", "viewed", "partially\_paid", "paid", "overdue", "voided" Filter by customer ID Filter by issue date start (YYYY-MM-DD) Filter by issue date end (YYYY-MM-DD) Filter by due date start (YYYY-MM-DD) Filter by due date end (YYYY-MM-DD) Show only overdue invoices Sort field: "created\_at", "issue\_date", "due\_date", "total\_amount" Sort order: "asc" or "desc" (default: "desc") ### Response Object type, always "list" Array of invoice objects Whether more items exist ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/invoices?status=sent&limit=10' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const invoices = await stateset.invoices.list({ status: 'sent', limit: 10, overdue_only: false }); ``` ```python Python theme={null} invoices = stateset.invoices.list( status='sent', limit=10, overdue_only=False ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "invoice", "invoice_number": "INV-2024-0001", "status": "sent", "customer_id": "cust_abc123", "customer_name": "Acme Corporation", "issue_date": "2024-01-19", "due_date": "2024-02-18", "currency": "USD", "total_amount": 697500, "amount_due": 697500, "days_until_due": 30 }, { "id": "inv_7823f083-bb2c-54d6-bf6d-1b8e3fc75f41", "object": "invoice", "invoice_number": "INV-2024-0002", "status": "partially_paid", "customer_id": "cust_def456", "customer_name": "TechCorp Inc", "issue_date": "2024-01-15", "due_date": "2024-01-30", "currency": "USD", "total_amount": 125000, "amount_due": 50000, "days_until_due": 11 } ], "has_more": true, "url": "/v1/invoices" } ``` # Send Invoice Source: https://docs.stateset.com/api-reference/invoices/send POST https://api.stateset.com/v1/invoices/:id/send Send an invoice to the customer via email This endpoint sends an invoice to the customer via email. The invoice must be in draft or sent status. ## Authentication This endpoint requires a valid API key with `invoices:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the invoice to send ## Request Body Email addresses to send to (defaults to customer email) CC email addresses BCC email addresses Custom email subject (defaults to "Invoice \[number] from \[company]") Custom email message Whether to attach PDF (default: true) ### Response Returns the sent invoice with email details. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/invoices/inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/send' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "cc": ["accounting@acme.com"], "message": "Please find attached invoice for January services. Let me know if you have any questions." }' ``` ```javascript Node.js theme={null} const invoice = await stateset.invoices.send( 'inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { cc: ["accounting@acme.com"], message: "Please find attached invoice for January services. Let me know if you have any questions." } ); ``` ```python Python theme={null} invoice = stateset.invoices.send( 'inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', cc=["accounting@acme.com"], message="Please find attached invoice for January services. Let me know if you have any questions." ) ``` ```json Response theme={null} { "id": "inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "invoice", "status": "sent", "sent_at": "2024-01-20T12:00:00Z", "email_details": { "sent_to": ["billing@acme.com"], "cc": ["accounting@acme.com"], "subject": "Invoice INV-2024-0001 from Stateset", "message": "Please find attached invoice for January services. Let me know if you have any questions.", "attachments": ["invoice_INV-2024-0001.pdf"] }, "sent_count": 1, "last_sent_at": "2024-01-20T12:00:00Z", "next_reminder_date": "2024-01-27T12:00:00Z" } ``` # Update Invoice Source: https://docs.stateset.com/api-reference/invoices/update PUT https://api.stateset.com/v1/invoices/:id Update an existing invoice This endpoint updates an existing invoice. Only draft invoices can have their line items modified. Sent invoices can only update certain fields. ## Authentication This endpoint requires a valid API key with `invoices:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the invoice ## Request Body Update due date (YYYY-MM-DD) Update payment terms Update invoice notes Update line items (draft invoices only) Update billing address Update custom fields ### Response Returns the updated invoice object. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/invoices/inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "due_date": "2024-02-28", "payment_terms": "Net 45", "notes": "Updated payment terms as discussed" }' ``` ```javascript Node.js theme={null} const invoice = await stateset.invoices.update( 'inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { due_date: "2024-02-28", payment_terms: "Net 45", notes: "Updated payment terms as discussed" } ); ``` ```python Python theme={null} invoice = stateset.invoices.update( 'inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', due_date="2024-02-28", payment_terms="Net 45", notes="Updated payment terms as discussed" ) ``` ```json Response theme={null} { "id": "inv_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "invoice", "invoice_number": "INV-2024-0001", "status": "sent", "updated_at": "2024-01-20T11:00:00Z", "due_date": "2024-02-28", "payment_terms": "Net 45", "notes": "Updated payment terms as discussed", "total_amount": 697500, "amount_due": 697500, "days_until_due": 40 } ``` # Accept Lead Source: https://docs.stateset.com/api-reference/leads/accept POST https://api.stateset.com/v1/leads/:id/accept This endpoint accepts an existing lead. ### Body The ID provided in the data tab may be used to identify the lead ### Response The ID provided in the data tab may be used to identify the lead The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/leads/:id/accept' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation leadAcceptMutation { leadAccept (id: "${leadId}") { leads { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const leads = await stateset.leads.accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} leads = stateset.leads.accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} leads = Stateset::Lead.accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} leads, err := stateset.leads.accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Lead leads = stateset.leads.accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $leads = $stateset->leads->accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var leads = await stateset.leads.accept({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "lead", "accepted": true } ``` # Convert Lead Source: https://docs.stateset.com/api-reference/leads/convert POST https://api.stateset.com/v1/leads/:id/convert Convert a qualified lead into a customer account Converting a lead creates an associated customer and/or account record and marks the lead as converted. This action cannot be undone — use the [unconvert endpoint](/api-reference/leads/unconvert) to reverse it. ## Path Parameters The unique identifier of the lead to convert. **Example:** `e0901f08-3aa1-43c5-af5c-0a9d2fc64e30` ## Request Body Whether to create an associated account record during conversion. Whether to create an associated customer record during conversion. Override the owner for the newly created account/customer records. ### Response The ID of the converted lead. Object type. Always `lead`. Whether the lead was successfully converted. Updated lead status. Will be `converted`. The ID of the newly created customer record (if `create_customer` was true). The ID of the newly created account record (if `create_account` was true). ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/leads/e0901f08-3aa1-43c5-af5c-0a9d2fc64e30/convert' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "create_account": true, "create_customer": true }' ``` ```graphql GraphQL theme={null} mutation convertLead($id: uuid!) { leadConvert(id: $id) { leads { id status } userErrors { field message } } } ``` ```javascript Node.js theme={null} const result = await stateset.leads.convert( 'e0901f08-3aa1-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} result = stateset.leads.convert( 'e0901f08-3aa1-43c5-af5c-0a9d2fc64e30' ) ``` ```ruby Ruby theme={null} result = Stateset::Lead.convert( 'e0901f08-3aa1-43c5-af5c-0a9d2fc64e30' ) ``` ```go Go theme={null} result, err := stateset.Leads.Convert( "e0901f08-3aa1-43c5-af5c-0a9d2fc64e30", ) ``` ```java Java theme={null} LeadConvertResult result = stateset.leads().convert( "e0901f08-3aa1-43c5-af5c-0a9d2fc64e30" ); ``` ```php PHP theme={null} $result = $stateset->leads->convert( 'e0901f08-3aa1-43c5-af5c-0a9d2fc64e30' ); ``` ```json Response theme={null} { "id": "e0901f08-3aa1-43c5-af5c-0a9d2fc64e30", "object": "lead", "converted": true, "status": "converted", "customer_id": "cust_7b2f4a91-d3e5-4c8a-b1f0-9e6d3c5a7b2f", "account_id": "acct_3d1e8f72-a5b6-4c9d-8e0f-1a2b3c4d5e6f" } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Lead not found", "details": { "resource": "lead", "id": "e0901f08-3aa1-43c5-af5c-0a9d2fc64e30" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (409 Conflict) theme={null} { "error": { "code": "ALREADY_CONVERTED", "message": "This lead has already been converted", "details": { "lead_id": "e0901f08-3aa1-43c5-af5c-0a9d2fc64e30", "converted_at": "2024-06-10T14:30:00.000Z" }, "request_id": "req_abc123def456" } } ``` # Create Lead Source: https://docs.stateset.com/api-reference/leads/create POST https://api.stateset.com/v1/leads Create a new lead record in the CRM pipeline Creates a lead that can be tracked, engaged, and converted into a customer or account. ## Request Body First name of the lead. **Example:** `Sarah` Last name of the lead. **Example:** `Johnson` Email address of the lead. Must be unique. **Example:** `sarah.johnson@company.com` Phone number of the lead. **Example:** `+1-555-234-5678` Job title or position. **Example:** `VP of Operations` Department or division. **Example:** `Operations` Source or origin of the lead. **Options:** `website`, `referral`, `trade_show`, `cold_call`, `social_media`, `partner`, `other` Additional details or notes about the lead. Street address. City. State or province. Country. Whether the lead should not be contacted by phone. Whether the lead has opted out of email communication. ### Response Unique identifier for the created lead. Object type. Always `lead`. First name of the lead. Last name of the lead. Email address of the lead. Phone number of the lead. Job title of the lead. Source of the lead. Current status of the lead. Starts as `new`. ISO 8601 timestamp when the lead was created. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/leads' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "firstName": "Sarah", "lastName": "Johnson", "email": "sarah.johnson@company.com", "phone": "+1-555-234-5678", "title": "VP of Operations", "department": "Operations", "leadSource": "website", "description": "Interested in returns automation" }' ``` ```graphql GraphQL theme={null} mutation createLead($input: LeadInput!) { insert_leads_one(object: $input) { id firstName lastName email phone title leadSource status created_at } } ``` ```javascript Node.js theme={null} const lead = await stateset.leads.create({ firstName: 'Sarah', lastName: 'Johnson', email: 'sarah.johnson@company.com', phone: '+1-555-234-5678', title: 'VP of Operations', leadSource: 'website', }); ``` ```python Python theme={null} lead = stateset.leads.create( first_name='Sarah', last_name='Johnson', email='sarah.johnson@company.com', phone='+1-555-234-5678', title='VP of Operations', lead_source='website', ) ``` ```ruby Ruby theme={null} lead = Stateset::Lead.create( firstName: 'Sarah', lastName: 'Johnson', email: 'sarah.johnson@company.com', phone: '+1-555-234-5678', title: 'VP of Operations', leadSource: 'website', ) ``` ```go Go theme={null} lead, err := stateset.Leads.Create(&LeadCreateParams{ FirstName: "Sarah", LastName: "Johnson", Email: "sarah.johnson@company.com", Phone: "+1-555-234-5678", Title: "VP of Operations", LeadSource: "website", }) ``` ```json Response theme={null} { "id": "e0901f08-3aa1-43c5-af5c-0a9d2fc64e30", "object": "lead", "firstName": "Sarah", "lastName": "Johnson", "email": "sarah.johnson@company.com", "phone": "+1-555-234-5678", "title": "VP of Operations", "department": "Operations", "leadSource": "website", "status": "new", "description": "Interested in returns automation", "created_at": "2024-06-15T10:30:00.000Z" } ``` ```json Error Response (409 Conflict) theme={null} { "error": { "code": "DUPLICATE_RESOURCE", "message": "A lead with this email already exists", "details": { "field": "email", "value": "sarah.johnson@company.com" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (422 Validation Error) theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Required fields are missing", "details": { "missing_fields": ["firstName", "email"] }, "request_id": "req_abc123def456" } } ``` # Delete Lead Source: https://docs.stateset.com/api-reference/leads/delete Delete a lead by ID. # Delete Lead Use this endpoint to delete a lead by ID. # Engage Lead Source: https://docs.stateset.com/api-reference/leads/engage POST https://api.stateset.com/v1/leads/:id/engage This endpoint engages an existing lead. ### Body The ID provided in the data tab may be used to identify the lead ### Response The ID provided in the data tab may be used to identify the lead The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/leads/:id/engages' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation leadEngageMutation { leadEngage (id: "${leadId}") { leads { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const leads = await stateset.leads.engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} leads = stateset.leads.engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} leads = Stateset::Lead.engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} leads, err := stateset.leads.engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Lead leads = stateset.leads.engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $leads = $stateset->leads->engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var leads = await stateset.leads.engage({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "lead", "engaged": true } ``` # Retrieve Lead Source: https://docs.stateset.com/api-reference/leads/get GET https://api.stateset.com/v1/leads/:id/retrieve This endpoint retrieves a lead ### Body The ID of the user group to which the lead belongs. ### Response The ID of the lead. Name or details of the assistant associated with the lead. Phone number of the assistant. URL or path to the lead's avatar image. Date of birth of the lead. Name or details of the controller associated with the lead. Date and time when the lead was created. Name or details of the person who created the lead. Department or division associated with the lead. Description or additional details about the lead. Indicates whether the lead should not be called. Email address of the lead. Indicates whether the lead has opted out of email communication. Fax number of the lead. Indicates whether the lead has opted out of fax communication. First name of the lead. Handle or username associated with the lead. Indicates whether the lead is marked as invalid. Languages known or spoken by the lead. Last name of the lead. Last person who modified the lead. Source or origin of the lead/lead. City of the mailing address. Country of the mailing address. Geocoding accuracy of the mailing address. State or province of the mailing address. Street of the mailing address. Name or details of the owner of the lead. Phone number of the lead. URL or path to the lead's photo. Name or details of the processor associated with the lead. Title or position of the lead. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/leads/retrieve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { leads(limit: $limit, offset: $offset, order_by: {created_date: $order_direction}) { ``` ```js Node.js theme={null} const leads = await stateset.leads.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} leads = stateset.leads.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} leads, err := stateset.leads.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} leads = Stateset::leads.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} leads leads = Stateset.leads.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} leads leads = Stateset.leads.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $leads = Stateset\leads::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/return HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` # List Leads Source: https://docs.stateset.com/api-reference/leads/list GET https://api.stateset.com/v1/leads This endpoint list leads. ### Body The ID of the user group to which the lead belongs. ### Response The ID of the lead. Name or details of the assistant associated with the lead. Phone number of the assistant. URL or path to the lead's avatar image. Date of birth of the lead. Name or details of the controller associated with the lead. Date and time when the lead was created. Name or details of the person who created the lead. Department or division associated with the lead. Description or additional details about the lead. Indicates whether the lead should not be called. Email address of the lead. Indicates whether the lead has opted out of email communication. Fax number of the lead. Indicates whether the lead has opted out of fax communication. First name of the lead. Handle or username associated with the lead. Indicates whether the lead is marked as invalid. Languages known or spoken by the lead. Last name of the lead. Last person who modified the lead. Source or origin of the lead/lead. City of the mailing address. Country of the mailing address. Geocoding accuracy of the mailing address. State or province of the mailing address. Street of the mailing address. Name or details of the owner of the lead. Phone number of the lead. URL or path to the lead's photo. Name or details of the processor associated with the lead. Title or position of the lead. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/leads' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` # Reject Lead Source: https://docs.stateset.com/api-reference/leads/reject POST https://api.stateset.com/v1/leads/:id/reject This endpoint rejects an existing lead. ### Body The ID provided in the data tab may be used to identify the lead ### Response The ID provided in the data tab may be used to identify the lead The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/leads/:id/reject' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation leadRejectMutation { leadReject (id: "${leadId}") { leads { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const leads = await stateset.leads.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} leads = stateset.leads.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} leads = Stateset::Lead.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} leads, err := stateset.leads.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Lead leads = stateset.leads.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $leads = $stateset->leads->reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var leads = await stateset.leads.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "lead", "rejected": true } ``` # UnConvert Lead Source: https://docs.stateset.com/api-reference/leads/unconvert POST https://api.stateset.com/v1/leads/:id/unconvert This endpoint converts an existing lead. ### Body The ID provided in the data tab may be used to identify the lead ### Response The ID provided in the data tab may be used to identify the lead The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/leads/:id/unconvert' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation leadUnConvertMutation { leadUnConvert (id: "${leadId}") { leads { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const leads = await stateset.leads.unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} leads = stateset.leads.unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} leads = Stateset::Lead.unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} leads, err := stateset.leads.unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Lead leads = stateset.leads.unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $leads = $stateset->leads->unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var leads = await stateset.leads.unconvert({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "lead", "unconverted": true } ``` # Create Location Source: https://docs.stateset.com/api-reference/locations/create POST https://api.stateset.com/v1/locations Create a new warehouse or store location This endpoint creates a new location for inventory management. Locations can be warehouses, stores, or distribution centers. ## Authentication This endpoint requires a valid API key with `locations:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Location name Unique location code (e.g., "WH-001", "STORE-NYC-01") Location type: "warehouse", "store", "distribution\_center", "dropship" Location address Street address Additional address info City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Contact information Contact person name Contact email Contact phone Operating hours Monday hours with open/close times Tuesday hours Wednesday hours Thursday hours Friday hours Saturday hours Sunday hours Location capabilities: "storage", "fulfillment", "returns", "cross\_dock", "pickup" Storage capacity information Total square footage Number of storage units/bins Number of pallet positions Location timezone (e.g., "America/Los\_Angeles") Whether location is active (default: true) Additional custom fields ### Response Returns the created location. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/locations' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "name": "West Coast Distribution Center", "code": "WH-WEST-01", "type": "warehouse", "address": { "line1": "1000 Distribution Way", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "contact": { "name": "John Smith", "email": "john.smith@warehouse.com", "phone": "+1-555-123-4567" }, "capabilities": ["storage", "fulfillment", "returns"], "capacity": { "total_sqft": 50000, "storage_units": 5000, "pallet_positions": 2000 }, "timezone": "America/Los_Angeles" }' ``` ```javascript Node.js theme={null} const location = await stateset.locations.create({ name: "West Coast Distribution Center", code: "WH-WEST-01", type: "warehouse", address: { line1: "1000 Distribution Way", city: "Los Angeles", state: "CA", postal_code: "90001", country: "US" }, contact: { name: "John Smith", email: "john.smith@warehouse.com", phone: "+1-555-123-4567" }, capabilities: ["storage", "fulfillment", "returns"], capacity: { total_sqft: 50000, storage_units: 5000, pallet_positions: 2000 }, timezone: "America/Los_Angeles" }); ``` ```json Response theme={null} { "id": "loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "location", "name": "West Coast Distribution Center", "code": "WH-WEST-01", "type": "warehouse", "status": "active", "created_at": "2024-01-19T16:00:00Z", "address": { "line1": "1000 Distribution Way", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US", "formatted": "1000 Distribution Way, Los Angeles, CA 90001, US" }, "contact": { "name": "John Smith", "email": "john.smith@warehouse.com", "phone": "+1-555-123-4567" }, "capabilities": ["storage", "fulfillment", "returns"], "capacity": { "total_sqft": 50000, "storage_units": 5000, "pallet_positions": 2000, "available_units": 4850, "available_pallets": 1920 }, "operating_hours": { "monday": { "open": "06:00", "close": "22:00" }, "tuesday": { "open": "06:00", "close": "22:00" }, "wednesday": { "open": "06:00", "close": "22:00" }, "thursday": { "open": "06:00", "close": "22:00" }, "friday": { "open": "06:00", "close": "22:00" }, "saturday": { "open": "08:00", "close": "18:00" }, "sunday": { "closed": true } }, "timezone": "America/Los_Angeles", "coordinates": { "latitude": 34.0522, "longitude": -118.2437 } } ``` # Delete Location Source: https://docs.stateset.com/api-reference/locations/delete Delete a location by ID. # Delete Location Use this endpoint to delete a location by ID. # Get Location Source: https://docs.stateset.com/api-reference/locations/get GET https://api.stateset.com/v1/locations/:id Retrieve a specific location by ID This endpoint retrieves detailed information about a specific location including capacity, inventory levels, and operational details. ## Authentication This endpoint requires a valid API key with `locations:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the location ## Query Parameters Expand related objects. Options: "inventory\_summary", "staff", "upcoming\_shipments" ### Response Unique location identifier Object type, always "location" Location name Location code Location type Capacity information with available space ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/locations/loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30?expand=inventory_summary' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const location = await stateset.locations.retrieve( 'loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { expand: ['inventory_summary'] } ); ``` ```python Python theme={null} location = stateset.locations.retrieve( 'loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', expand=['inventory_summary'] ) ``` ```json Response theme={null} { "id": "loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "location", "name": "West Coast Distribution Center", "code": "WH-WEST-01", "type": "warehouse", "status": "active", "created_at": "2024-01-19T16:00:00Z", "updated_at": "2024-01-20T08:00:00Z", "address": { "line1": "1000 Distribution Way", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US", "formatted": "1000 Distribution Way, Los Angeles, CA 90001, US" }, "contact": { "name": "John Smith", "email": "john.smith@warehouse.com", "phone": "+1-555-123-4567" }, "capabilities": ["storage", "fulfillment", "returns"], "capacity": { "total_sqft": 50000, "storage_units": 5000, "pallet_positions": 2000, "available_units": 4850, "available_pallets": 1920, "utilization_percent": 4.0 }, "operating_hours": { "monday": { "open": "06:00", "close": "22:00" }, "tuesday": { "open": "06:00", "close": "22:00" }, "wednesday": { "open": "06:00", "close": "22:00" }, "thursday": { "open": "06:00", "close": "22:00" }, "friday": { "open": "06:00", "close": "22:00" }, "saturday": { "open": "08:00", "close": "18:00" }, "sunday": { "closed": true } }, "timezone": "America/Los_Angeles", "coordinates": { "latitude": 34.0522, "longitude": -118.2437 }, "inventory_summary": { "total_skus": 1250, "total_units": 125000, "total_value": 2500000, "low_stock_alerts": 15, "out_of_stock": 3 }, "metrics": { "orders_fulfilled_today": 45, "orders_fulfilled_week": 312, "average_fulfillment_time": "2.5 hours", "accuracy_rate": 99.7 } } ``` # List Locations Source: https://docs.stateset.com/api-reference/locations/list GET https://api.stateset.com/v1/locations List all locations with filtering and pagination This endpoint retrieves a paginated list of locations. Use filters to narrow results by type, capabilities, and status. ## Authentication This endpoint requires a valid API key with `locations:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of items to return (default: 20, max: 100) Number of items to skip Filter by type: "warehouse", "store", "distribution\_center", "dropship" Filter by status: "active", "inactive", "maintenance" Filter by capabilities: "storage", "fulfillment", "returns", "cross\_dock", "pickup" Filter by country code Filter by state/province Filter by city Sort field: "created\_at", "name", "code", "capacity" Sort order: "asc" or "desc" ### Response Object type, always "list" Array of location objects Whether more items exist ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/locations?type=warehouse&status=active' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const locations = await stateset.locations.list({ type: 'warehouse', status: 'active', capabilities: ['fulfillment'] }); ``` ```python Python theme={null} locations = stateset.locations.list( type='warehouse', status='active', capabilities=['fulfillment'] ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "location", "name": "West Coast Distribution Center", "code": "WH-WEST-01", "type": "warehouse", "status": "active", "address": { "city": "Los Angeles", "state": "CA", "country": "US" }, "capabilities": ["storage", "fulfillment", "returns"], "capacity": { "utilization_percent": 4.0, "available_units": 4850 } }, { "id": "loc_7823f083-bb2c-54d6-bf6d-1b8e3fc75f41", "object": "location", "name": "East Coast Fulfillment Center", "code": "WH-EAST-01", "type": "warehouse", "status": "active", "address": { "city": "Newark", "state": "NJ", "country": "US" }, "capabilities": ["storage", "fulfillment", "cross_dock"], "capacity": { "utilization_percent": 65.0, "available_units": 1750 } } ], "has_more": true, "total_count": 8 } ``` # Update Location Source: https://docs.stateset.com/api-reference/locations/update PUT https://api.stateset.com/v1/locations/:id Update location information This endpoint updates location details including contact information, operating hours, and capabilities. ## Authentication This endpoint requires a valid API key with `locations:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the location ## Request Body Update location name Update contact information Update operating hours Update location capabilities Update capacity information Update active status Update custom fields ### Response Returns the updated location object. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/locations/loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "contact": { "name": "Jane Doe", "email": "jane.doe@warehouse.com", "phone": "+1-555-987-6543" }, "capabilities": ["storage", "fulfillment", "returns", "pickup"] }' ``` ```javascript Node.js theme={null} const location = await stateset.locations.update( 'loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { contact: { name: "Jane Doe", email: "jane.doe@warehouse.com", phone: "+1-555-987-6543" }, capabilities: ["storage", "fulfillment", "returns", "pickup"] } ); ``` ```python Python theme={null} location = stateset.locations.update( 'loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', contact={ "name": "Jane Doe", "email": "jane.doe@warehouse.com", "phone": "+1-555-987-6543" }, capabilities=["storage", "fulfillment", "returns", "pickup"] ) ``` ```json Response theme={null} { "id": "loc_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "location", "updated_at": "2024-01-20T13:00:00Z", "name": "West Coast Distribution Center", "code": "WH-WEST-01", "contact": { "name": "Jane Doe", "email": "jane.doe@warehouse.com", "phone": "+1-555-987-6543" }, "capabilities": ["storage", "fulfillment", "returns", "pickup"], "status": "active" } ``` # Create Manufacture Order Source: https://docs.stateset.com/api-reference/manufactureorder/create POST https://api.stateset.com/v1/manufacture_orders This endpoint creates a new manufacture order ### Body Unique identifier for the manufacture order Additional notes or information about the manufacture order Number assigned to the manufacture order Priority level of the manufacture order Site or location associated with the manufacture order Location where the manufactured product will be stored Date and time when the manufacture order was created Expected date of completion for the manufacture order Date when the manufacture order was issued ### Response Unique identifier for the manufacture order Additional notes or information about the manufacture order Number assigned to the manufacture order Priority level of the manufacture order Site or location associated with the manufacture order Location where the manufactured product will be stored Date and time when the manufacture order was created Expected date of completion for the manufacture order Date when the manufacture order was issued Name of the bill of materials (BOM) associated with the line item Number assigned to the bill of materials (BOM) Unique identifier for the line item Expected date for the completion of the line item Status of the line item (e.g., in progress, completed, etc.) Type or category of the line item Number of the associated manufacture order Type of output produced by the line item (e.g., product, component) Name of the part associated with the line item Number assigned to the part associated with the line item Priority level of the line item Quantity of the part to be manufactured or processed Site or location associated with the line item Number of the associated work order Location of the yield of the manufacture order line item ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/manufacture_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```js Node.js theme={null} const created = await stateset.manufactureorder.create( 'mo_ODkRWQtx9NVsRX' ); ``` ```graphQL GraphQL theme={null} mutation addManufactureOrderLineItem($manufacture_order_line_item: manufacture_order_line_items_insert_input!) { insert_manufacture_order_line_items(objects: [$manufacture_order_line_item]) { returning { id } } } ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Delete Manufacture Order Source: https://docs.stateset.com/api-reference/manufactureorder/delete DELETE https://api.stateset.com/v1/manufacture_orders/:id This endpoint deletes an existing manufacturer order. ### Body The ID provided in the data tab may be used to identify the manufacture order ### Response The ID provided in the data tab may be used to identify the manufacture order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/manufacture_orders/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "mo_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteManufactureOrder ($id: String!) { delete_manufacture_orders(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const manufactureorders = await stateset.manufactureorders.del({ 'mo_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} manufactureorders = stateset.manufactureorders.del({ 'mo_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} manufactureorders, err := stateset.manufactureorders.Del( "mo_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Return manufactureorders = stateset.manufactureorders.del( "mo_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const manufactureorders = await stateset.manufactureorders.del({ 'mo_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} manufactureorders = Stateset::Return.del({ 'mo_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $manufactureorder = $stateset->manufactureorder->del( 'mo_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/manufacture_orders HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "mo_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "deleted": true } ``` # Get Manufacture Order Source: https://docs.stateset.com/api-reference/manufactureorder/get GET https://api.stateset.com/v1/manufacture_orders/:id This endpoint gets or creates a new manufacture order. ### Body Unique identifier for the manufacture order ### Response Unique identifier for the manufacture order Additional notes or information about the manufacture order Number assigned to the manufacture order Priority level of the manufacture order Site or location associated with the manufacture order Location where the manufactured product will be stored Date and time when the manufacture order was created Expected date of completion for the manufacture order Date when the manufacture order was issued Name of the bill of materials (BOM) associated with the line item Number assigned to the bill of materials (BOM) Unique identifier for the line item Expected date for the completion of the line item Status of the line item (e.g., in progress, completed, etc.) Type or category of the line item Number of the associated manufacture order Type of output produced by the line item (e.g., product, component) Name of the part associated with the line item Number assigned to the part associated with the line item Priority level of the line item Quantity of the part to be manufactured or processed Site or location associated with the line item Number of the associated work order Location of the yield of the manufacture order line item ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/manufacture_orders/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { { "count": 1, "next": null, "previous": null, "results": [ { "id": "b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1", "memo": "This is a manufacture order", "number": "MO-0001", "priority": "High", "site": "Site 1", "yield_location": "Location 1", "created_on": "2021-01-01T00:00:00.000000Z", "expected_completion_date": "2021-01-01", "issued_on": "2021-01-01", "manufacture_order_line_items": [ { "bom_name": "BOM 1", "bom_number": "BOM-0001", "id": "b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1", "expected_date": "2021-01-01", "line_status": "In Progress", "line_type": "Manufacture", "manufacture_order_number": "MO-0001", "output_type": "Product", "part_name": "Part 1", "part_number": "PART-0001", "priority": "High", "quantity": 100, "site": "Site 1", "work_order_number": "WO-0001", "yield_location": "Location 1" } ] } ] } } ``` ## Manufacture Order | Field | Type | Description | | -------------------------- | -------- | ----------------------------------------------------------- | | id | String | Unique identifier for the manufacture order | | memo | String | Additional notes or information about the manufacture order | | number | String | Number assigned to the manufacture order | | priority | String | Priority level of the manufacture order | | site | String | Site or location associated with the manufacture order | | yield\_location | String | Location where the manufactured product will be stored | | created\_on | DateTime | Date and time when the manufacture order was created | | expected\_completion\_date | Date | Expected date of completion for the manufacture order | | issued\_on | Date | Date when the manufacture order was issued | ## Manufacture Order Line Item | Field | Type | Description | | -------------------------- | ------- | ------------------------------------------------------------------- | | bom\_name | String | Name of the bill of materials (BOM) associated with the line item | | bom\_number | String | Number assigned to the bill of materials (BOM) | | id | String | Unique identifier for the line item | | expected\_date | Date | Expected date for the completion of the line item | | line\_status | String | Status of the line item (e.g., in progress, completed, etc.) | | line\_type | String | Type or category of the line item | | manufacture\_order\_number | String | Number of the associated manufacture order | | output\_type | String | Type of output produced by the line item (e.g., product, component) | | part\_name | String | Name of the part associated with the line item | | part\_number | String | Number assigned to the part associated with the line item | | priority | String | Priority level of the line item | | quantity | Integer | Quantity of the part to be manufactured or processed | | site | String | Site or location associated with the line item | | work\_order\_number | String | Number of the associated work order | | yield\_location | String | Location where the manufactured product will be stored | # List Manufacture Orders Source: https://docs.stateset.com/api-reference/manufactureorder/list GET https://api.stateset.com/v1/manufacture_orders/list This endpoint list manufacture orders. ### Body This is the limit of the manufacture orders. This is the offset of the manufacture orders. This is the order direction of the manufacture orders. ### Response Unique identifier for the manufacture order Additional notes or information about the manufacture order Number assigned to the manufacture order Priority level of the manufacture order Site or location associated with the manufacture order Location where the manufactured product will be stored Date and time when the manufacture order was created Expected date of completion for the manufacture order Date when the manufacture order was issued Name of the bill of materials (BOM) associated with the line item Number assigned to the bill of materials (BOM) Unique identifier for the line item Expected date for the completion of the line item Status of the line item (e.g., in progress, completed, etc.) Type or category of the line item Number of the associated manufacture order Type of output produced by the line item (e.g., product, component) Name of the part associated with the line item Number assigned to the part associated with the line item Priority level of the line item Quantity of the part to be manufactured or processed Site or location associated with the line item Number of the associated work order Location of the yield of the manufacture order line item ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/manufacture_orders' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "ASC" }' ``` ```json Response theme={null} { { "count": 1, "next": null, "previous": null, "results": [ { "id": "b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1", "memo": "This is a manufacture order", "number": "MO-0001", "priority": "High", "site": "Site 1", "yield_location": "Location 1", "created_on": "2021-01-01T00:00:00.000000Z", "expected_completion_date": "2021-01-01", "issued_on": "2021-01-01", "manufacture_order_line_items": [ { "bom_name": "BOM 1", "bom_number": "BOM-0001", "id": "b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1", "expected_date": "2021-01-01", "line_status": "In Progress", "line_type": "Manufacture", "manufacture_order_number": "MO-0001", "output_type": "Product", "part_name": "Part 1", "part_number": "PART-0001", "priority": "High", "quantity": 100, "site": "Site 1", "work_order_number": "WO-0001", "yield_location": "Location 1" } ] } ] } } ``` # Update Manufacture Order Source: https://docs.stateset.com/api-reference/manufactureorder/update PUT https://api.stateset.com/v1/manufacture_orders/:id This endpoint updates an existing manufacture order. ### Body Unique identifier for the manufacture order Additional notes or information about the manufacture order Number assigned to the manufacture order Priority level of the manufacture order Site or location associated with the manufacture order Location where the manufactured product will be stored Date and time when the manufacture order was created Expected date of completion for the manufacture order Date when the manufacture order was issued ### Response Unique identifier for the manufacture order Additional notes or information about the manufacture order Number assigned to the manufacture order Priority level of the manufacture order Site or location associated with the manufacture order Location where the manufactured product will be stored Date and time when the manufacture order was created Expected date of completion for the manufacture order Date when the manufacture order was issued Name of the bill of materials (BOM) associated with the line item Number assigned to the bill of materials (BOM) Unique identifier for the line item Expected date for the completion of the line item Status of the line item (e.g., in progress, completed, etc.) Type or category of the line item Number of the associated manufacture order Type of output produced by the line item (e.g., product, component) Name of the part associated with the line item Number assigned to the part associated with the line item Priority level of the line item Quantity of the part to be manufactured or processed Site or location associated with the line item Number of the associated work order Location of the yield of the manufacture order line item ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/manufacture_orders/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", "memo": "test", "number": "1", "priority": "1", "site": "1", "yield_location": "1", "created_on": "2021-01-01T00:00:00Z", "expected_completion_date": "2021-01-01" }' ``` ```json Response theme={null} { "id": "1", "memo": "test", "number": "1", "priority": "1", "site": "1", "yield_location": "1", "created_on": "2021-01-01T00:00:00Z", "expected_completion_date": "2021-01-01" } ``` # Create Manufacture Order Line Item Source: https://docs.stateset.com/api-reference/manufactureorderlineitem/create POST https://api.stateset.com/v1/manufacture_order_line_items This endpoint creates a new manufacture order line item. ### Body This is the id of the manufacture order line item. This is the name of the bill of materials (BOM) associated with the line item. This is the number assigned to the bill of materials (BOM). This is the expected date for the completion of the line item. This is the status of the line item (e.g., in progress, completed, etc.). This is the type or category of the line item. This is the number of the associated manufacture order. This is the type of output produced by the line item (e.g., product, component). This is the name of the part associated with the line item. This is the number assigned to the part associated with the line item. This is the priority level of the line item. This is the quantity of the part to be manufactured or processed. This is the site or location associated with the line item. This is the number of the associated work order. This is the location where the manufactured product will be stored. ### Response This is the id of the manufacture order line item. This is the name of the bill of materials (BOM) associated with the line item. This is the number assigned to the bill of materials (BOM). This is the expected date for the completion of the line item. This is the status of the line item (e.g., in progress, completed, etc.). This is the type or category of the line item. This is the number of the associated manufacture order. This is the type of output produced by the line item (e.g., product, component). This is the name of the part associated with the line item. This is the number assigned to the part associated with the line item. This is the priority level of the line item. This is the quantity of the part to be manufactured or processed. This is the site or location associated with the line item. This is the number of the associated work order. This is the location where the manufactured product will be stored. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/manufacture_order_line_items' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Delete Manufacture Order Line Item Source: https://docs.stateset.com/api-reference/manufactureorderlineitem/delete DELETE https://api.stateset.com/v1/manufacture_order_line_items/:id This endpoint deletes an existing manufacture order line item. ### Body The ID of the packing list item to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/manufacture_order_line_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "example_1" }' ``` ```json Response theme={null} { "id": "example_1", "object": "manufacture_order_line_item", "deleted": true, } ``` # Get Manufacture Order Line Item Source: https://docs.stateset.com/api-reference/manufactureorderlineitem/get GET https://api.stateset.com/v1/manufacture_order_line_items/:id This endpoint gets or creates a new manufacture order line item. ### Body This is the id of the manufacture order line item. ### Response This is the id of the manufacture order line item. This is the name of the bill of materials (BOM) associated with the line item. This is the number assigned to the bill of materials (BOM). This is the expected date for the completion of the line item. This is the status of the line item (e.g., in progress, completed, etc.). This is the type or category of the line item. This is the number of the associated manufacture order. This is the type of output produced by the line item (e.g., product, component). This is the name of the part associated with the line item. This is the number assigned to the part associated with the line item. This is the priority level of the line item. This is the quantity of the part to be manufactured or processed. This is the site or location associated with the line item. This is the number of the associated work order. This is the location where the manufactured product will be stored. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/work_order_line_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1" }' ``` ```json Response theme={null} { "id": "1", "bom_name": "BOM 1", "bom_number": "BOM-1", "expected_date": "2021-01-01", "line_status": "In Progress", "line_type": "Manufacture", "manufacture_order_number": "MO-1", "output_type": "Product", "part_name": "Part 1", "part_number": "PART-1", "priority": "High", "quantity": 100, "site": "Site 1", "work_order_number": "WO-1", "yield_location": "Location 1" } ``` ## Manufacture Order Line Item | Field | Type | Description | | -------------------------- | ------- | ------------------------------------------------------------------- | | bom\_name | String | Name of the bill of materials (BOM) associated with the line item | | bom\_number | String | Number assigned to the bill of materials (BOM) | | id | String | Unique identifier for the line item | | expected\_date | Date | Expected date for the completion of the line item | | line\_status | String | Status of the line item (e.g., in progress, completed, etc.) | | line\_type | String | Type or category of the line item | | manufacture\_order\_number | String | Number of the associated manufacture order | | output\_type | String | Type of output produced by the line item (e.g., product, component) | | part\_name | String | Name of the part associated with the line item | | part\_number | String | Number assigned to the part associated with the line item | | priority | String | Priority level of the line item | | quantity | Integer | Quantity of the part to be manufactured or processed | | site | String | Site or location associated with the line item | | work\_order\_number | String | Number of the associated work order | | yield\_location | String | Location where the manufactured product will be stored | # Update Manufacture Order Line Item Source: https://docs.stateset.com/api-reference/manufactureorderlineitem/update PUT https://api.stateset.com/v1/manufacture_order_line_items/:id This endpoint updates an existing manufacture order line item. ### Body This is the id of the manufacture order line item. This is the name of the bill of materials (BOM) associated with the line item. This is the number assigned to the bill of materials (BOM). This is the expected date for the completion of the line item. This is the status of the line item (e.g., in progress, completed, etc.). This is the type or category of the line item. This is the number of the associated manufacture order. This is the type of output produced by the line item (e.g., product, component). This is the name of the part associated with the line item. This is the number assigned to the part associated with the line item. This is the priority level of the line item. This is the quantity of the part to be manufactured or processed. This is the site or location associated with the line item. This is the number of the associated work order. This is the location where the manufactured product will be stored. ### Response This is the id of the manufacture order line item. This is the name of the bill of materials (BOM) associated with the line item. This is the number assigned to the bill of materials (BOM). This is the expected date for the completion of the line item. This is the status of the line item (e.g., in progress, completed, etc.). This is the type or category of the line item. This is the number of the associated manufacture order. This is the type of output produced by the line item (e.g., product, component). This is the name of the part associated with the line item. This is the number assigned to the part associated with the line item. This is the priority level of the line item. This is the quantity of the part to be manufactured or processed. This is the site or location associated with the line item. This is the number of the associated work order. This is the location where the manufactured product will be stored. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/manufacture_order_line_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # Create Message Source: https://docs.stateset.com/api-reference/messages/create POST https://api.stateset.com/v1/messages This endpoint creates a new message ### Body This is the ID of the message to be created. This is the time of the message to be created. This is the body of the message to be created. This is the username of the message to be created. This is the channel\_id of the message to be created. This is the user\_id of the message to be created. This is the is\_public of the message to be created. This is the from of the message to be created. This is the to of the message to be created. This is the from\_me of the message to be created. This is the sent\_receipt of the message to be created. This is the delivered\_receipt of the message to be created. This is the message\_number of the message to be created. This is the date of the message to be created. This is the timestamp of the message to be created. This is the created\_at of the message to be created. This is the updated\_at of the message to be created. ### Response This is the id of the message. This is the body of the message. This is the date and time when the message was created. This is the date when the message was sent. This indicates if the message has been delivered. This is the sender of the message. This indicates if the message was sent by the user. This indicates if the message is public or private. This is the unique number assigned to the message. This indicates if the message has been sent. This is the time when the message was sent. This is the timestamp of the message. This is the recipient of the message. This is the unique identifier for the user associated with the message. This is the username of the user associated with the message. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/message' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation insert_message ($message: message_insert_input! ){ insert_message ( objects: [$message] ) { returning { id time body username } } } ``` ```javascript Node.js theme={null} const created = await stateset.message.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_message": { "returning": [ { "id": "", } ] } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # Delete Message Source: https://docs.stateset.com/api-reference/messages/delete DELETE https://api.stateset.com/v1/messages/:id This endpoint deletes an existing message. ### Body The ID provided in the data tab may be used to identify the message ### Response The ID provided in the data tab may be used to identify the message The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/messages/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "msg_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteMessage ($id: String!) { delete_message(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const message = await stateset.channelthread.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} message = stateset.message.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} message, err := stateset.Cases.Del( "msg_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case message = stateset.message.del( "msg_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const message = await stateset.message.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} message = Stateset::Return.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $message = $stateset->message->del( 'msg_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/channelthread HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "channel_thread", "deleted": true } ``` # Get Messages Source: https://docs.stateset.com/api-reference/messages/get GET https://api.stateset.com/v1/messages/:id This endpoint gets a message. ### Body This is the id of the message. ### Response This is the id of the message. This is the body of the message. This is the date and time when the message was created. This is the date when the message was sent. This indicates if the message has been delivered. This is the sender of the message. This indicates if the message was sent by the user. This indicates if the message is public or private. This is the unique number assigned to the message. This indicates if the message has been sent. This is the time when the message was sent. This is the timestamp of the message. This is the recipient of the message. This is the unique identifier for the user associated with the message. This is the username of the user associated with the message. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/messages/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MyMessages { message { id body created_at date deliveredReceipt from fromMe is_public messageNumber sentReceipt time timestamp to user_id username } } ``` ```js Node.js theme={null} const messages = await stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} messages = stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} messages, err := stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} messages = Stateset::Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Message messages = Stateset.Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Message messages = Stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $messages = Stateset\Messages::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/messages HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # List Messages Source: https://docs.stateset.com/api-reference/messages/list GET https://api.stateset.com/v1/messages This endpoint lists messages. ### Body This is the limit of the messages. This is the offset of the messages This is the order direction of the messages. ### Response This is the id of the message. This is the body of the message. This is the date and time when the message was created. This is the date when the message was sent. This indicates if the message has been delivered. This is the sender of the message. This indicates if the message was sent by the user. This indicates if the message is public or private. This is the unique number assigned to the message. This indicates if the message has been sent. This is the time when the message was sent. This is the timestamp of the message. This is the recipient of the message. This is the unique identifier for the user associated with the message. This is the username of the user associated with the message. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/messages' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MyMessages { message { id body created_at date deliveredReceipt from fromMe is_public messageNumber sentReceipt time timestamp to user_id username } } ``` ```js Node.js theme={null} const messages = await stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} messages = stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} messages, err := stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} messages = Stateset::Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Message messages = Stateset.Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Message messages = Stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $messages = Stateset\Messages::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/messages HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # Update Message Source: https://docs.stateset.com/api-reference/messages/update POST https://api.stateset.com/v1/messages/:id This endpoint updates a message ### Body This is the ID of the message to be created. This is the time of the message to be created. This is the body of the message to be created. This is the username of the message to be created. This is the channel\_id of the message to be created. This is the user\_id of the message to be created. This is the is\_public of the message to be created. This is the from of the message to be created. This is the to of the message to be created. This is the from\_me of the message to be created. This is the sent\_receipt of the message to be created. This is the delivered\_receipt of the message to be created. This is the message\_number of the message to be created. This is the date of the message to be created. This is the timestamp of the message to be created. This is the created\_at of the message to be created. This is the updated\_at of the message to be created. ### Response ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/messages/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation insert_message ($message: message_insert_input! ){ insert_message ( objects: [$message] ) { returning { id time body username } } } ``` ```javascript Node.js theme={null} const created = await stateset.message.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_message": { "returning": [ { "id": "", } ] } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # Create Note Source: https://docs.stateset.com/api-reference/notes/create POST https://api.stateset.com/v1/notes Create a new note record for annotations or comments This endpoint requires authentication with `notes:write` permission. ### Request Parameters The title or subject of the note The main content or body of the note ID or name of the user creating the note (auto-filled if not provided) Optional ID of the resource this note is associated with (e.g., order ID) ### Response Unique identifier for the created note The title of the note The content of the note Timestamp when the note was created Timestamp when the note was last updated User who created the note User who last modified the note ### Request Example ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/notes' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "title": "Important Update", "body": "Customer requested expedited shipping", "associated_id": "order_123" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.stateset.com/v1/notes', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY' }, body: JSON.stringify({ title: 'Important Update', body: 'Customer requested expedited shipping', associated_id: 'order_123' }) }); ``` ```python Python theme={null} import requests response = requests.post( 'https://api.stateset.com/v1/notes', headers={ 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY' }, json={ 'title': 'Important Update', 'body': 'Customer requested expedited shipping', 'associated_id': 'order_123' } ) ``` ### Response Example ```json Success Response theme={null} { "id": "note_001", "title": "Important Update", "body": "Customer requested expedited shipping", "created_date": "2024-01-01T12:00:00Z", "last_modified_date": "2024-01-01T12:00:00Z", "created_by": "user_123", "last_modified_by": "user_123" } ``` ```json Error Response theme={null} { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Missing required field: title" } } ``` # Delete Note Source: https://docs.stateset.com/api-reference/notes/delete DELETE https://api.stateset.com/v1/notes/:id This endpoint deletes an existing note. ### Body The ID provided in the data tab may be used to identify the note ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/notes/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteNote($id: String!) { delete_notes(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const notes = await stateset.notes.del({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} notes = stateset.notes.del({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} notes, err := stateset.notes.Del( "nt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Note notes = stateset.notes.del( "nt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const notes = await stateset.notes.del({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} notes = Stateset::Note.del({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $notes = $stateset->notes->del( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/note HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "note", "deleted": true } ``` # Retrieve Note Source: https://docs.stateset.com/api-reference/notes/get GET https://api.stateset.com/v1/notes/:id This endpoint retrieves a note. ### Body This is the id of the note. ### Response This is the id of the note This is the title of the note This is the body of the note This is the created date of the note This is the last modified date of the note ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/note/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { notes(limit: $limit, offset: $offset, order_by: {created_date: $order_direction}) { id title body createdDate lastModifiedDate } } ``` ```js Node.js theme={null} const notes = await stateset.notes.retrieve({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} notes = stateset.notes.retrieve({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} notes, err := stateset.notes.Retrieve( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} notes = Stateset::Notes.retrieve( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} notes notes = Stateset.notes.retrieve( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} notes notes = Stateset.notes.Retrieve( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $notes = Stateset\notes::retrieve( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/note HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "notes": [ { "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", }, ] } ``` # List Notes Source: https://docs.stateset.com/api-reference/notes/list GET https://api.stateset.com/v1/notes/list This endpoint list notes. ### Body This is the limit of the notes. This is the offset of the notes. This is the order direction of the notes. ### Response This is the id of the note This is the title of the note This is the body of the note This is the created date of the note This is the last modified date of the note ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/note/list' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { notes(limit: $limit, offset: $offset, order_by: {created_date: $order_direction}) { id title body createdDate lastModifiedDate } } ``` ```js Node.js theme={null} const notes = await stateset.notes.list({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} notes = stateset.notes.list({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} notes, err := stateset.notes.list( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} notes = Stateset::Notes.list( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} notes notes = Stateset.notes.list( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} notes notes = Stateset.notes.list( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $notes = Stateset\notes::list( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/note HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "notes": [ { "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", }, ] } ``` # Update Note Source: https://docs.stateset.com/api-reference/notes/update POST https://api.stateset.com/v1/notes/update This endpoint updates a note. ### Body This is the id of the note. This is the title of the note. This is the body of the note. This is the created date of the note. This is the last modified date of the note. This is the user that created the note. This is the user that last modified the note. ### Response This is the id of the note This is the title of the note This is the body of the note This is the created date of the note This is the last modified date of the note ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/note' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", "title": "Note Title", "body": "Note Body", "created_date": "2020-01-01T00:00:00.000Z", "last_modified_date": "2020-01-01T00:00:00.000Z" }' ``` ```graphQL GraphQL theme={null} mutation addNote($note: notes_insert_input!) { insert_notes(objects: [$note]) { returning { id title body createdDate lastModifiedDate } } ``` ```js Node.js theme={null} const notes = await stateset.notes.update({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} notes = stateset.notes.update({ 'nt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} notes, err := stateset.notes.update( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} notes = Stateset::Notes.update( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} notes notes = Stateset.notes.update( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} notes notes = Stateset.notes.update( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $notes = Stateset\notes::update( 'nt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/note HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "notes": [ { "id": "nt_1NXWPnCo6bFb1KQto6C8OWvE", }, ] } ``` # Add Discount Source: https://docs.stateset.com/api-reference/orders/add-discount Add a discount to an order. # Add Discount Use this endpoint to apply a discount to an existing order. # Add Item to Order Source: https://docs.stateset.com/api-reference/orders/add-item POST https://api.stateset.com/v1/orders/:id/add-item This endpoint adds an item to an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/add-item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderAddItemMutation { orderAddItem(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.addItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.addItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.addItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.addItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.addItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->addItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.AddItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "added": true } ``` # Apply Discount Source: https://docs.stateset.com/api-reference/orders/apply-discount POST https://api.stateset.com/v1/orders/:id/apply-discount This endpoint applies a discount to an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/orders/:id/apply-discount' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderApplyDiscountMutation { orderApplyDiscount(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.applyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.applyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.applyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.applyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.applyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->applyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.ApplyDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "discount_applied": true } ``` # Apply Promotion Source: https://docs.stateset.com/api-reference/orders/apply-promotion POST https://api.stateset.com/v1/orders/:id/apply-promotion This endpoint applies a promotion to an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/apply-promotion' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderApplyPromotionMutation { orderApplyPromotion(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.applyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.applyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.applyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.applyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.applyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->applyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.ApplyPromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "applied": true } ``` # Cancel Order Source: https://docs.stateset.com/api-reference/orders/cancel POST https://api.stateset.com/v1/orders/:id/cancel This endpoint cancels an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderCancelMutation { orderCancel(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "cancelled": true } ``` # Create Order Source: https://docs.stateset.com/api-reference/orders/create POST https://api.stateset.com/v1/orders Create a new order with automatic inventory allocation and fulfillment workflow initiation This endpoint creates a new order and automatically triggers order processing workflows, including inventory allocation, payment processing, and fulfillment initiation. ## Authentication This endpoint requires a valid API key with `orders:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Customer information for the order Customer's email address Customer's first name Customer's last name Customer's phone number (E.164 format recommended) Existing customer ID if available Array of items in the order Product SKU Quantity ordered (must be positive) Unit price in cents (e.g., 1999 for \$19.99) Product name for display Product variant ID if applicable Additional item-specific metadata Shipping address for the order Street address line 1 Street address line 2 City name State/Province code (e.g., "CA", "NY") Postal/ZIP code ISO 3166-1 alpha-2 country code (e.g., "US", "CA") Billing address if different from shipping. If not provided, shipping address will be used. Same structure as shipping\_address Payment information Payment method: `card`, `paypal`, `apple_pay`, `google_pay`, `bank_transfer` Stripe PaymentIntent ID if using Stripe External payment transaction ID Shipping preferences Shipping method: `standard`, `express`, `overnight`, `economy` Preferred carrier: `ups`, `fedex`, `usps`, `dhl` Specific service level code Additional custom metadata to store with the order Unique key to ensure idempotent order creation ### Response Unique identifier for the created order Always "order" for this object type Human-readable order number (e.g., "ORD-2024-001234") Order status: `pending`, `processing`, `shipped`, `delivered`, `cancelled` Customer information associated with the order Array of order items with calculated totals Order totals breakdown Subtotal before tax and shipping (in cents) Total tax amount (in cents) Shipping cost (in cents) Total discount amount (in cents) Grand total (in cents) ISO 8601 timestamp of order creation ISO 8601 timestamp of last update ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/orders \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer": { "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe", "phone": "+1234567890" }, "items": [ { "sku": "TSHIRT-BLUE-L", "quantity": 2, "price": 1999, "name": "Blue T-Shirt (Large)" }, { "sku": "HAT-RED", "quantity": 1, "price": 1499, "name": "Red Baseball Cap" } ], "shipping_address": { "line1": "123 Main Street", "line2": "Apt 4B", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "payment": { "method": "card", "payment_intent_id": "pi_1234567890" }, "shipping": { "method": "standard", "carrier": "ups" }, "metadata": { "source": "web", "campaign": "summer-sale" } }' ``` ```graphQL GraphQL theme={null} mutation CreateOrder($input: OrderCreateInput!) { orderCreate(input: $input) { order { id orderNumber status customer { email firstName lastName } items { sku quantity price total } totals { subtotal tax shipping total } createdAt } userErrors { field message } } } ``` ```js Node.js theme={null} const order = await stateset.orders.create({ customer: { email: 'john.doe@example.com', first_name: 'John', last_name: 'Doe', phone: '+1234567890' }, items: [ { sku: 'TSHIRT-BLUE-L', quantity: 2, price: 1999, name: 'Blue T-Shirt (Large)' } ], shipping_address: { line1: '123 Main Street', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' }, payment: { method: 'card', payment_intent_id: 'pi_1234567890' } }); ``` ```python Python theme={null} order = stateset.orders.create( customer={ 'email': 'john.doe@example.com', 'first_name': 'John', 'last_name': 'Doe', 'phone': '+1234567890' }, items=[ { 'sku': 'TSHIRT-BLUE-L', 'quantity': 2, 'price': 1999, 'name': 'Blue T-Shirt (Large)' } ], shipping_address={ 'line1': '123 Main Street', 'city': 'San Francisco', 'state': 'CA', 'postal_code': '94105', 'country': 'US' }, payment={ 'method': 'card', 'payment_intent_id': 'pi_1234567890' } ) ``` ```ruby Ruby theme={null} order = Stateset::Order.create({ customer: { email: 'john.doe@example.com', first_name: 'John', last_name: 'Doe', phone: '+1234567890' }, items: [ { sku: 'TSHIRT-BLUE-L', quantity: 2, price: 1999, name: 'Blue T-Shirt (Large)' } ], shipping_address: { line1: '123 Main Street', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' }, payment: { method: 'card', payment_intent_id: 'pi_1234567890' } }) ``` ```go Go theme={null} order, err := stateset.Orders.Create(&stateset.OrderParams{ Customer: &stateset.CustomerParams{ Email: "john.doe@example.com", FirstName: "John", LastName: "Doe", Phone: "+1234567890", }, Items: []*stateset.OrderItemParams{ { SKU: "TSHIRT-BLUE-L", Quantity: 2, Price: 1999, Name: "Blue T-Shirt (Large)", }, }, ShippingAddress: &stateset.AddressParams{ Line1: "123 Main Street", City: "San Francisco", State: "CA", PostalCode: "94105", Country: "US", }, Payment: &stateset.PaymentParams{ Method: "card", PaymentIntentID: "pi_1234567890", }, }) ``` ```java Java theme={null} Map params = new HashMap<>(); params.put("customer", Map.of( "email", "john.doe@example.com", "first_name", "John", "last_name", "Doe", "phone", "+1234567890" )); params.put("items", List.of(Map.of( "sku", "TSHIRT-BLUE-L", "quantity", 2, "price", 1999, "name", "Blue T-Shirt (Large)" ))); params.put("shipping_address", Map.of( "line1", "123 Main Street", "city", "San Francisco", "state", "CA", "postal_code", "94105", "country", "US" )); params.put("payment", Map.of( "method", "card", "payment_intent_id", "pi_1234567890" )); Order order = stateset.orders().create(params); ``` ```php PHP theme={null} $order = $stateset->orders->create([ 'customer' => [ 'email' => 'john.doe@example.com', 'first_name' => 'John', 'last_name' => 'Doe', 'phone' => '+1234567890', ], 'items' => [ [ 'sku' => 'TSHIRT-BLUE-L', 'quantity' => 2, 'price' => 1999, 'name' => 'Blue T-Shirt (Large)', ], ], 'shipping_address' => [ 'line1' => '123 Main Street', 'city' => 'San Francisco', 'state' => 'CA', 'postal_code' => '94105', 'country' => 'US', ], 'payment' => [ 'method' => 'card', 'payment_intent_id' => 'pi_1234567890', ], ]); ``` ```csharp C# theme={null} var order = await stateset.Orders.CreateAsync(new OrderCreateParams { Customer = new CustomerParams { Email = "john.doe@example.com", FirstName = "John", LastName = "Doe", Phone = "+1234567890" }, Items = new List { new OrderItemParams { Sku = "TSHIRT-BLUE-L", Quantity = 2, Price = 1999, Name = "Blue T-Shirt (Large)" } }, ShippingAddress = new AddressParams { Line1 = "123 Main Street", City = "San Francisco", State = "CA", PostalCode = "94105", Country = "US" }, Payment = new PaymentParams { Method = "card", PaymentIntentId = "pi_1234567890" } }); ``` ```json Success Response theme={null} { "id": "ord_1a2b3c4d5e6f", "object": "order", "order_number": "ORD-2024-001234", "status": "processing", "customer": { "id": "cus_9z8y7x6w5v4u", "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe", "phone": "+1234567890" }, "items": [ { "id": "item_abc123", "sku": "TSHIRT-BLUE-L", "quantity": 2, "price": 1999, "name": "Blue T-Shirt (Large)", "total": 3998 }, { "id": "item_def456", "sku": "HAT-RED", "quantity": 1, "price": 1499, "name": "Red Baseball Cap", "total": 1499 } ], "shipping_address": { "line1": "123 Main Street", "line2": "Apt 4B", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "billing_address": { "line1": "123 Main Street", "line2": "Apt 4B", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "payment": { "method": "card", "payment_intent_id": "pi_1234567890", "status": "paid" }, "shipping": { "method": "standard", "carrier": "ups", "tracking_number": null, "estimated_delivery": "2024-01-22T00:00:00Z" }, "totals": { "subtotal": 5497, "tax": 482, "shipping": 799, "discount": 0, "total": 6778 }, "metadata": { "source": "web", "campaign": "summer-sale" }, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ``` ```json Error Response - Validation Error theme={null} { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Invalid request parameters", "details": { "items[0].quantity": "Quantity must be a positive integer", "customer.email": "Invalid email format" } } } ``` ```json Error Response - Inventory Unavailable theme={null} { "success": false, "error": { "code": "INVENTORY_UNAVAILABLE", "message": "Insufficient inventory for requested items", "details": { "unavailable_items": [ { "sku": "TSHIRT-BLUE-L", "requested": 2, "available": 1 } ] } } } ``` # Delete Order Source: https://docs.stateset.com/api-reference/orders/delete DELETE https://api.stateset.com/v1/orders/:id This endpoint deletes an order. Only draft or cancelled orders can be deleted. ### Path Parameters The unique identifier of the order to delete ### Query Parameters Force deletion even if there are related records (requires admin permission) Archive the order instead of deleting it (recommended for audit trail) ### Response The ID of the deleted order Indicates whether the order was successfully deleted Indicates if the order was archived instead of deleted Summary of related records affected Number of related payment records Number of related shipment records Number of related return records Number of related refund records Timestamp when the order was deleted User who deleted the order ### Error Responses Error object containing details about what went wrong Error code (e.g., "order\_not\_deletable", "order\_shipped", "active\_refunds") Human-readable error message Additional error details including order status and blockers ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/orders/ord_123abc' \ --header 'Authorization: Token ' ``` ```bash cURL (Archive Instead) theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/orders/ord_123abc?archive_instead=true' \ --header 'Authorization: Token ' ``` ```graphQL GraphQL theme={null} mutation orderDeleteMutation { orderDelete(id: "${orderId}", archiveInstead: false) { success order { id deleted } userErrors { field message } } } ``` ```js Node.js theme={null} const deletedOrder = await stateset.orders.delete('ord_123abc'); // Or archive instead const archivedOrder = await stateset.orders.delete('ord_123abc', { archive_instead: true }); ``` ```python Python theme={null} deleted_order = stateset.orders.delete('ord_123abc') # Or archive instead archived_order = stateset.orders.delete('ord_123abc', { 'archive_instead': True }) ``` ```ruby Ruby theme={null} deleted_order = Stateset::Order.delete('ord_123abc') # Or archive instead archived_order = Stateset::Order.delete('ord_123abc', { archive_instead: true }) ``` ```go Go theme={null} deletedOrder, err := stateset.Orders.Delete("ord_123abc") // Or archive instead archivedOrder, err := stateset.Orders.Delete("ord_123abc", DeleteOptions{ ArchiveInstead: true }) ``` ```java Java theme={null} Order deletedOrder = stateset.orders.delete("ord_123abc"); // Or archive instead DeleteOptions options = new DeleteOptions(); options.setArchiveInstead(true); Order archivedOrder = stateset.orders.delete("ord_123abc", options); ``` ```php PHP theme={null} $deleted_order = $stateset->orders->delete('ord_123abc'); // Or archive instead $archived_order = $stateset->orders->delete('ord_123abc', [ 'archive_instead' => true ]); ``` ```csharp C# theme={null} var deletedOrder = await stateset.Orders.Delete("ord_123abc"); // Or archive instead var archivedOrder = await stateset.Orders.Delete("ord_123abc", new DeleteOptions { ArchiveInstead = true }); ``` ```json Success Response theme={null} { "id": "ord_123abc", "deleted": true, "archived": false, "related_records": { "payments": 0, "shipments": 0, "returns": 0, "refunds": 0 }, "deleted_at": "2024-01-15T14:30:00Z", "deleted_by": "user_123" } ``` ```json Archive Response theme={null} { "id": "ord_123abc", "deleted": false, "archived": true, "status": "archived", "archived_at": "2024-01-15T14:30:00Z", "archived_by": "user_123", "archive_reason": "User requested archival instead of deletion" } ``` ```json Error Response - Order Shipped theme={null} { "error": { "code": "order_not_deletable", "message": "Cannot delete order that has been shipped. Only draft or cancelled orders can be deleted.", "details": { "order_id": "ord_123abc", "current_status": "shipped", "deletable_statuses": ["draft", "cancelled"], "suggestion": "Cancel the order first or archive it instead" } } } ``` ```json Error Response - Active Returns theme={null} { "error": { "code": "active_returns", "message": "Cannot delete order with active returns. Please resolve all returns first.", "details": { "order_id": "ord_123abc", "active_returns": 2, "return_ids": ["ret_456def", "ret_789ghi"] } } } ``` # Exchange Order Source: https://docs.stateset.com/api-reference/orders/exchange POST https://api.stateset.com/v1/orders/:id/exchange This endpoint exchanges an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/orders/:id/exchange' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderExchangeMutation { orderExchange(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Exchange({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "exchanged": true } ``` # Retrieve Order Source: https://docs.stateset.com/api-reference/orders/get GET https://api.stateset.com/v1/order/:id/retrieve This endpoint retrieves an order. ### Body This is the id of the order. ### Response This is the id of the order. This is the name of the order. This is the order number. This is the date the order was created. This is the date the order was last updated. This is the status of the order. This is the imported status of the order. This is the delivery date of the order. This is the person who ordered. This is the delivery address for the order. These are additional notes for the order. This is the date the order was imported. This is the customer number associated with the order. This is the name of the customer. This indicates if the order was imported. This is the email of the customer. This is the source of the order. This is the email of the buyer. This is a message from the buyer. This is the SLA time for cancelling the order. This is the reason for cancellation, if applicable. This is who initiated the cancellation, if applicable. This is the type of fulfillment for the order. This is the type of delivery for the order. This indicates if the order is cash on delivery. This indicates if this is a replacement order. This is a note from the seller. This is the current status of the order. This is the tracking number for the order. This is the id of the warehouse handling the order. These are the line items associated with the order. This is the id of the order line item. This is the id of the associated wholesale order. This is the name of the product. This is the quantity of the product ordered. This is the date the line item was created. This is the date the line item was last updated. This is the unit of measurement for the product. This is the id of the product. This is the brand of the product. This is the stock code of the product. This is the size of the product. This is the status of the line item. This is the sale price of the product. This is the discount offered by the seller. This is the seller's SKU for the product. This is the SKU id of the product. This is the image URL for the product SKU. This is the name of the product SKU. This is the type of the product SKU. This is the original price of the product. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/order/retrieve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "ord_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query ($id: UUID!) { order(id: $id) { id name order_number created_date updated_date order_status imported_status delivery_date ordered_by delivery_address notes imported_date customer_number customer_name import customer_email source buyer_email buyer_message cancel_order_sla_time cancel_reason cancellation_initiator fulfillment_type delivery_type is_cod is_replacement_order seller_note status tracking_number warehouse_id order_line_items { id wholesale_order_id product_name quantity created_date updated_date unit product_id brand stock_code size status sale_price seller_discount seller_sku sku_id sku_image sku_name sku_type original_price } } } ``` ```js Node.js theme={null} const order = await stateset.orders.retrieve('ord_1NXWPnCo6bFb1KQto6C8OWvE'); ``` ```py Python theme={null} order = stateset.orders.retrieve('ord_1NXWPnCo6bFb1KQto6C8OWvE') ``` ```go Golang theme={null} order, err := stateset.Orders.Retrieve("ord_1NXWPnCo6bFb1KQto6C8OWvE") ``` ```ruby Ruby theme={null} order = Stateset::Order.retrieve('ord_1NXWPnCo6bFb1KQto6C8OWvE') ``` ```java Java theme={null} Order order = Order.retrieve("ord_1NXWPnCo6bFb1KQto6C8OWvE"); ``` ```csharp C# theme={null} var order = Order.Retrieve("ord_1NXWPnCo6bFb1KQto6C8OWvE"); ``` ```php PHP theme={null} $order = $stateset->orders->retrieve('ord_1NXWPnCo6bFb1KQto6C8OWvE'); ``` ```http HTTP theme={null} GET /v1/order/ord_1NXWPnCo6bFb1KQto6C8OWvE HTTP/1.1 Host: api.stateset.com Content-Type: application/json Authorization: Bearer ``` ```json Response theme={null} { "order": { "id": "ord_1NXWPnCo6bFb1KQto6C8OWvE", "name": "Example Order", "order_number": "ORD-12345", "created_date": "2023-08-23T10:00:00Z", "updated_date": "2023-08-23T11:00:00Z", "order_status": "Processing", "imported_status": "Completed", "delivery_date": "2023-08-30T14:00:00Z", "ordered_by": "John Doe", "delivery_address": "123 Main St, Anytown, AN 12345", "notes": "Please handle with care", "imported_date": "2023-08-23T09:00:00Z", "customer_number": "CUST-6789", "customer_name": "John Doe", "import": true, "customer_email": "john.doe@example.com", "source": "Online Store", "buyer_email": "john.doe@example.com", "buyer_message": "Looking forward to receiving the order!", "cancel_order_sla_time": null, "cancel_reason": null, "cancellation_initiator": null, "fulfillment_type": "Standard", "delivery_type": "Home Delivery", "is_cod": false, "is_replacement_order": false, "seller_note": "Thank you for your order", "status": "Processing", "tracking_number": "TRACK-98765", "warehouse_id": "wh_2MXYQoDp7cGc2LRup7D9PXvF", "order_line_items": [ { "id": "oli_3OYZRpEq8dHd3MSvq8E0QYwG", "wholesale_order_id": "ord_1NXWPnCo6bFb1KQto6C8OWvE", "product_name": "Example Product", "quantity": "2", "created_date": "2023-08-23T10:05:00Z", "updated_date": "2023-08-23T10:05:00Z", "unit": "piece", "product_id": "prod_4PZaSqFr9eIe4NTwr9F1RZxH", "brand": "Example Brand", "stock_code": "EX-1234", "size": "Medium", "status": "In Stock", "sale_price": 2999, "seller_discount": 500, "seller_sku": "SKU-5678", "sku_id": "sku_6QAbTrGs0fJf5OUxs0G2SZyI", "sku_image": "https://example.com/images/product.jpg", "sku_name": "Example Product - Medium", "sku_type": "Standard", "original_price": 3499 } ] } } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Order not found", "details": { "resource": "order", "id": "ord_1a2b3c4d5e6f" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` # Hold Order Source: https://docs.stateset.com/api-reference/orders/hold POST https://api.stateset.com/v1/orders/:id/hold This endpoint holds an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/hold' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderHoldMutation { orderHold(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Hold({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "held": true } ``` # List Orders Source: https://docs.stateset.com/api-reference/orders/list GET https://api.stateset.com/v1/orders Retrieve orders with advanced filtering, pagination, and sorting capabilities This endpoint supports comprehensive filtering, pagination, and sorting. Use query parameters to efficiently retrieve the exact orders you need. ## Pagination Parameters Maximum number of orders to return per page. Range: 1-100. Number of orders to skip. Use for pagination. Cursor-based pagination token. More efficient for large datasets. ## Sorting Parameters Sort field. Options: `created_at`, `updated_at`, `order_number`, `total_amount`, `status`, `customer_email` Sort direction. Options: `asc`, `desc` ## Filter Parameters ### Status Filters Filter by order status. Options: `pending`, `processing`, `shipped`, `delivered`, `cancelled`, `refunded` Filter by multiple statuses. Example: `status_in=pending,processing` ### Date Filters Orders created after this date (ISO 8601 format: `2024-01-01T00:00:00Z`) Orders created before this date (ISO 8601 format: `2024-12-31T23:59:59Z`) Orders updated after this date Orders shipped after this date ### Customer Filters Filter by exact customer email Filter by customer ID Filter by customer tier. Options: `bronze`, `silver`, `gold`, `platinum` ### Financial Filters Orders with total amount greater than or equal to this value Orders with total amount less than or equal to this value Filter by currency code (ISO 4217). Example: `USD`, `EUR`, `GBP` ### Location Filters Filter by shipping country code (ISO 3166-1). Example: `US`, `CA`, `GB` Filter by shipping state/province Filter by fulfillment center ID ### Product Filters Filter orders containing specific SKU Filter orders containing products from specific category ### Source Filters Filter by order source. Options: `website`, `mobile_app`, `marketplace`, `phone`, `retail` Filter by sales channel ### Search Full-text search across order number, customer name, email, and product names ### Advanced Filters Filter orders that have associated returns Filter gift orders Filter by fraud risk level. Options: `low`, `medium`, `high` Filter by order priority. Options: `low`, `normal`, `high`, `urgent` ### Include Parameters Include related data. Options: `line_items`, `customer`, `shipping_address`, `billing_address`, `payments`, `returns`, `fulfillments` ### Response An array of order objects. This is the id of the order. This is the name of the order. This is the order number. This is the date the order was created. This is the date the order was last updated. This is the status of the order. This is the imported status of the order. This is the delivery date of the order. This is the person who ordered. This is the delivery address for the order. These are additional notes for the order. This is the date the order was imported. This is the customer number associated with the order. This is the name of the customer. This indicates if the order was imported. This is the email of the customer. This is the source of the order. This is the email of the buyer. This is a message from the buyer. This is the SLA time for cancelling the order. This is the reason for cancellation, if applicable. This is who initiated the cancellation, if applicable. This is the type of fulfillment for the order. This is the type of delivery for the order. This indicates if the order is cash on delivery. This indicates if this is a replacement order. This is a note from the seller. This is the current status of the order. This is the tracking number for the order. This is the id of the warehouse handling the order. These are the line items associated with the order. This is the id of the order line item. This is the id of the associated wholesale order. This is the name of the product. This is the quantity of the product ordered. This is the date the line item was created. This is the date the line item was last updated. This is the unit of measurement for the product. This is the id of the product. This is the brand of the product. This is the stock code of the product. This is the size of the product. This is the status of the line item. This is the sale price of the product. This is the discount offered by the seller. This is the seller's SKU for the product. This is the SKU id of the product. This is the image URL for the product SKU. This is the name of the product SKU. This is the type of the product SKU. This is the original price of the product. The total number of orders matching the query parameters. ```bash Basic Pagination theme={null} curl -X GET "https://api.stateset.com/v1/orders?limit=20&offset=0" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` ```bash Advanced Filtering theme={null} curl -X GET "https://api.stateset.com/v1/orders" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -G \ --data-urlencode "status_in=processing,shipped" \ --data-urlencode "created_after=2024-01-01T00:00:00Z" \ --data-urlencode "total_amount_gte=50.00" \ --data-urlencode "shipping_country=US" \ --data-urlencode "include=line_items,customer" \ --data-urlencode "sort=total_amount" \ --data-urlencode "order=desc" \ --data-urlencode "limit=50" ``` ```bash Search and Filter theme={null} curl -X GET "https://api.stateset.com/v1/orders" \ -H "Authorization: Bearer YOUR_API_KEY" \ -G \ --data-urlencode "search=john@example.com" \ --data-urlencode "status=delivered" \ --data-urlencode "created_after=2024-01-01" \ --data-urlencode "created_before=2024-01-31" ``` ```bash Cursor-based Pagination theme={null} curl -X GET "https://api.stateset.com/v1/orders?cursor=eyJpZCI6Im9yZF8xMjM0NSIsImNyZWF0ZWRfYXQiOiIyMDI0LTAxLTE1VDEwOjMwOjAwWiJ9&limit=25" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $sort: String!, $order: String!) { orders(limit: $limit, offset: $offset, sort: $sort, order: $order) { id name order_number created_date updated_date order_status imported_status delivery_date ordered_by delivery_address notes imported_date customer_number customer_name import customer_email source buyer_email buyer_message cancel_order_sla_time cancel_reason cancellation_initiator fulfillment_type delivery_type is_cod is_replacement_order seller_note status tracking_number warehouse_id order_line_items { id wholesale_order_id product_name quantity created_date updated_date unit product_id brand stock_code size status sale_price seller_discount seller_sku sku_id sku_image sku_name sku_type original_price } } total_count } ``` ```js Basic Pagination theme={null} const orders = await stateset.orders.list({ limit: 20, offset: 0, sort: 'created_at', order: 'desc' }); ``` ```js Advanced Filtering theme={null} const orders = await stateset.orders.list({ status_in: ['processing', 'shipped'], created_after: '2024-01-01T00:00:00Z', total_amount_gte: 50.00, shipping_country: 'US', include: ['line_items', 'customer'], sort: 'total_amount', order: 'desc', limit: 50 }); ``` ```js Pagination Helper Function theme={null} // Paginate through all orders async function getAllOrders(filters = {}) { const allOrders = []; let hasMore = true; let offset = 0; const limit = 100; while (hasMore) { const response = await stateset.orders.list({ ...filters, limit, offset }); allOrders.push(...response.orders); hasMore = response.orders.length === limit; offset += limit; // Add delay to respect rate limits if (hasMore) { await new Promise(resolve => setTimeout(resolve, 100)); } } return allOrders; } // Usage const allProcessingOrders = await getAllOrders({ status: 'processing', created_after: '2024-01-01' }); ``` ```js Cursor-based Pagination theme={null} // More efficient for large datasets async function getOrdersWithCursor(filters = {}) { const allOrders = []; let cursor = null; do { const response = await stateset.orders.list({ ...filters, cursor, limit: 100 }); allOrders.push(...response.orders); cursor = response.next_cursor; } while (cursor); return allOrders; } ``` ```js Real-time Filtering Example theme={null} // Filter orders dynamically based on user input class OrderFilter { constructor(client) { this.client = client; this.cache = new Map(); } async searchOrders(query) { const cacheKey = JSON.stringify(query); if (this.cache.has(cacheKey)) { return this.cache.get(cacheKey); } const filters = this.buildFilters(query); const orders = await this.client.orders.list(filters); // Cache for 5 minutes this.cache.set(cacheKey, orders); setTimeout(() => this.cache.delete(cacheKey), 300000); return orders; } buildFilters(query) { const filters = { limit: 50 }; if (query.search) { filters.search = query.search; } if (query.status && query.status.length > 0) { filters.status_in = query.status; } if (query.dateRange) { filters.created_after = query.dateRange.start; filters.created_before = query.dateRange.end; } if (query.amountRange) { if (query.amountRange.min) filters.total_amount_gte = query.amountRange.min; if (query.amountRange.max) filters.total_amount_lte = query.amountRange.max; } if (query.location) { filters.shipping_country = query.location.country; if (query.location.state) filters.shipping_state = query.location.state; } return filters; } } ``` ```py Python theme={null} orders = stateset.orders.list( limit=10, offset=0, sort='created_date', order='desc' ) ``` ```go Golang theme={null} orders, err := stateset.Orders.List(&stateset.OrderListParams{ Limit: 10, Offset: 0, Sort: "created_date", Order: "desc", }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.list( limit: 10, offset: 0, sort: 'created_date', order: 'desc' ) ``` ```java Java theme={null} OrderListParams params = new OrderListParams.Builder() .setLimit(10) .setOffset(0) .setSort("created_date") .setOrder("desc") .build(); OrderCollection orders = Order.list(params); ``` ```csharp C# theme={null} var orderListOptions = new OrderListOptions { Limit = 10, Offset = 0, Sort = "created_date", Order = "desc" }; var orders = Order.List(orderListOptions); ``` ```php PHP theme={null} $orders = $stateset->orders->list([ 'limit' => 10, 'offset' => 0, 'sort' => 'created_date', 'order' => 'desc' ]); ``` ```http HTTP theme={null} GET /v1/orders?limit=10&offset=0&sort=created_date&order=desc HTTP/1.1 Host: api.stateset.com Content-Type: application/json Authorization: Bearer ``` ```json Response theme={null} { "orders": [ { "id": "ord_1NXWPnCo6bFb1KQto6C8OWvE", "name": "Example Order 1", "order_number": "ORD-12345", "created_date": "2023-08-23T10:00:00Z", "updated_date": "2023-08-23T11:00:00Z", "order_status": "Processing", "imported_status": "Completed", "delivery_date": "2023-08-30T14:00:00Z", "ordered_by": "John Doe", "delivery_address": "123 Main St, Anytown, AN 12345", "notes": "Please handle with care", "imported_date": "2023-08-23T09:00:00Z", "customer_number": "CUST-6789", "customer_name": "John Doe", "import": true, "customer_email": "john.doe@example.com", "source": "Online Store", "buyer_email": "john.doe@example.com", "buyer_message": "Looking forward to receiving the order!", "cancel_order_sla_time": null, "cancel_reason": null, "cancellation_initiator": null, "fulfillment_type": "Standard", "delivery_type": "Home Delivery", "is_cod": false, "is_replacement_order": false, "seller_note": "Thank you for your order", "status": "Processing", "tracking_number": "TRACK-98765", "warehouse_id": "wh_2MXYQoDp7cGc2LRup7D9PXvF", "order_line_items": [ { "id": "oli_3OYZRpEq8dHd3MSvq8E0QYwG", "wholesale_order_id": "ord_1NXWPnCo6bFb1KQto6C8OWvE", "product_name": "Example Product", "quantity": "2", "created_date": "2023-08-23T10:05:00Z", "updated_date": "2023-08-23T10:05:00Z", "unit": "piece", "product_id": "prod_4PZaSqFr9eIe4NTwr9F1RZxH", "brand": "Example Brand", "stock_code": "EX-1234", "size": "Medium", "status": "In Stock", "sale_price": 2999, "seller_discount": 500, "seller_sku": "SKU-5678", "sku_id": "sku_6QAbTrGs0fJf5OUxs0G2SZyI", "sku_image": "https://example.com/images/product.jpg", "sku_name": "Example Product - Medium", "sku_type": "Standard", "original_price": 3499 } ] }, ], "total_count": 1, "has_more": false, "next_cursor": null, "has_more": false, "next_cursor": null, "filters_applied": { "status": "processing", "created_after": "2024-01-01T00:00:00Z" }, "pagination": { "current_page": 1, "per_page": 20, "total_pages": 1 } } ``` # Merge Order Source: https://docs.stateset.com/api-reference/orders/merge POST https://api.stateset.com/v1/orders/:id/merge This endpoint merges an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/merge' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderMergeMutation { orderMerge(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Merge({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "merged": true } ``` # Refund Order Source: https://docs.stateset.com/api-reference/orders/refund POST https://api.stateset.com/v1/orders/:id/refund This endpoint refunds an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/refund' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderRefundMutation { orderRefund(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Refund({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "refunded": true } ``` # Release Order Source: https://docs.stateset.com/api-reference/orders/release POST https://api.stateset.com/v1/orders/:id/release This endpoint releases an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/release' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderReleaseMutation { orderRelease(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Release({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "released": true } ``` # Remove Discount Source: https://docs.stateset.com/api-reference/orders/remove-discount POST https://api.stateset.com/v1/orders/:id/remove-discount This endpoint removes a discount from an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/orders/:id/remove-discount' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderRemoveDiscountMutation { orderRemoveDiscount(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.removeDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.removeDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.removeDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.removeDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.removeDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->removeDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.RemoveDiscount({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "discount_removed": true } ``` # Remove Item from Order Source: https://docs.stateset.com/api-reference/orders/remove-item POST https://api.stateset.com/v1/orders/:id/remove-item This endpoint removes an item from an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/remove-item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderRemoveItemMutation { orderRemoveItem(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.removeItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.removeItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.removeItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.removeItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.removeItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->removeItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.RemoveItem({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "removed": true } ``` # Remove Promotion Source: https://docs.stateset.com/api-reference/orders/remove-promotion POST https://api.stateset.com/v1/orders/:id/remove-promotion This endpoint removes a promotion from an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/remove-promotion' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderRemovePromotionMutation { orderRemovePromotion(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.removePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.removePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.removePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.removePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.removePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->removePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.RemovePromotion({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "removed": true } ``` # Return Order Source: https://docs.stateset.com/api-reference/orders/return POST https://api.stateset.com/v1/orders/:id/return This endpoint returns an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/orders/:id/return' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderReturnMutation { orderReturn(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Return({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "returned": true } ``` # Ship Order Source: https://docs.stateset.com/api-reference/orders/ship POST https://api.stateset.com/v1/orders/:id/ship This endpoint ships an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/ship' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderShipMutation { orderShip(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Ship({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "shipped": true } ``` # Split Order Source: https://docs.stateset.com/api-reference/orders/split POST https://api.stateset.com/v1/orders/:id/split This endpoint splits an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/split' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderSplitMutation { orderSplit(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Split({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "split": true } ``` # Tag Order Source: https://docs.stateset.com/api-reference/orders/tag POST https://api.stateset.com/v1/orders/:id/tag This endpoint tags an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/tag' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderTagMutation { orderTag(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Tag({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "tagged": true } ``` # Update Order Source: https://docs.stateset.com/api-reference/orders/update POST https://api.stateset.com/v1/orders/:id/update This endpoint updates an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/order/:id/update' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation orderUpdateMutation { orderUpdate(id: "${orderId}") { order { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const orders = await stateset.orders.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} orders = stateset.orders.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} orders = Stateset::Order.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} orders, err := stateset.Orders.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order orders = stateset.Orders.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $orders = $stateset->orders->update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var orders = await stateset.Orders.Update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "order", "updated": true } ``` # Overview Source: https://docs.stateset.com/api-reference/overview An introduction to the Stateset One Platform # Stateset One Platform Documentation ## Introduction to Stateset One Stateset One is an autonomous commerce operating system designed to streamline and optimize the entire commercial lifecycle for direct-to-consumer (DTC) merchants, warehouses, suppliers, and their developer partners. By unifying commerce, logistics, and finance operations, Stateset One enables seamless automation, efficient workflows, and data-driven decision-making. All platform features are accessible via GraphQL Mutations, Queries, and Subscriptions, and the solution is fully localized in English, Spanish, Catalan, Portuguese, French, Italian, Japanese, German, Dutch, and Romanian. ### Who Benefits from Stateset One? 1. **Direct-to-Consumer Merchants:**\ Ideal for brands looking to streamline operations, reduce manual processes, and drive growth with an agile and scalable finance and operations platform. 2. **Warehouses and Suppliers:**\ Enhance collaboration and efficiency with DTC merchants. Stateset One simplifies financial and operational workflows, making it easier to manage, fulfill, and optimize supply chain activities. 3. **Developers and Technical Partners:**\ Built with developers in mind, Stateset One’s modern, interoperable platform supports flexible integrations and smooth development experiences—perfect for agencies and technical teams working with commerce clients. ## Stateset Home & Onboarding ### Stateset Dashboard #### Examples of Challenges Stateset One Solves * **Manual Data Entry Across Multiple Apps** * *Problem:* Merchants often juggle different applications to handle orders, shipping, returns, and other tasks, manually updating each system. * *Solution:* Stateset One centralizes and automates reverse logistics and refund processing, eliminating manual entry. * *Value:* Save time, reduce errors, and minimize operational costs. * *Benefit:* Focus on strategic growth rather than repetitive administrative tasks. ## Core Features * **3-Factor App Architecture with Durable Execution OS**\ Built to ensure reliability, resilience, and long-term maintainability. * **Single Point GraphQL API Remote Data Joins**\ Seamlessly integrate and query data across multiple sources through a unified GraphQL endpoint. * **Event Triggers and Webhooks**\ Automate responses to system events and integrate with external applications effortlessly. * **Real-Time Global Search**\ Empower customer service and warehouse teams with instant access to the data they need. * **Data Validation and Synchronization**\ Ensure data accuracy, consistency, and compliance across all connected systems. * **Workflow Orchestration with Temporal**\ Automate, monitor, and optimize complex intercompany and operational processes. * **Event-Driven Automation**\ Trigger workflows, notifications, and actions based on business events—no more manual intervention. * **Automated Label Printing & Refund Processing**\ Streamline shipping, returns, and financial workflows to boost efficiency and reduce errors. * **Tested QA Paths for Serverless Functions**\ Reliably scale operations and integrations with thoroughly tested serverless components. ## Stateset One Value Proposition 1. **Modern, Agile Technology:**\ Built on next-generation frameworks and distributed consensus protocols, Stateset One replaces outdated, siloed systems with a cutting-edge, integrated approach. 2. **Streamlined Workflows:**\ Automating intercompany processes dramatically reduces coordination time, allowing merchants, suppliers, and agencies to operate faster and more efficiently. 3. **Scalability and Adaptability:**\ Grow without accumulating technical debt. Stateset One’s scalable architecture supports evolving business models and ever-increasing volumes of data. 4. **Developer-Friendly Infrastructure:**\ Designed for integrators, the platform supports seamless third-party integrations, empowering technical partners to deliver robust solutions. 5. **Robust and Reliable:**\ Leveraging proven technologies and cloud services, Stateset One ensures reliability, security, and long-term stability for all customers. By centralizing, automating, and optimizing commerce operations, Stateset One delivers tangible value, allowing businesses and their partners to focus on innovation, customer satisfaction, and growth. # Create Packing List Source: https://docs.stateset.com/api-reference/packinglist/create POST https://api.stateset.com/v1/packing_lists This endpoint creates a new packing_list ### Body The id of the packing\_list to be created. If not provided, a new id will be generated. The number of the packing\_list to be created. If not provided, a new number will be generated. The deliveryDate of the packing\_list to be created. If not provided, a new deliveryDate will be generated. The invoice\_number of the packing\_list to be created. If not provided, a new invoice\_number will be generated. The arrivalDate of the packing\_list to be created. If not provided, a new arrivalDate will be generated. The purchase\_order\_number of the packing\_list to be created. If not provided, a new purchase\_order\_number will be generated. The ship\_per of the packing\_list to be created. If not provided, a new ship\_per will be generated. The tracking\_number of the packing\_list to be created. If not provided, a new tracking\_number will be generated. ### Response This is the unique identifier for the packing list. This is the number associated with the packing list. This is the date of delivery for the packing list. This is the invoice number associated with the packing list. This is the date of arrival for the packing list. This is the purchase order number associated with the packing list. This is the shipping information or carrier for the packing list. This is the tracking number associated with the shipment for the packing list. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/packing_list' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.packinglist.create({ id: '' }); ``` ```json Response theme={null} { "id": "1", "number": "1", "deliveryDate": "2020-01-01", "arrivalDate": "2020-01-01", "ship_per": "John Doe", "tracking_number": "1234567890" } ``` # Delete Packing List Source: https://docs.stateset.com/api-reference/packinglist/delete DELETE https://api.stateset.com/v1/packing_lists/:id This endpoint deletes an existing packing_list. ### Body The id of the packing\_list to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/packing_lists/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```javascript Node.js theme={null} const deleted = await stateset.packinglists.del( 'pl_ODkRWQtx9NVsRX' ); ``` ```graphQL GraphQL theme={null} mutation deletePackingList ($packing_list_id: String!) { delete_packing_list(where: {id: {_eq: $packing_list_id}}) { affected_rows } } ``` ```python Python theme={null} deleted = stateset.packinglists.del( 'pl_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} deleted = Stateset::PackingLists.del( 'pl_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $deleted = $stateset->packinglists->del( 'pl_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} deleted, err := stateset.PackingLists.Del( 'pl_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} PackingLists deleted = stateset.packinglists.del( 'pl_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "id": "pl_1NXWPnCo6bFb1KQto6C8OWvE", "object": "packinglist", "deleted": true } ``` # Get Packing List Source: https://docs.stateset.com/api-reference/packinglist/get GET https://api.stateset.com/v1/packing_lists/:id This endpoint gets or creates a new packing list. ### Body This is the unique identifier for the packing list. If this is not provided, a new packing list will be created. ### Response This is the unique identifier for the packing list. This is the number associated with the packing list. This is the date of delivery for the packing list. This is the invoice number associated with the packing list. This is the date of arrival for the packing list. This is the purchase order number associated with the packing list. This is the shipping information or carrier for the packing list. This is the tracking number associated with the shipment for the packing list. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/packing_lists/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", }' ``` ```graphQL GraphQL theme={null} mutation addPackingList($packing_list: packing_list_insert_input!) { insert_packing_list(objects: [$packing_list]) { returning { id number deliveryDate arrivalDate ship_per tracking_number } } } ``` ```javascript Node.js theme={null} var packinglists = await stateset.packinglists.retreive({ id: "1" }); ``` ```python Python theme={null} packinglists = stateset.packinglists.retreive({ "id": "1" }) ``` ```ruby Ruby theme={null} packinglists = Stateset::PackingLists.retreive({ "id": "1" }) ``` ```php PHP theme={null} $packinglists = $stateset->packinglists->retreive([ "id" => "1" ]); ``` ```go Go theme={null} packinglists, err := stateset.PackingLists.Retreive("1") ``` ```java Java theme={null} PackingLists packinglists = stateset.packinglists.retreive({ "id": "1" }); ``` ```json Response theme={null} { "id": "1", "number": "1", "deliveryDate": "2020-01-01", "arrivalDate": "2020-01-01", "ship_per": "John Doe", "tracking_number": "1234567890" } ``` ## Packing List | Name | Type | Description | | ----------------------- | -------------------------- | ----------------------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the packing list | | number | Text (Nullable) | Number associated with the packing list | | deliveryDate | Date (Nullable) | Date of delivery for the packing list | | invoice\_number | Text (Nullable) | Invoice number associated with the packing list | | arrivalDate | Date (Nullable) | Date of arrival for the packing list | | purchase\_order\_number | Text (Nullable) | Purchase order number associated with the packing list | | ship\_per | Text (Nullable) | Shipping information or carrier for the packing list | | tracking\_number | Text (Nullable) | Tracking number associated with the shipment for the packing list | ## Packing List Item | Name | Type | Description | | ------------- | -------------------------- | -------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the packing list item | | sku | Text | Stock Keeping Unit (SKU) for the packing list item | | description | Text | Description or additional details about the item | | quantity | Integer | Quantity of the item in the packing list item | | packing\_list | Text | Identifier for the associated packing list | | arrived | Boolen | Whether or not the packing list item has arrived | # List Packing List Source: https://docs.stateset.com/api-reference/packinglist/list GET https://api.stateset.com/v1/packing_list/:id This endpoint list packing lists. ### Body This is the limit of the packing lists. This is the offset of the packing lists. This is the order direction of the packing lists. ### Response This is the unique identifier for the packing list. This is the number associated with the packing list. This is the date of delivery for the packing list. This is the invoice number associated with the packing list. This is the date of arrival for the packing list. This is the purchase order number associated with the packing list. This is the shipping information or carrier for the packing list. This is the tracking number associated with the shipment for the packing list. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/packing_lists/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { packing_lists(limit: $limit, offset: $offset, order_by: {createdDate: $order_direction}) { id number deliveryDate arrivalDate ship_per tracking_number } } ``` ```javascript Node.js theme={null} var packinglists = await stateset.packinglists.retreive({ id: "1" }); ``` ```python Python theme={null} packinglists = stateset.packinglists.retreive({ "id": "1" }) ``` ```ruby Ruby theme={null} packinglists = Stateset::PackingLists.retreive({ "id": "1" }) ``` ```php PHP theme={null} $packinglists = $stateset->packinglists->retreive([ "id" => "1" ]); ``` ```go Go theme={null} packinglists, err := stateset.PackingLists.Retreive("1") ``` ```java Java theme={null} PackingLists packinglists = stateset.packinglists.retreive({ "id": "1" }); ``` ```json Response theme={null} { "id": "1", "number": "1", "deliveryDate": "2020-01-01", "arrivalDate": "2020-01-01", "ship_per": "John Doe", "tracking_number": "1234567890" } ``` ## Packing List | Name | Type | Description | | ----------------------- | -------------------------- | ----------------------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the packing list | | number | Text (Nullable) | Number associated with the packing list | | deliveryDate | Date (Nullable) | Date of delivery for the packing list | | invoice\_number | Text (Nullable) | Invoice number associated with the packing list | | arrivalDate | Date (Nullable) | Date of arrival for the packing list | | purchase\_order\_number | Text (Nullable) | Purchase order number associated with the packing list | | ship\_per | Text (Nullable) | Shipping information or carrier for the packing list | | tracking\_number | Text (Nullable) | Tracking number associated with the shipment for the packing list | ## Packing List Item | Name | Type | Description | | ------------- | -------------------------- | -------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the packing list item | | sku | Text | Stock Keeping Unit (SKU) for the packing list item | | description | Text | Description or additional details about the item | | quantity | Integer | Quantity of the item in the packing list item | | packing\_list | Text | Identifier for the associated packing list | | arrived | Boolen | Whether or not the packing list item has arrived | # Update Packing List Source: https://docs.stateset.com/api-reference/packinglist/update PUT https://api.stateset.com/v1/packing_lists/:id This endpoint updates an existing packing_list. ### Body The id of the packing\_list to be created. If not provided, a new id will be generated. The number of the packing\_list to be created. If not provided, a new number will be generated. The deliveryDate of the packing\_list to be created. If not provided, a new deliveryDate will be generated. The invoice\_number of the packing\_list to be created. If not provided, a new invoice\_number will be generated. The arrivalDate of the packing\_list to be created. If not provided, a new arrivalDate will be generated. The purchase\_order\_number of the packing\_list to be created. If not provided, a new purchase\_order\_number will be generated. The ship\_per of the packing\_list to be created. If not provided, a new ship\_per will be generated. The tracking\_number of the packing\_list to be created. If not provided, a new tracking\_number will be generated. ### Response This is the unique identifier for the packing list. This is the number associated with the packing list. This is the date of delivery for the packing list. This is the invoice number associated with the packing list. This is the date of arrival for the packing list. This is the purchase order number associated with the packing list. This is the shipping information or carrier for the packing list. This is the tracking number associated with the shipment for the packing list. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/packing_list/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```graphQL GraphQL theme={null} mutation ( $id: String $packing_list: packing_list_set_input! ) { update_packing_list ( where: { id : { _eq: $id }} _set: $packing_list ) { returning { id number arrivalDate deliveryDate ship_per shipment_type invoice_number purchase_order_number tracking_number status source destination units } } } ``` ```javascript Node.js theme={null} const updated = await stateset.packinglists.update( 'pi_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "id": "1", "number": "1", "deliveryDate": "2020-01-01", "arrivalDate": "2020-01-01", "ship_per": "John Doe", "tracking_number": "1234567890" } ``` # Create Packing List Item Source: https://docs.stateset.com/api-reference/packinglistitem/create POST https://api.stateset.com/v1/packing_list_items/:id This endpoint creates a new packing list item ### Body The ID of the packing list item to create. The SKU of the packing list item to create. The description of the packing list item to create. The quantity of the packing list item to create. The packing list of the packing list item to create. The arrived of the packing list item to create. ### Response The ID of the packing list item to create. The SKU of the packing list item to create. The description of the packing list item to create. The quantity of the packing list item to create. The packing list of the packing list item to create. The arrived of the packing list item to create. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/packing_list_item/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "pi_ODkRWQtx9NVsRX", "sku": "sku_1", "description": "description_1", "quantity": 1, "packing_list": "pl_1", "arrived": true }' ``` ```js Node.js theme={null} const created = await stateset.packingItems.create( 'pi_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "id": "pi_ODkRWQtx9NVsRX", "sku": "sku_1", "description": "description_1", "quantity": 1, "packing_list": "pl_1", "arrived": true } ``` ## Packing List Item | Name | Type | Description | | ------------- | -------------------------- | -------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the packing list item | | sku | Text | Stock Keeping Unit (SKU) for the packing list item | | description | Text | Description or additional details about the item | | quantity | Integer | Quantity of the item in the packing list item | | packing\_list | Text | Identifier for the associated packing list | | arrived | Boolen | Whether or not the packing list item has arrived | # Delete Packing List Item Source: https://docs.stateset.com/api-reference/packinglistitem/delete DELETE https://api.stateset.com/v1/packing_list_items/:id This endpoint deletes an existing packing list item. ### Body The ID of the packing list item to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/packing_list_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```javascript Node.js theme={null} const deleted = await stateset.packingItems.del( 'pi_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} deleted = stateset.packingItems.del( 'pi_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} deleted = Stateset::PackingItems.del( 'pi_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $deleted = $stateset->packingItems->del( 'pi_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} deleted, err := stateset.PackingItems.Del( 'pi_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} PackingItems deleted = stateset.packingItems.del( 'pi_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "success": 1 } ``` # Get Packing List Item Source: https://docs.stateset.com/api-reference/packinglistitem/get GET https://api.stateset.com/v1/packing_list_items/:id This endpoint gets or creates a new packing list item. ### Body This is the id of the packing list item ### Response This is the id of the packing list item This is the sku of the packing list item This is the description of the packing list item This is the quantity of the packing list item This is the packing list of the packing list item This is the arrived of the packing list item ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/packing_list_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", }' ``` ```json Response theme={null} { { "id": "1", "sku": "1", "description": "1", "quantity": 1, "packing_list": "1", "arrived": true } } ``` ## Packing List Item | Name | Type | Description | | ------------- | -------------------------- | -------------------------------------------------- | | id | Text (Primary Key, Unique) | Unique identifier for the packing list item | | sku | Text | Stock Keeping Unit (SKU) for the packing list item | | description | Text | Description or additional details about the item | | quantity | Integer | Quantity of the item in the packing list item | | packing\_list | Text | Identifier for the associated packing list | | arrived | Boolen | Whether or not the packing list item has arrived | # Update Packing List Item Source: https://docs.stateset.com/api-reference/packinglistitem/update PUT https://api.stateset.com/v1/packing_list_items/:id This endpoint updates an existing packing list item. ### Body The ID of the packing list item to update. The SKU of the packing list item to update. The description of the packing list item to update. The quantity of the packing list item to update. The packing list of the packing list item to update. The arrived of the packing list item to update. ### Response The ID of the packing list item to update. The SKU of the packing list item to update. The description of the packing list item to update. The quantity of the packing list item to update. The packing list of the packing list item to update. The arrived of the packing list item to update. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/packing_list_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", "sku": "1", "description": "1", "quantity": 1, "packing_list": "1", "arrived": true }' ``` ```json Response theme={null} { "id": "1", "sku": "1", "description": "1", "quantity": 1, "packing_list": "1", "arrived": true } ``` # Capture Payment Source: https://docs.stateset.com/api-reference/payments/capture POST https://api.stateset.com/v1/payments/:id/capture Capture a previously authorized payment This endpoint captures a previously authorized payment. Only payments created with `capture: false` can be captured. ## Authentication This endpoint requires a valid API key with `payments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The payment ID to capture ## Request Body Amount to capture in cents (defaults to full authorization amount) Text for customer's statement (max 22 chars) Additional metadata to attach to the capture ### Response Returns the captured payment object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/payments/pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/capture' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "amount": 15000 }' ``` ```javascript Node.js theme={null} const payment = await stateset.payments.capture( 'pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { amount: 15000 } ); ``` ```python Python theme={null} payment = stateset.payments.capture( 'pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', amount=15000 ) ``` ```json Response theme={null} { "id": "pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "payment", "amount": 15000, "amount_capturable": 0, "amount_captured": 15000, "currency": "USD", "status": "succeeded", "captured": true, "captured_at": "2024-01-19T16:00:00Z", "created_at": "2024-01-19T15:30:00Z", "payment_method": { "type": "card", "card": { "last4": "4242", "brand": "visa" } }, "capture_details": { "captured_amount": 15000, "capture_time": "2024-01-19T16:00:00Z", "processor_capture_id": "ch_capture_123456" } } ``` # Create Payment Source: https://docs.stateset.com/api-reference/payments/create POST https://api.stateset.com/v1/payments Process a payment for an order or invoice This endpoint processes payments through various payment methods and gateways. It supports credit cards, ACH, wire transfers, and digital wallets. ## Authentication This endpoint requires a valid API key with `payments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Payment amount in cents (e.g., 1000 for \$10.00) ISO 4217 currency code (e.g., "USD", "EUR") Payment method details Payment type: "card", "ach", "wire", "paypal", "crypto" Credit/debit card details (for type: "card") Card number (will be tokenized) Expiration month (1-12) Expiration year (4 digits) Card verification code Pre-tokenized card token (alternative to raw card data) ACH bank transfer details (for type: "ach") Bank account number Bank routing number Account type: "checking" or "savings" Associated order ID Associated invoice ID Customer ID making the payment Payment description Text to appear on customer's statement (max 22 chars) Whether to immediately capture the payment (default: true) Billing address for verification Street address Apartment/Suite number City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Additional custom fields ### Response Returns the created payment with processing status. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/payments' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "amount": 15000, "currency": "USD", "payment_method": { "type": "card", "card": { "token": "tok_1234567890abcdef" } }, "order_id": "order_123456", "customer_id": "cust_abc123", "description": "Payment for Order #123456", "capture": true }' ``` ```javascript Node.js theme={null} const payment = await stateset.payments.create({ amount: 15000, currency: "USD", payment_method: { type: "card", card: { token: "tok_1234567890abcdef" } }, order_id: "order_123456", customer_id: "cust_abc123", description: "Payment for Order #123456", capture: true }); ``` ```json Response theme={null} { "id": "pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "payment", "amount": 15000, "currency": "USD", "status": "succeeded", "captured": true, "created_at": "2024-01-19T15:30:00Z", "payment_method": { "type": "card", "card": { "last4": "4242", "brand": "visa", "exp_month": 12, "exp_year": 2025, "fingerprint": "Xt5EWLLDS7FJjR1c" } }, "order_id": "order_123456", "customer_id": "cust_abc123", "description": "Payment for Order #123456", "receipt_url": "https://receipts.stateset.com/pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "processor_response": { "approved": true, "authorization_code": "123456", "avs_result": "Y", "cvv_result": "M", "network_transaction_id": "123456789" } } ``` # Get Payment Source: https://docs.stateset.com/api-reference/payments/get GET https://api.stateset.com/v1/payments/:id Retrieve a specific payment by ID This endpoint retrieves detailed information about a specific payment including transaction details and processing status. ## Authentication This endpoint requires a valid API key with `payments:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the payment ## Query Parameters Expand related objects. Options: "customer", "order", "invoice", "refunds", "disputes" ### Response Unique payment identifier Object type, always "payment" Payment amount in cents ISO 4217 currency code Payment status: "pending", "processing", "succeeded", "failed", "cancelled" Payment method details Response from payment processor ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/payments/pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const payment = await stateset.payments.retrieve( 'pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} payment = stateset.payments.retrieve( 'pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "payment", "amount": 15000, "currency": "USD", "status": "succeeded", "captured": true, "created_at": "2024-01-19T15:30:00Z", "updated_at": "2024-01-19T15:30:05Z", "payment_method": { "type": "card", "card": { "last4": "4242", "brand": "visa", "exp_month": 12, "exp_year": 2025, "fingerprint": "Xt5EWLLDS7FJjR1c", "country": "US", "funding": "credit" } }, "order_id": "order_123456", "invoice_id": null, "customer_id": "cust_abc123", "customer": { "id": "cust_abc123", "email": "john.doe@example.com", "name": "John Doe" }, "description": "Payment for Order #123456", "statement_descriptor": "STATESET ORDER", "receipt_url": "https://receipts.stateset.com/pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "receipt_number": "2234-5678", "billing_address": { "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "processor_response": { "approved": true, "authorization_code": "123456", "avs_result": "Y", "cvv_result": "M", "network_transaction_id": "123456789", "processor": "stripe", "risk_score": 32 }, "refunds": { "total_refunded": 0, "has_more": false, "data": [] }, "metadata": { "order_reference": "ORD-2024-001", "channel": "web" } } ``` # List Payments Source: https://docs.stateset.com/api-reference/payments/list GET https://api.stateset.com/v1/payments List all payments with filtering and pagination This endpoint retrieves a paginated list of payments. Use filters to narrow results by status, date range, amount, and more. ## Authentication This endpoint requires a valid API key with `payments:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of items to return (default: 20, max: 100) Cursor for pagination (payment ID) Cursor for reverse pagination (payment ID) Filter by status: "pending", "processing", "succeeded", "failed", "cancelled" Filter by customer ID Filter by order ID Filter by invoice ID Filter by payment method: "card", "ach", "wire", "paypal" Filter by creation date start (ISO 8601) Filter by creation date end (ISO 8601) Minimum amount in cents Maximum amount in cents Filter by currency code ### Response Object type, always "list" Array of payment objects Whether more items exist ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/payments?status=succeeded&limit=10' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const payments = await stateset.payments.list({ status: 'succeeded', limit: 10, created_from: '2024-01-01' }); ``` ```python Python theme={null} payments = stateset.payments.list( status='succeeded', limit=10, created_from='2024-01-01' ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "payment", "amount": 15000, "currency": "USD", "status": "succeeded", "created_at": "2024-01-19T15:30:00Z", "payment_method": { "type": "card", "card": { "last4": "4242", "brand": "visa" } }, "customer_id": "cust_abc123", "order_id": "order_123456", "description": "Payment for Order #123456" }, { "id": "pay_7823f083-bb2c-54d6-bf6d-1b8e3fc75f41", "object": "payment", "amount": 25000, "currency": "USD", "status": "succeeded", "created_at": "2024-01-19T12:15:00Z", "payment_method": { "type": "ach", "ach": { "last4": "6789", "bank_name": "Chase" } }, "customer_id": "cust_def456", "invoice_id": "inv_789012", "description": "Invoice payment" } ], "has_more": true, "url": "/v1/payments" } ``` # Refund Payment Source: https://docs.stateset.com/api-reference/payments/refund POST https://api.stateset.com/v1/payments/:id/refund Create a full or partial refund for a payment This endpoint creates a refund for a captured payment. Refunds can be partial or full amount. ## Authentication This endpoint requires a valid API key with `payments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The payment ID to refund ## Request Body Amount to refund in cents (defaults to full payment amount) Refund reason: "duplicate", "fraudulent", "requested\_by\_customer", "defective", "other" Internal notes about the refund Whether to send refund notification email (default: true) Additional metadata for the refund ### Response Returns the refund object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/payments/pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/refund' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "amount": 5000, "reason": "requested_by_customer", "notes": "Customer returned item" }' ``` ```javascript Node.js theme={null} const refund = await stateset.payments.refund( 'pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { amount: 5000, reason: "requested_by_customer", notes: "Customer returned item" } ); ``` ```python Python theme={null} refund = stateset.payments.refund( 'pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', amount=5000, reason="requested_by_customer", notes="Customer returned item" ) ``` ```json Response theme={null} { "id": "ref_1234567890abcdef", "object": "refund", "amount": 5000, "currency": "USD", "payment_id": "pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "status": "succeeded", "reason": "requested_by_customer", "notes": "Customer returned item", "created_at": "2024-01-20T10:00:00Z", "processed_at": "2024-01-20T10:00:05Z", "payment": { "id": "pay_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "amount": 15000, "amount_refunded": 5000, "refunds_count": 1 }, "processor_refund_id": "re_1234567890", "receipt_url": "https://receipts.stateset.com/ref_1234567890abcdef", "metadata": { "return_id": "ret_abc123" } } ``` # Create Picks Source: https://docs.stateset.com/api-reference/picks/create POST https://api.stateset.com/v1/picks This endpoint creates a new picks ### Body The id of the packing\_list to be created. If not provided, a new id will be generated. The number of the packing\_list to be created. If not provided, a new number will be generated. The delivery date of the packing\_list to be created. If not provided, a new delivery date will be generated. The arrival date of the packing\_list to be created. If not provided, a new arrival date will be generated. The ship per of the packing\_list to be created. If not provided, a new ship per will be generated. The tracking number of the packing\_list to be created. If not provided, a new tracking number will be generated. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/packing_list' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.packinglist.create({ id: '' }); ``` ```json Response theme={null} { "id": "1", "number": "1", "deliveryDate": "2020-01-01", "arrivalDate": "2020-01-01", "ship_per": "John Doe", "tracking_number": "1234567890" } ``` # Delete Pick Source: https://docs.stateset.com/api-reference/picks/delete DELETE https://api.stateset.com/v1/picks/:id This endpoint deletes an existing pick. ### Body The id of the pick to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/picks/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "pl_ODkRWQtx9NVsRX" }' ``` ```javascript Node.js theme={null} const deleted = await stateset.picks.del( 'pl_ODkRWQtx9NVsRX' ); ``` ```graphQL GraphQL theme={null} mutation deletePicks ($pick_id: String!) { delete_picks(where: {id: {_eq: $pick_id}}) { affected_rows } } ``` ```python Python theme={null} deleted = stateset.picks.del( 'pl_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} deleted = Stateset::picks.del( 'pl_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $deleted = $stateset->picks->del( 'pl_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} deleted, err := stateset.picks.Del( 'pl_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} picks deleted = stateset.picks.del( 'pl_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "id": "pi_1NXWPnCo6bFb1KQto6C8OWvE", "object": "picks", "deleted": true } ``` # Get Pick Source: https://docs.stateset.com/api-reference/picks/get GET https://api.stateset.com/v1/picks This endpoint gets a pick ### Body This is the unique identifier for the pick. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/picks' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", }' ``` ```graphQL GraphQL theme={null} query MyPicks { picks { id number date_created bill_of_materials_number location pick_method site status work_order_number pick_line_items { id part_name part_number pick_number pick_plan quantity_picked quantity_to_pick status } } } ``` ```javascript Node.js theme={null} var picks = await stateset.picks.retreive({ id: "1" }); ``` ```python Python theme={null} pickss = stateset.picks.retreive({ "id": "1" }) ``` ```ruby Ruby theme={null} picks = Stateset::Picks.retreive({ "id": "1" }) ``` ```php PHP theme={null} $picks = $stateset->picks->retreive([ "id" => "1" ]); ``` ```go Go theme={null} picks, err := stateset.Picks.Retreive("1") ``` ```java Java theme={null} Picks picks = stateset.picks.retreive({ "id": "1" }); ``` ```json Response theme={null} { "id": "1", "number": "1", "date_created": "2021-01-01T00:00:00Z", "bill_of_materials_number": "1", "location": "1", "pick_method": "1", "site": "1", "status": "1", "work_order_number": "1", "pick_line_items": [ { "id": "1", "part_name": "1", "part_number": "1", "pick_number": "1", "pick_plan": "1", "quantity_picked": "1", "quantity_to_pick": "1", "status": "1" } ] } ``` ## Picks # List Picks Source: https://docs.stateset.com/api-reference/picks/list GET https://api.stateset.com/v1/picks This endpoint gets a pick ### Body This is the limit of the picks. This is the offset of the picks. This is the order direction of the picks. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/picks' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1", }' ``` ```graphQL GraphQL theme={null} query MyPicks { picks { id number date_created bill_of_materials_number location pick_method site status work_order_number pick_line_items { id part_name part_number pick_number pick_plan quantity_picked quantity_to_pick status } } } ``` ```javascript Node.js theme={null} var picks = await stateset.picks.list({ id: "1" }); ``` ```python Python theme={null} pickss = stateset.picks.list({ "id": "1" }) ``` ```ruby Ruby theme={null} picks = Stateset::Picks.list({ "id": "1" }) ``` ```php PHP theme={null} $picks = $stateset->picks->list([ "id" => "1" ]); ``` ```go Go theme={null} picks, err := stateset.Picks.list("1") ``` ```java Java theme={null} Picks picks = stateset.picks.list({ "id": "1" }); ``` ```json Response theme={null} { "id": "1", "number": "1", "date_created": "2021-01-01T00:00:00Z", "bill_of_materials_number": "1", "location": "1", "pick_method": "1", "site": "1", "status": "1", "work_order_number": "1", "pick_line_items": [ { "id": "1", "part_name": "1", "part_number": "1", "pick_number": "1", "pick_plan": "1", "quantity_picked": "1", "quantity_to_pick": "1", "status": "1" } ] } ``` ## Picks # Update Pick Source: https://docs.stateset.com/api-reference/picks/update POST https://api.stateset.com/v1/picks/update This endpoint updates a pick ### Body The id of the packing\_list to be created. If not provided, a new id will be generated. The number of the packing\_list to be created. If not provided, a new number will be generated. The date\_created of the packing\_list to be created. If not provided, a new date\_created will be generated. The bill\_of\_materials\_number of the packing\_list to be created. If not provided, a new bill\_of\_materials\_number will be generated. The location of the packing\_list to be created. If not provided, a new location will be generated. The pick\_method of the packing\_list to be created. If not provided, a new pick\_method will be generated. The site of the packing\_list to be created. If not provided, a new site will be generated. The status of the packing\_list to be created. If not provided, a new status will be generated. The work\_order\_number of the packing\_list to be created. If not provided, a new work\_order\_number will be generated. ### Response This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick This is the unique identifier for the pick ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/packing_list' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```javascript Node.js theme={null} var created = await stateset.packinglist.create({ id: '' }); ``` ```json Response theme={null} { "id": "1", "number": "1", "deliveryDate": "2020-01-01", "arrivalDate": "2020-01-01", "ship_per": "John Doe", "tracking_number": "1234567890" } ``` # Calculate Price Source: https://docs.stateset.com/api-reference/pricing-rules/calculate POST https://api.stateset.com/v1/pricing-rules/calculate Calculate prices with applicable pricing rules This endpoint calculates final prices for products by applying all applicable pricing rules based on customer, quantity, and other conditions. ## Authentication This endpoint requires a valid API key with `pricing:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Customer ID for customer-specific pricing Customer segment if customer\_id not provided Sales channel: "web", "pos", "b2b", "marketplace" Products to calculate pricing for Product ID Product variant ID Quantity Original list price in cents Product category ID Product SKU Currency code (default: account currency) Date for time-based pricing (ISO 8601) ### Response Returns calculated prices with applied rules breakdown. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/pricing-rules/calculate' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "customer_segment": "wholesale", "channel": "b2b", "items": [ { "product_id": "prod_electronics_001", "quantity": 75, "list_price": 9999, "category_id": "cat_electronics" }, { "product_id": "prod_accessories_001", "quantity": 10, "list_price": 1999, "category_id": "cat_accessories" } ] }' ``` ```javascript Node.js theme={null} const calculation = await stateset.pricingRules.calculate({ customer_segment: "wholesale", channel: "b2b", items: [ { product_id: "prod_electronics_001", quantity: 75, list_price: 9999, category_id: "cat_electronics" }, { product_id: "prod_accessories_001", quantity: 10, list_price: 1999, category_id: "cat_accessories" } ] }); ``` ```json Response theme={null} { "object": "price_calculation", "items": [ { "product_id": "prod_electronics_001", "quantity": 75, "list_price": 9999, "final_price": 8499, "unit_discount": 1500, "total_discount": 112500, "subtotal": 637425, "applied_rules": [ { "rule_id": "pr_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "rule_name": "B2B Volume Pricing - Electronics", "type": "volume_based", "discount_percentage": 15, "quantity_tier": "50-99" } ] }, { "product_id": "prod_accessories_001", "quantity": 10, "list_price": 1999, "final_price": 1999, "unit_discount": 0, "total_discount": 0, "subtotal": 19990, "applied_rules": [], "reason_no_discount": "category_not_eligible" } ], "summary": { "total_list_price": 769915, "total_discount": 112500, "total_final_price": 657415, "discount_percentage": 14.6, "currency": "USD" }, "rules_considered": 3, "rules_applied": 1, "calculation_timestamp": "2024-06-20T16:30:00Z" } ``` # Create Pricing Rule Source: https://docs.stateset.com/api-reference/pricing-rules/create POST https://api.stateset.com/v1/pricing-rules Create a dynamic pricing rule for products or customer segments This endpoint creates a new pricing rule that automatically adjusts product prices based on various conditions like customer type, quantity, date ranges, or inventory levels. ## Authentication This endpoint requires a valid API key with `pricing:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Pricing rule name Rule type: "customer\_specific", "volume\_based", "time\_based", "channel\_based", "dynamic" Rule priority (lower numbers take precedence) Price adjustment configuration Adjustment method: "fixed\_price", "percentage\_discount", "fixed\_discount", "markup", "formula" Adjustment value (percentage for percentage methods, cents for fixed methods) Pricing formula (for formula method) Round final price to nearest value in cents Minimum margin percentage to maintain Conditions for rule application Applicable customer segment IDs Specific customer IDs Applicable product IDs Applicable category IDs SKU patterns (supports wildcards) Sales channels: "web", "pos", "b2b", "marketplace" Volume-based pricing tiers Minimum quantity for this tier Price adjustment for this tier Dynamic pricing based on inventory Low stock threshold High stock threshold Price adjustment curve: "linear", "exponential", "stepped" Rule validity period Start date (ISO 8601) End date (ISO 8601) Time-based schedule Active days (0-6, Sunday is 0) Active time ranges Currency code (defaults to account currency) Rule status: "active", "scheduled", "inactive" Additional custom fields ### Response Returns the created pricing rule object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/pricing-rules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "name": "B2B Volume Pricing - Electronics", "type": "volume_based", "priority": 10, "price_adjustment": { "method": "percentage_discount", "round_to": 99, "minimum_margin": 15 }, "conditions": { "customer_segments": ["wholesale", "distributor"], "category_ids": ["cat_electronics"], "quantity_breaks": [ { "min_quantity": 10, "adjustment": { "method": "percentage_discount", "value": 10 } }, { "min_quantity": 50, "adjustment": { "method": "percentage_discount", "value": 15 } }, { "min_quantity": 100, "adjustment": { "method": "percentage_discount", "value": 20 } } ] }, "validity": { "start_date": "2024-01-01T00:00:00Z" }, "status": "active" }' ``` ```javascript Node.js theme={null} const pricingRule = await stateset.pricingRules.create({ name: "B2B Volume Pricing - Electronics", type: "volume_based", priority: 10, price_adjustment: { method: "percentage_discount", round_to: 99, minimum_margin: 15 }, conditions: { customer_segments: ["wholesale", "distributor"], category_ids: ["cat_electronics"], quantity_breaks: [ { min_quantity: 10, adjustment: { method: "percentage_discount", value: 10 } }, { min_quantity: 50, adjustment: { method: "percentage_discount", value: 15 } }, { min_quantity: 100, adjustment: { method: "percentage_discount", value: 20 } } ] }, validity: { start_date: "2024-01-01T00:00:00Z" }, status: "active" }); ``` ```json Response theme={null} { "id": "pr_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "pricing_rule", "name": "B2B Volume Pricing - Electronics", "type": "volume_based", "priority": 10, "price_adjustment": { "method": "percentage_discount", "round_to": 99, "minimum_margin": 15 }, "conditions": { "customer_segments": ["wholesale", "distributor"], "customer_ids": [], "product_ids": [], "category_ids": ["cat_electronics"], "sku_patterns": [], "channels": [], "quantity_breaks": [ { "min_quantity": 10, "max_quantity": 49, "adjustment": { "method": "percentage_discount", "value": 10 } }, { "min_quantity": 50, "max_quantity": 99, "adjustment": { "method": "percentage_discount", "value": 15 } }, { "min_quantity": 100, "max_quantity": null, "adjustment": { "method": "percentage_discount", "value": 20 } } ] }, "validity": { "start_date": "2024-01-01T00:00:00Z", "end_date": null, "is_active": true, "schedule": null }, "currency": "USD", "status": "active", "created_at": "2024-01-20T13:00:00Z", "updated_at": "2024-01-20T13:00:00Z", "created_by": "user_123", "statistics": { "times_applied": 0, "total_discount_given": 0, "affected_orders": 0, "last_applied": null } } ``` # Get Pricing Rule Source: https://docs.stateset.com/api-reference/pricing-rules/get GET https://api.stateset.com/v1/pricing-rules/:id Retrieve details of a specific pricing rule This endpoint retrieves detailed information about a specific pricing rule, including its conditions, application statistics, and current status. ## Authentication This endpoint requires a valid API key with `pricing:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the pricing rule ### Response Returns the pricing rule object if found. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/pricing-rules/pr_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const pricingRule = await stateset.pricingRules.retrieve( 'pr_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} pricing_rule = stateset.pricing_rules.retrieve( 'pr_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "pr_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "pricing_rule", "name": "B2B Volume Pricing - Electronics", "type": "volume_based", "priority": 10, "price_adjustment": { "method": "percentage_discount", "round_to": 99, "minimum_margin": 15 }, "conditions": { "customer_segments": ["wholesale", "distributor"], "customer_ids": [], "product_ids": [], "category_ids": ["cat_electronics"], "sku_patterns": [], "channels": [], "quantity_breaks": [ { "min_quantity": 10, "max_quantity": 49, "adjustment": { "method": "percentage_discount", "value": 10 } }, { "min_quantity": 50, "max_quantity": 99, "adjustment": { "method": "percentage_discount", "value": 15 } }, { "min_quantity": 100, "max_quantity": null, "adjustment": { "method": "percentage_discount", "value": 20 } } ] }, "validity": { "start_date": "2024-01-01T00:00:00Z", "end_date": null, "is_active": true, "schedule": null }, "currency": "USD", "status": "active", "created_at": "2024-01-20T13:00:00Z", "updated_at": "2024-05-15T09:30:00Z", "created_by": "user_123", "statistics": { "times_applied": 342, "total_discount_given": 458950, "affected_orders": 342, "last_applied": "2024-06-20T15:45:00Z", "average_discount_per_order": 1342, "top_customers": [ { "customer_id": "cust_wholesale_001", "times_used": 45, "total_saved": 67500 } ] } } ``` # Bulk Update Products Source: https://docs.stateset.com/api-reference/products/bulk-update POST https://api.stateset.com/v1/products/bulk-update Update multiple products in a single request This endpoint allows updating up to 100 products in a single request. Use this for bulk price changes, inventory updates, or status changes. ### Request Body Array of product updates (max 100 items) Product ID to update Updated pricing information Updated inventory settings Updated status Updated metadata Updated tags If true, validates the updates without applying them (default: false) ### Response Successfully updated products Products that failed to update with error details Summary of the bulk operation Total number of products in request Number of successfully updated products Number of failed updates ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/products/bulk-update' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "updates": [ { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "price": { "amount": 11999 }, "tags": ["electronics", "audio", "sale", "clearance"] }, { "id": "prod_abc123def456", "price": { "amount": 6999 }, "inventory": { "low_stock_threshold": 25 } }, { "id": "prod_xyz789ghi012", "status": "archived" } ] }' ``` ```graphQL GraphQL theme={null} mutation BulkUpdateProducts($updates: [ProductUpdate!]!) { bulkUpdateProducts(updates: $updates) { updated { id name sku updated_at } errors { product_id error } summary { total successful failed } } } ``` ```javascript Node.js theme={null} const result = await stateset.products.bulkUpdate({ updates: [ { id: "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", price: { amount: 11999 }, tags: ["electronics", "audio", "sale", "clearance"] }, { id: "prod_abc123def456", price: { amount: 6999 }, inventory: { low_stock_threshold: 25 } }, { id: "prod_xyz789ghi012", status: "archived" } ] }); ``` ```python Python theme={null} result = stateset.products.bulk_update({ "updates": [ { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "price": {"amount": 11999}, "tags": ["electronics", "audio", "sale", "clearance"] }, { "id": "prod_abc123def456", "price": {"amount": 6999}, "inventory": {"low_stock_threshold": 25} }, { "id": "prod_xyz789ghi012", "status": "archived" } ] }) ``` ```json Response theme={null} { "updated": [ { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "updated_at": "2024-01-15T17:30:00Z" }, { "id": "prod_abc123def456", "name": "Sport Wireless Earbuds", "sku": "SWE-001", "updated_at": "2024-01-15T17:30:00Z" } ], "errors": [ { "product_id": "prod_xyz789ghi012", "error": "Product not found" } ], "summary": { "total": 3, "successful": 2, "failed": 1 } } ``` # Create Product Source: https://docs.stateset.com/api-reference/products/create POST https://api.stateset.com/v1/products Create a new product with inventory tracking and variant support This endpoint creates a new product and automatically initializes inventory tracking. Products support multiple variants and can be associated with suppliers and categories. ## Authentication This endpoint requires a valid API key with `products:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Product name for display Unique stock keeping unit (SKU) identifier Detailed product description Product category (e.g., "Electronics", "Clothing", "Home & Garden") Brand or manufacturer name Pricing information Price in cents (e.g., 1999 for \$19.99) ISO 4217 currency code (e.g., "USD", "EUR") Original price for displaying discounts Cost information for margin calculations Cost in cents ISO 4217 currency code Inventory settings Whether to track inventory levels (default: true) Initial stock quantity Threshold for low stock alerts Whether to allow orders when out of stock Primary warehouse ID for this product Product dimensions for shipping calculations Weight in pounds Length in inches Width in inches Height in inches Product variants (e.g., different sizes, colors) Variant SKU Variant name Variant options (e.g., size: "M", color: "Blue") Variant-specific pricing (overrides base product price) Variant-specific inventory settings UPC, EAN, or other barcode Product images Image URL Alt text for accessibility Display order (1-based) Associated variant IDs Supplier information Existing supplier ID Supplier's SKU for this product Expected days for reordering Minimum quantity for supplier orders Additional custom fields as key-value pairs Array of string tags for categorization and search Product status: "active", "draft", or "archived" (default: "active") ### Response Unique product identifier Always "product" ISO 8601 timestamp of creation ISO 8601 timestamp of last update Product name Product SKU Product status Array of product variants with their IDs Summary of inventory across all variants ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/products' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "price": { "amount": 14999, "currency": "USD", "compare_at": 19999 }, "cost": { "amount": 7500, "currency": "USD" }, "inventory": { "track_inventory": true, "quantity": 150, "low_stock_threshold": 20, "allow_backorder": false }, "dimensions": { "weight": 0.5, "length": 8, "width": 7, "height": 3 }, "variants": [ { "sku": "WBH-001-BLK", "name": "Wireless Bluetooth Headphones - Black", "options": { "color": "Black" }, "inventory": { "quantity": 100 } }, { "sku": "WBH-001-WHT", "name": "Wireless Bluetooth Headphones - White", "options": { "color": "White" }, "inventory": { "quantity": 50 } } ], "images": [ { "url": "https://example.com/images/headphones-main.jpg", "alt_text": "Wireless Bluetooth Headphones", "position": 1 } ], "tags": ["electronics", "audio", "wireless", "bluetooth"] }' ``` ```graphQL GraphQL theme={null} mutation CreateProduct { createProduct(input: { name: "Wireless Bluetooth Headphones" sku: "WBH-001" description: "Premium noise-cancelling wireless headphones with 30-hour battery life" category: "Electronics" brand: "AudioTech" price: { amount: 14999 currency: "USD" compare_at: 19999 } inventory: { track_inventory: true quantity: 150 low_stock_threshold: 20 } }) { id name sku status inventory_summary { total_quantity available_quantity reserved_quantity } } } ``` ```javascript Node.js theme={null} const product = await stateset.products.create({ name: "Wireless Bluetooth Headphones", sku: "WBH-001", description: "Premium noise-cancelling wireless headphones with 30-hour battery life", category: "Electronics", brand: "AudioTech", price: { amount: 14999, currency: "USD", compare_at: 19999 }, inventory: { track_inventory: true, quantity: 150, low_stock_threshold: 20, allow_backorder: false }, variants: [ { sku: "WBH-001-BLK", name: "Wireless Bluetooth Headphones - Black", options: { color: "Black" }, inventory: { quantity: 100 } }, { sku: "WBH-001-WHT", name: "Wireless Bluetooth Headphones - White", options: { color: "White" }, inventory: { quantity: 50 } } ] }); ``` ```python Python theme={null} product = stateset.products.create({ "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "price": { "amount": 14999, "currency": "USD", "compare_at": 19999 }, "inventory": { "track_inventory": True, "quantity": 150, "low_stock_threshold": 20, "allow_backorder": False } }) ``` ```json Response theme={null} { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "product", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "status": "active", "price": { "amount": 14999, "currency": "USD", "compare_at": 19999 }, "cost": { "amount": 7500, "currency": "USD" }, "inventory": { "track_inventory": true, "low_stock_threshold": 20, "allow_backorder": false }, "inventory_summary": { "total_quantity": 150, "available_quantity": 150, "reserved_quantity": 0, "by_warehouse": { "wh_001": { "available": 150, "reserved": 0 } } }, "variants": [ { "id": "var_1234567890", "sku": "WBH-001-BLK", "name": "Wireless Bluetooth Headphones - Black", "options": { "color": "Black" }, "inventory": { "quantity": 100, "available": 100, "reserved": 0 } }, { "id": "var_0987654321", "sku": "WBH-001-WHT", "name": "Wireless Bluetooth Headphones - White", "options": { "color": "White" }, "inventory": { "quantity": 50, "available": 50, "reserved": 0 } } ], "images": [ { "id": "img_abc123", "url": "https://example.com/images/headphones-main.jpg", "alt_text": "Wireless Bluetooth Headphones", "position": 1 } ], "tags": ["electronics", "audio", "wireless", "bluetooth"], "metadata": {} } ``` # Delete Product Source: https://docs.stateset.com/api-reference/products/delete DELETE https://api.stateset.com/v1/products/:id Delete a product from the catalog Deleting a product is irreversible. Products with existing orders cannot be deleted and must be archived instead. ### Path Parameters The unique identifier of the product to delete ### Response The ID of the deleted product Always "product" Always true for successful deletion ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/products/prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```graphQL GraphQL theme={null} mutation DeleteProduct($id: ID!) { deleteProduct(id: $id) { id deleted } } ``` ```javascript Node.js theme={null} const result = await stateset.products.delete( 'prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} result = stateset.products.delete( 'prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "product", "deleted": true } ``` ### Error Responses Error object when deletion fails Type of error (e.g., "invalid\_request", "product\_has\_orders") Human-readable error message Error code for programmatic handling ```json Error Response theme={null} { "error": { "type": "product_has_orders", "message": "Cannot delete product with existing orders. Archive the product instead.", "code": "PRODUCT_HAS_ORDERS" } } ``` # Get Product Source: https://docs.stateset.com/api-reference/products/get GET https://api.stateset.com/v1/products/:id Retrieve a single product by ID with full details including variants and inventory ### Path Parameters The unique identifier of the product to retrieve ### Query Parameters Include real-time inventory data (default: true) Include all product variants (default: true) Filter inventory data by specific warehouse ### Response Unique product identifier Always "product" ISO 8601 timestamp of creation ISO 8601 timestamp of last update Product name Product SKU Product description Product category Brand name Pricing information including amount, currency, and compare\_at price Cost information for margin calculations Product status: "active", "draft", or "archived" Inventory settings and current levels Aggregated inventory data across all variants and warehouses Array of product variants with full details Product images with URLs and metadata Product dimensions for shipping calculations Supplier information if configured Array of product tags Custom metadata fields ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/products/prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```graphQL GraphQL theme={null} query GetProduct($id: ID!) { product(id: $id) { id name sku description category brand status price { amount currency compare_at } inventory_summary { total_quantity available_quantity reserved_quantity } variants { id sku name options inventory { quantity available reserved } } images { url alt_text position } } } ``` ```javascript Node.js theme={null} const product = await stateset.products.retrieve( 'prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { include_inventory: true, include_variants: true } ); ``` ```python Python theme={null} product = stateset.products.retrieve( 'prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', include_inventory=True, include_variants=True ) ``` ```json Response theme={null} { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "product", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T14:22:00Z", "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "status": "active", "price": { "amount": 14999, "currency": "USD", "compare_at": 19999 }, "cost": { "amount": 7500, "currency": "USD" }, "inventory": { "track_inventory": true, "low_stock_threshold": 20, "allow_backorder": false }, "inventory_summary": { "total_quantity": 150, "available_quantity": 145, "reserved_quantity": 5, "by_warehouse": { "wh_001": { "available": 145, "reserved": 5 } } }, "dimensions": { "weight": 0.5, "length": 8, "width": 7, "height": 3 }, "variants": [ { "id": "var_1234567890", "sku": "WBH-001-BLK", "name": "Wireless Bluetooth Headphones - Black", "options": { "color": "Black" }, "price": null, "inventory": { "quantity": 100, "available": 97, "reserved": 3 }, "barcode": null }, { "id": "var_0987654321", "sku": "WBH-001-WHT", "name": "Wireless Bluetooth Headphones - White", "options": { "color": "White" }, "price": null, "inventory": { "quantity": 50, "available": 48, "reserved": 2 }, "barcode": null } ], "images": [ { "id": "img_abc123", "url": "https://example.com/images/headphones-main.jpg", "alt_text": "Wireless Bluetooth Headphones", "position": 1, "variant_ids": [] } ], "supplier": null, "tags": ["electronics", "audio", "wireless", "bluetooth"], "metadata": {} } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Product not found", "details": { "resource": "product", "id": "prod_abc123" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` # List Products Source: https://docs.stateset.com/api-reference/products/list GET https://api.stateset.com/v1/products Retrieve a paginated list of products with filtering and search capabilities ### Query Parameters Number of products to return (default: 20, max: 100) Number of products to skip (for pagination) Cursor for pagination (alternative to offset) Filter by status: "active", "draft", or "archived" Filter by product category Filter by brand name Search products by name, SKU, or description Filter by exact SKU match Filter by tags (comma-separated) Minimum price filter (in cents) Maximum price filter (in cents) Filter products with available inventory Filter products below low stock threshold Filter products created after this date (ISO 8601) Filter products created before this date (ISO 8601) Filter products updated after this date (ISO 8601) Sort field: "created\_at", "updated\_at", "name", "price", "sku" (default: "created\_at") Sort order: "asc" or "desc" (default: "desc") Include variant details in response (default: false) Include inventory summary (default: false) ### Response Always "list" Array of product objects Whether there are more products to retrieve Total number of products matching the filters Cursor for retrieving the next page ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/products?limit=10&status=active&category=Electronics' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```graphQL GraphQL theme={null} query ListProducts( $limit: Int $offset: Int $status: ProductStatus $category: String $search: String ) { products( limit: $limit offset: $offset status: $status category: $category search: $search ) { data { id name sku category brand status price { amount currency } inventory_summary { total_quantity available_quantity } } has_more total_count } } ``` ```javascript Node.js theme={null} const products = await stateset.products.list({ limit: 10, status: 'active', category: 'Electronics', in_stock: true, sort_by: 'price', sort_order: 'asc' }); // Iterate through all products for await (const product of stateset.products.list()) { console.log(product.id, product.name); } ``` ```python Python theme={null} products = stateset.products.list( limit=10, status='active', category='Electronics', in_stock=True, sort_by='price', sort_order='asc' ) # Iterate through all products for product in stateset.products.list(): print(product.id, product.name) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "product", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T14:22:00Z", "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "status": "active", "price": { "amount": 14999, "currency": "USD", "compare_at": 19999 }, "inventory_summary": { "total_quantity": 150, "available_quantity": 145, "reserved_quantity": 5 }, "tags": ["electronics", "audio", "wireless", "bluetooth"] }, { "id": "prod_1234567890abcdef", "object": "product", "created_at": "2024-01-14T09:15:00Z", "updated_at": "2024-01-14T09:15:00Z", "name": "USB-C Charging Cable", "sku": "USB-C-001", "description": "Fast charging USB-C cable, 6ft length", "category": "Electronics", "brand": "TechConnect", "status": "active", "price": { "amount": 1299, "currency": "USD", "compare_at": null }, "inventory_summary": { "total_quantity": 500, "available_quantity": 487, "reserved_quantity": 13 }, "tags": ["electronics", "cables", "charging"] } ], "has_more": true, "total_count": 42, "next_cursor": "eyJpZCI6InByb2RfMTIzNDU2Nzg5MGFiY2RlZiJ9" } ``` # Search Products Source: https://docs.stateset.com/api-reference/products/search POST https://api.stateset.com/v1/products/search Advanced product search with full-text search, filters, and faceted results This endpoint provides powerful search capabilities including fuzzy matching, relevance scoring, and aggregated facets for building filter UIs. ### Request Body Search query for full-text search across product names, descriptions, and SKUs Additional filters to narrow results Filter by one or more categories Filter by one or more brands Price range filter Minimum price in cents Maximum price in cents Only show products with available inventory Filter by product tags Filter by status: "active", "draft", or "archived" Sort options Sort field: "relevance", "price", "name", "created\_at", "popularity" Sort order: "asc" or "desc" Pagination options Number of results (default: 20, max: 100) Number of results to skip Include aggregated facets for building filter UIs (default: true) ### Response Array of matching products with relevance scores Total number of matching products Aggregated data for building filter UIs Category counts Brand counts Price range distributions Tag counts ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/products/search' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "query": "wireless headphones", "filters": { "categories": ["Electronics"], "price_range": { "min": 5000, "max": 20000 }, "in_stock": true }, "sort": { "field": "relevance", "order": "desc" }, "pagination": { "limit": 10, "offset": 0 } }' ``` ```graphQL GraphQL theme={null} mutation SearchProducts($input: SearchProductsInput!) { searchProducts(input: $input) { results { id name sku description category brand price { amount currency } relevance_score } total_count facets { categories { value count } brands { value count } } } } ``` ```javascript Node.js theme={null} const searchResults = await stateset.products.search({ query: "wireless headphones", filters: { categories: ["Electronics"], price_range: { min: 5000, max: 20000 }, in_stock: true }, sort: { field: "relevance", order: "desc" } }); ``` ```python Python theme={null} search_results = stateset.products.search({ "query": "wireless headphones", "filters": { "categories": ["Electronics"], "price_range": { "min": 5000, "max": 20000 }, "in_stock": True }, "sort": { "field": "relevance", "order": "desc" } }) ``` ```json Response theme={null} { "results": [ { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "price": { "amount": 14999, "currency": "USD" }, "relevance_score": 0.98, "inventory_summary": { "available": true, "quantity": 145 } }, { "id": "prod_abc123def456", "name": "Sport Wireless Earbuds", "sku": "SWE-001", "description": "Waterproof wireless earbuds perfect for workouts", "category": "Electronics", "brand": "FitAudio", "price": { "amount": 7999, "currency": "USD" }, "relevance_score": 0.85, "inventory_summary": { "available": true, "quantity": 230 } } ], "total_count": 15, "facets": { "categories": [ { "value": "Electronics", "count": 15 } ], "brands": [ { "value": "AudioTech", "count": 5 }, { "value": "FitAudio", "count": 3 }, { "value": "SoundMax", "count": 4 }, { "value": "TechConnect", "count": 3 } ], "price_ranges": [ { "range": "50-100", "count": 3 }, { "range": "100-150", "count": 8 }, { "range": "150-200", "count": 4 } ], "tags": [ { "value": "wireless", "count": 15 }, { "value": "bluetooth", "count": 12 }, { "value": "noise-cancelling", "count": 6 } ] } } ``` # Update Product Source: https://docs.stateset.com/api-reference/products/update PUT https://api.stateset.com/v1/products/:id Update an existing product's details, pricing, or inventory settings This endpoint supports partial updates. Only include the fields you want to change. ### Path Parameters The unique identifier of the product to update ### Request Body Product name for display Detailed product description Product category Brand or manufacturer name Updated pricing information Price in cents ISO 4217 currency code Original price for displaying discounts Updated cost information Cost in cents ISO 4217 currency code Updated inventory settings Whether to track inventory levels Threshold for low stock alerts Whether to allow orders when out of stock Updated product dimensions Weight in pounds Length in inches Width in inches Height in inches Product status: "active", "draft", or "archived" Additional custom fields as key-value pairs Array of string tags for categorization ### Response Returns the updated product object with all fields. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/products/prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "price": { "amount": 12999, "compare_at": 14999 }, "inventory": { "low_stock_threshold": 15 }, "tags": ["electronics", "audio", "wireless", "bluetooth", "sale"] }' ``` ```graphQL GraphQL theme={null} mutation UpdateProduct($id: ID!, $input: UpdateProductInput!) { updateProduct(id: $id, input: $input) { id name sku price { amount currency compare_at } inventory { low_stock_threshold allow_backorder } tags updated_at } } ``` ```javascript Node.js theme={null} const product = await stateset.products.update( 'prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { price: { amount: 12999, compare_at: 14999 }, inventory: { low_stock_threshold: 15 }, tags: ["electronics", "audio", "wireless", "bluetooth", "sale"] } ); ``` ```python Python theme={null} product = stateset.products.update( 'prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', price={ "amount": 12999, "compare_at": 14999 }, inventory={ "low_stock_threshold": 15 }, tags=["electronics", "audio", "wireless", "bluetooth", "sale"] ) ``` ```json Response theme={null} { "id": "prod_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "product", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T16:45:00Z", "name": "Wireless Bluetooth Headphones", "sku": "WBH-001", "description": "Premium noise-cancelling wireless headphones with 30-hour battery life", "category": "Electronics", "brand": "AudioTech", "status": "active", "price": { "amount": 12999, "currency": "USD", "compare_at": 14999 }, "cost": { "amount": 7500, "currency": "USD" }, "inventory": { "track_inventory": true, "low_stock_threshold": 15, "allow_backorder": false }, "inventory_summary": { "total_quantity": 150, "available_quantity": 145, "reserved_quantity": 5 }, "dimensions": { "weight": 0.5, "length": 8, "width": 7, "height": 3 }, "tags": ["electronics", "audio", "wireless", "bluetooth", "sale"], "metadata": {} } ``` # Create Promotion Source: https://docs.stateset.com/api-reference/promotions/create POST https://api.stateset.com/v1/promotions Create a new promotion with flexible discount rules and targeting This endpoint creates a new promotion that can be applied to orders, products, or customer segments. Promotions support various discount types and complex rule conditions. ## Authentication This endpoint requires a valid API key with `promotions:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Internal name for the promotion Promotion code for customers to enter (leave empty for automatic promotions) Customer-facing description of the promotion Promotion type: "percentage", "fixed\_amount", "bogo", "tiered", "bundle", "free\_shipping" Discount value configuration Discount amount (percentage for percentage type, cents for fixed\_amount) Tier configuration for tiered discounts Minimum order amount in cents Discount for this tier Buy quantity for BOGO Get quantity for BOGO Maximum discount amount in cents (for percentage discounts) Conditions for promotion eligibility Minimum order amount in cents Maximum total uses across all customers Maximum uses per customer Eligible customer segment IDs Applicable product IDs Applicable category IDs Excluded product IDs Whether to exclude items already on sale Required shipping methods Required payment methods Promotion validity period Start date and time (ISO 8601) End date and time (ISO 8601) Timezone for date calculations (default: UTC) Recurring schedule Days promotion is active (0-6, Sunday is 0) Active hours Start time (HH:MM) End time (HH:MM) Rules for combining with other promotions Whether this promotion can be combined with others Application priority (lower numbers apply first) Promotion IDs that cannot be combined with this one Display configuration Show promotion badge on products Show in cart/checkout Custom badge text Promotional banner text Promotion status: "active", "scheduled", "paused", "expired" Additional custom fields ### Response Returns the created promotion object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/promotions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "name": "Summer Sale 2024", "code": "SUMMER20", "description": "Get 20% off on all summer collection items", "type": "percentage", "value": { "amount": 20, "max_discount": 10000 }, "conditions": { "min_purchase_amount": 5000, "max_uses_total": 1000, "max_uses_per_customer": 1, "category_ids": ["cat_summer_2024"], "exclude_sale_items": true }, "validity": { "start_date": "2024-06-01T00:00:00Z", "end_date": "2024-08-31T23:59:59Z", "timezone": "America/Los_Angeles" }, "stacking": { "allowed": false, "priority": 1 }, "display": { "show_in_catalog": true, "show_in_cart": true, "badge_text": "SUMMER SALE" }, "status": "scheduled" }' ``` ```javascript Node.js theme={null} const promotion = await stateset.promotions.create({ name: "Summer Sale 2024", code: "SUMMER20", description: "Get 20% off on all summer collection items", type: "percentage", value: { amount: 20, max_discount: 10000 }, conditions: { min_purchase_amount: 5000, max_uses_total: 1000, max_uses_per_customer: 1, category_ids: ["cat_summer_2024"], exclude_sale_items: true }, validity: { start_date: "2024-06-01T00:00:00Z", end_date: "2024-08-31T23:59:59Z", timezone: "America/Los_Angeles" }, stacking: { allowed: false, priority: 1 }, display: { show_in_catalog: true, show_in_cart: true, badge_text: "SUMMER SALE" }, status: "scheduled" }); ``` ```python Python theme={null} promotion = stateset.promotions.create( name="Summer Sale 2024", code="SUMMER20", description="Get 20% off on all summer collection items", type="percentage", value={ "amount": 20, "max_discount": 10000 }, conditions={ "min_purchase_amount": 5000, "max_uses_total": 1000, "max_uses_per_customer": 1, "category_ids": ["cat_summer_2024"], "exclude_sale_items": True }, validity={ "start_date": "2024-06-01T00:00:00Z", "end_date": "2024-08-31T23:59:59Z", "timezone": "America/Los_Angeles" }, stacking={ "allowed": False, "priority": 1 }, display={ "show_in_catalog": True, "show_in_cart": True, "badge_text": "SUMMER SALE" }, status="scheduled" ) ``` ```json Response theme={null} { "id": "promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "promotion", "name": "Summer Sale 2024", "code": "SUMMER20", "description": "Get 20% off on all summer collection items", "type": "percentage", "value": { "amount": 20, "max_discount": 10000 }, "conditions": { "min_purchase_amount": 5000, "max_uses_total": 1000, "max_uses_per_customer": 1, "used_count": 0, "category_ids": ["cat_summer_2024"], "exclude_sale_items": true }, "validity": { "start_date": "2024-06-01T00:00:00Z", "end_date": "2024-08-31T23:59:59Z", "timezone": "America/Los_Angeles", "is_active": false, "days_remaining": 134 }, "stacking": { "allowed": false, "priority": 1 }, "display": { "show_in_catalog": true, "show_in_cart": true, "badge_text": "SUMMER SALE" }, "status": "scheduled", "created_at": "2024-01-20T10:00:00Z", "updated_at": "2024-01-20T10:00:00Z", "created_by": "user_123", "performance": { "total_orders": 0, "total_revenue": 0, "total_discount_given": 0, "conversion_rate": 0 } } ``` # Get Promotion Source: https://docs.stateset.com/api-reference/promotions/get GET https://api.stateset.com/v1/promotions/:id Retrieve details of a specific promotion This endpoint retrieves detailed information about a specific promotion, including its current usage statistics and performance metrics. ## Authentication This endpoint requires a valid API key with `promotions:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the promotion ### Response Returns the promotion object if found. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/promotions/promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const promotion = await stateset.promotions.retrieve( 'promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} promotion = stateset.promotions.retrieve( 'promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "promotion", "name": "Summer Sale 2024", "code": "SUMMER20", "description": "Get 20% off on all summer collection items", "type": "percentage", "value": { "amount": 20, "max_discount": 10000 }, "conditions": { "min_purchase_amount": 5000, "max_uses_total": 1000, "max_uses_per_customer": 1, "used_count": 245, "category_ids": ["cat_summer_2024"], "exclude_sale_items": true }, "validity": { "start_date": "2024-06-01T00:00:00Z", "end_date": "2024-08-31T23:59:59Z", "timezone": "America/Los_Angeles", "is_active": true, "days_remaining": 72 }, "stacking": { "allowed": false, "priority": 1 }, "display": { "show_in_catalog": true, "show_in_cart": true, "badge_text": "SUMMER SALE" }, "status": "active", "created_at": "2024-01-20T10:00:00Z", "updated_at": "2024-06-15T14:30:00Z", "created_by": "user_123", "performance": { "total_orders": 245, "total_revenue": 489750, "total_discount_given": 97950, "conversion_rate": 0.0245, "average_order_value": 1999, "daily_usage": [ { "date": "2024-06-20", "uses": 12, "revenue": 23988 } ] } } ``` # List Promotions Source: https://docs.stateset.com/api-reference/promotions/list GET https://api.stateset.com/v1/promotions List all promotions with filtering and pagination options This endpoint returns a paginated list of promotions. You can filter by status, type, validity dates, and more. ## Authentication This endpoint requires a valid API key with `promotions:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of promotions to return (1-100) Number of promotions to skip Filter by status: "active", "scheduled", "paused", "expired" Filter by promotion type: "percentage", "fixed\_amount", "bogo", "tiered", "bundle", "free\_shipping" Search by promotion code (partial match) Filter promotions active on a specific date (ISO 8601) Filter by eligible customer segment Sort by field: "created\_at", "start\_date", "end\_date", "priority", "usage\_count" Sort order: "asc" or "desc" ### Response Returns a paginated list of promotion objects. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/promotions?status=active&limit=20' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const promotions = await stateset.promotions.list({ status: 'active', limit: 20 }); ``` ```python Python theme={null} promotions = stateset.promotions.list( status='active', limit=20 ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "promotion", "name": "Summer Sale 2024", "code": "SUMMER20", "description": "Get 20% off on all summer collection items", "type": "percentage", "value": { "amount": 20, "max_discount": 10000 }, "status": "active", "validity": { "start_date": "2024-06-01T00:00:00Z", "end_date": "2024-08-31T23:59:59Z", "is_active": true }, "conditions": { "used_count": 245, "max_uses_total": 1000 }, "created_at": "2024-01-20T10:00:00Z" }, { "id": "promo_1234f083-bb2d-54d6-bg6d-1b0e3gd75f41", "object": "promotion", "name": "First Time Buyer", "code": "WELCOME10", "description": "10% off for new customers", "type": "percentage", "value": { "amount": 10 }, "status": "active", "validity": { "start_date": "2024-01-01T00:00:00Z", "end_date": null, "is_active": true }, "conditions": { "used_count": 1523, "max_uses_per_customer": 1 }, "created_at": "2024-01-01T00:00:00Z" } ], "has_more": true, "total_count": 42, "url": "/v1/promotions" } ``` # Update Promotion Source: https://docs.stateset.com/api-reference/promotions/update PUT https://api.stateset.com/v1/promotions/:id Update an existing promotion This endpoint updates an existing promotion. You can modify conditions, validity periods, and display settings. Some fields cannot be updated after a promotion has been used. ## Authentication This endpoint requires a valid API key with `promotions:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the promotion to update ## Request Body All fields are optional. Only provided fields will be updated. Internal name for the promotion Customer-facing description Update promotion conditions Maximum total uses Maximum uses per customer Eligible customer segments Update validity period New end date (ISO 8601) Update status: "active", "paused", "expired" ### Response Returns the updated promotion object. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/promotions/promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "validity": { "end_date": "2024-09-30T23:59:59Z" }, "conditions": { "max_uses_total": 1500 }, "status": "active" }' ``` ```javascript Node.js theme={null} const promotion = await stateset.promotions.update( 'promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { validity: { end_date: "2024-09-30T23:59:59Z" }, conditions: { max_uses_total: 1500 }, status: "active" } ); ``` ```python Python theme={null} promotion = stateset.promotions.update( 'promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', validity={ "end_date": "2024-09-30T23:59:59Z" }, conditions={ "max_uses_total": 1500 }, status="active" ) ``` ```json Response theme={null} { "id": "promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "promotion", "name": "Summer Sale 2024", "code": "SUMMER20", "description": "Get 20% off on all summer collection items", "type": "percentage", "value": { "amount": 20, "max_discount": 10000 }, "conditions": { "min_purchase_amount": 5000, "max_uses_total": 1500, "max_uses_per_customer": 1, "used_count": 245, "category_ids": ["cat_summer_2024"], "exclude_sale_items": true }, "validity": { "start_date": "2024-06-01T00:00:00Z", "end_date": "2024-09-30T23:59:59Z", "timezone": "America/Los_Angeles", "is_active": true, "days_remaining": 102 }, "status": "active", "updated_at": "2024-06-20T15:00:00Z", "updated_by": "user_456" } ``` # Validate Promotion Source: https://docs.stateset.com/api-reference/promotions/validate POST https://api.stateset.com/v1/promotions/validate Validate a promotion code and check eligibility for a specific cart This endpoint validates whether a promotion code can be applied to a given cart, checking all conditions and returning applicable discounts. ## Authentication This endpoint requires a valid API key with `promotions:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Promotion code to validate Customer ID for personalized validation Cart details for validation Cart items Product ID Product variant ID Item quantity Unit price in cents Product category ID Whether item is already on sale Cart subtotal in cents Selected shipping method Selected payment method Already applied promotion IDs for stacking validation ### Response Returns validation result with applicable discount details. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/promotions/validate' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "code": "SUMMER20", "customer_id": "cust_abc123", "cart": { "items": [ { "product_id": "prod_123", "quantity": 2, "price": 2999, "category_id": "cat_summer_2024" }, { "product_id": "prod_456", "quantity": 1, "price": 4999, "category_id": "cat_accessories" } ], "subtotal": 10997, "shipping_method": "standard" } }' ``` ```javascript Node.js theme={null} const validation = await stateset.promotions.validate({ code: "SUMMER20", customer_id: "cust_abc123", cart: { items: [ { product_id: "prod_123", quantity: 2, price: 2999, category_id: "cat_summer_2024" }, { product_id: "prod_456", quantity: 1, price: 4999, category_id: "cat_accessories" } ], subtotal: 10997, shipping_method: "standard" } }); ``` ```python Python theme={null} validation = stateset.promotions.validate( code="SUMMER20", customer_id="cust_abc123", cart={ "items": [ { "product_id": "prod_123", "quantity": 2, "price": 2999, "category_id": "cat_summer_2024" }, { "product_id": "prod_456", "quantity": 1, "price": 4999, "category_id": "cat_accessories" } ], "subtotal": 10997, "shipping_method": "standard" } ) ``` ```json Response theme={null} { "valid": true, "promotion": { "id": "promo_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "code": "SUMMER20", "name": "Summer Sale 2024", "type": "percentage", "description": "Get 20% off on all summer collection items" }, "eligibility": { "is_eligible": true, "customer_eligible": true, "cart_eligible": true, "within_usage_limits": true, "within_date_range": true, "meets_minimum_purchase": true }, "discount_calculation": { "applicable_items": [ { "product_id": "prod_123", "quantity": 2, "original_amount": 5998, "discount_amount": 1200, "final_amount": 4798 } ], "excluded_items": [ { "product_id": "prod_456", "reason": "category_not_eligible" } ], "discount_amount": 1200, "final_subtotal": 9797 }, "warnings": [], "metadata": { "customer_usage_count": 0, "total_usage_count": 245, "days_until_expiry": 134 } } ``` # Cancel Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/cancel POST https://api.stateset.com/v1/purchase_orders/:id/cancel This endpoint cancels an existing purchase order. ### Body The ID provided in the data tab may be used to identify the purchase order ### Response The ID provided in the data tab may be used to identify the purchase order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/purchase_order/:id/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "po_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation cancelPurchaseOrder ($id: String!) { cance_purchaseorder(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const purchaseorders = await stateset.purchaseorders.cancel({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} purchaseorders = stateset.purchaseorders.cancel({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} purchaseorders, err := stateset.purchaseorders.cancel.( "po_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Return purchaseorders = stateset.purchaseorders.cancel( "po_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const purchaseorders = await stateset.purchaseorders.cancel({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} purchaseorders = Stateset::PurchaseOrder.cancel({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $purchaseorders = $stateset->purchaseorders->cancel( 'po_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} POST /v1/purchaseorder/:id/cancel HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "object": "purchaseorder", "cancelled": true } ``` # Complete Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/complete POST https://api.stateset.com/v1/purchase_orders/:id/complete This endpoint completes an existing purchase order. ### Body The ID provided in the data tab may be used to identify the purchase order ### Response The ID provided in the data tab may be used to identify the purchase order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/purchase_order/:id/complete' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "po_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation completePurchaseOrder ($id: String!) { cance_purchaseorder(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const purchaseorders = await stateset.purchaseorders.complete({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} purchaseorders = stateset.purchaseorders.complete({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} purchaseorders, err := stateset.purchaseorders.complete.( "po_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Return purchaseorders = stateset.purchaseorders.complete( "po_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const purchaseorders = await stateset.purchaseorders.complete({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} purchaseorders = Stateset::PurchaseOrder.complete({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $purchaseorders = $stateset->purchaseorders->complete( 'po_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} POST /v1/purchaseorder/:id/complete HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "object": "purchaseorder", "completed": true } ``` # Create Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/create POST https://api.stateset.com/v1/purchase_orders This endpoint creates a new purchase order ### Body This is the id of the purchase order. This is the date the purchase order was created. This is the date the purchase order was delivered. This is the description of the purchase order. This is the external id of the purchase order. This is the financer of the purchase order. This is the fulfiller of the purchase order. This is the date the purchase order was last updated. This is the date the purchase order was purchased. This is the hash of the purchase order. This is the name of the purchase order. This is the number of the purchase order. This is the status of the purchase order. This is the purchaser of the purchase order. This is the subtotal of the purchase order. This is the total of the purchase order. This is the vendor of the purchase order. This is the transaction id of the purchase order. ### Response This is the id of the purchase order. This is the date the purchase order was created. This is the date the purchase order was delivered. This is the description of the purchase order. This is the external id of the purchase order. This is the financer of the purchase order. This is the fulfiller of the purchase order. This is the date the purchase order was last updated. This is the date the purchase order was purchased. This is the hash of the purchase order. This is the name of the purchase order. This is the number of the purchase order. This is the status of the purchase order. This is the purchaser of the purchase order. This is the subtotal of the purchase order. This is the total of the purchase order. This is the vendor of the purchase order. This is the transaction id of the purchase order. ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/purchaseorders \ -H "Authorization: Bearer ${STATESET_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "purchase_order_number": "PO-2026-001234", "description": "Q1 inventory restock — blue t-shirts", "vendor": "Acme Textiles Inc.", "total": "4500.00", "subtotal": "4200.00", "purchase_date": "2026-01-15T00:00:00.000Z", "delivery_date": "2026-02-01T00:00:00.000Z" }' ``` ```graphQL GraphQL theme={null} mutation InsertNewPurchaseOrder( $po: purchaseorders_insert_input! ) { insert_purchaseorders(objects: [$po]) { returning { id purchase_order_number description vendor total subtotal purchase_order_status purchase_date delivery_date } } } ``` ```js Node.js theme={null} const purchaseOrder = await stateset.purchaseOrders.create({ purchase_order_number: 'PO-2026-001234', description: 'Q1 inventory restock — blue t-shirts', vendor: 'Acme Textiles Inc.', total: '4500.00', subtotal: '4200.00', purchase_date: '2026-01-15T00:00:00.000Z', delivery_date: '2026-02-01T00:00:00.000Z', }); ``` ```python Python theme={null} purchase_order = stateset.purchase_orders.create( purchase_order_number="PO-2026-001234", description="Q1 inventory restock — blue t-shirts", vendor="Acme Textiles Inc.", total="4500.00", subtotal="4200.00", purchase_date="2026-01-15T00:00:00.000Z", delivery_date="2026-02-01T00:00:00.000Z", ) ``` ```ruby Ruby theme={null} purchase_order = Stateset::PurchaseOrder.create({ purchase_order_number: 'PO-2026-001234', description: 'Q1 inventory restock — blue t-shirts', vendor: 'Acme Textiles Inc.', total: '4500.00', subtotal: '4200.00', purchase_date: '2026-01-15T00:00:00.000Z', delivery_date: '2026-02-01T00:00:00.000Z', }) ``` ```go Go theme={null} purchaseOrder, err := stateset.PurchaseOrders.Create(&stateset.PurchaseOrderParams{ PurchaseOrderNumber: "PO-2026-001234", Description: "Q1 inventory restock — blue t-shirts", Vendor: "Acme Textiles Inc.", Total: "4500.00", Subtotal: "4200.00", PurchaseDate: "2026-01-15T00:00:00.000Z", DeliveryDate: "2026-02-01T00:00:00.000Z", }) ``` ```java Java theme={null} Map params = new HashMap<>(); params.put("purchase_order_number", "PO-2026-001234"); params.put("description", "Q1 inventory restock — blue t-shirts"); params.put("vendor", "Acme Textiles Inc."); params.put("total", "4500.00"); params.put("subtotal", "4200.00"); params.put("purchase_date", "2026-01-15T00:00:00.000Z"); params.put("delivery_date", "2026-02-01T00:00:00.000Z"); PurchaseOrder purchaseOrder = stateset.purchaseOrders().create(params); ``` ```php PHP theme={null} $purchaseOrder = $stateset->purchaseOrders->create([ 'purchase_order_number' => 'PO-2026-001234', 'description' => 'Q1 inventory restock — blue t-shirts', 'vendor' => 'Acme Textiles Inc.', 'total' => '4500.00', 'subtotal' => '4200.00', 'purchase_date' => '2026-01-15T00:00:00.000Z', 'delivery_date' => '2026-02-01T00:00:00.000Z', ]); ``` ```csharp C# theme={null} var purchaseOrder = await stateset.PurchaseOrders.CreateAsync( new PurchaseOrderCreateParams { PurchaseOrderNumber = "PO-2026-001234", Description = "Q1 inventory restock — blue t-shirts", Vendor = "Acme Textiles Inc.", Total = "4500.00", Subtotal = "4200.00", PurchaseDate = "2026-01-15T00:00:00.000Z", DeliveryDate = "2026-02-01T00:00:00.000Z" } ); ``` ```json Response theme={null} { "id": "po_1a2b3c4d5e6f", "createdat": "2026-01-15T12:00:00.000Z", "delivery_date": "2026-02-01T00:00:00.000Z", "description": "Q1 inventory restock — blue t-shirts", "external_id": "ext_po_98765", "financer": "fin_abc123", "fulfiller": "ful_def456", "lastupdated": "2026-01-15T12:00:00.000Z", "purchase_date": "2026-01-15T00:00:00.000Z", "purchase_order_hash": "a1b2c3d4e5f6", "purchase_order_name": "Q1 Blue T-Shirt Restock", "purchase_order_number": "PO-2026-001234", "purchase_order_status": "created", "purchaser": "usr_abc123", "subtotal": "4200.00", "total": "4500.00", "vendor": "Acme Textiles Inc.", "transaction_id": "txn_789xyz" } ``` # Delete Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/delete DELETE https://api.stateset.com/v1/purchase_orders/:id This endpoint deletes an existing purchase order. ### Body The ID provided in the data tab may be used to identify the purchase order ### Response The ID provided in the data tab may be used to identify the purchase order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/purchase_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "po_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deletePurchaseOrder ($id: String!) { delete_purchaseorder(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const purchaseorders = await stateset.purchaseorders.del({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} purchaseorders = stateset.purchaseorders.del({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} purchaseorders, err := stateset.purchaseorders.Del( "po_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Return purchaseorders = stateset.purchaseorders.del( "po_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const purchaseorders = await stateset.purchaseorders.del({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} purchaseorders = Stateset::PurchaseOrder.del({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $purchaseorders = $stateset->purchaseorders->del( 'po_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/purchaseorder HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "object": "purchaseorder", "deleted": true } ``` # Finance Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/finance POST https://api.stateset.com/v1/purchase_orders/:id/finance This endpoint finances an existing purchase order. ### Body The ID provided in the data tab may be used to identify the purchase order ### Response The ID provided in the data tab may be used to identify the purchase order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/purchase_order/:id/finance' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "po_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation financePurchaseOrder ($id: String!) { cance_purchaseorder(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const purchaseorders = await stateset.purchaseorders.finance({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} purchaseorders = stateset.purchaseorders.finance({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} purchaseorders, err := stateset.purchaseorders.finance.( "po_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Return purchaseorders = stateset.purchaseorders.finance( "po_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const purchaseorders = await stateset.purchaseorders.finance({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} purchaseorders = Stateset::PurchaseOrder.finance({ 'po_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $purchaseorders = $stateset->purchaseorders->finance( 'po_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} POST /v1/purchaseorder/:id/finance HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "object": "purchaseorder", "financed": true } ``` # Get Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/get GET https://api.stateset.com/v1/purchase_orders This endpoint gets or creates a new purchase order. ### Body This is the id of the purchase order. ### Response This is the id of the purchase order. This is the date the purchase order was created. This is the date the purchase order was delivered. This is the description of the purchase order. This is the external id of the purchase order. This is the financer of the purchase order. This is the fulfiller of the purchase order. This is the date the purchase order was last updated. This is the date the purchase order was purchased. This is the hash of the purchase order. This is the name of the purchase order. This is the number of the purchase order. This is the status of the purchase order. This is the purchaser of the purchase order. This is the subtotal of the purchase order. This is the total of the purchase order. This is the vendor of the purchase order. This is the transaction id of the purchase order. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/purchaseorder' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query { purchaseorder { id createdat delivery_date description external_id financer fulfiller lastupdated purchase_date purchase_order_hash purchase_order_name purchase_order_number purchase_order_status purchaser subtotal total vendor transaction_id } } ``` ```js Node.js theme={null} const purchaseorders = await stateset.purchaseorders.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} purchaseorders = stateset.purchaseorders.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} purchaseorders, err := stateset.purchaseorders.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} purchaseorders = Stateset::purchaseorders.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} purchaseorders = Stateset.purchaseorders.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} purchaseorders s = Stateset.purchaseorders.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $purchaseorders = Stateset\purchaseorders::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/purchaseorder HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { { "id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "createdat": "2021-04-20T20:00:00.000Z", "delivery_date": "2021-04-20T20:00:00.000Z", "description": "This is a purchase order.", "external_id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "financer": "0x00000000", "fulfiller": "0x00000000", "lastupdated": "2021-04-20T20:00:00.000Z", "purchase_date": "2021-04-20T20:00:00.000Z", "purchase_order_hash": "0x00000000", "purchase_order_name": "Purchase Order", "purchase_order_number": "po_1NXWPnCo6bFb1KQto6C8OWvE", "purchase_order_status": "0x00000000", "purchaser": "0x00000000", "subtotal": "0.00", "total": "0.00", "vendor": "0x00000000", "transaction_id": "0x00000000" } } ``` # List Purchase Orders Source: https://docs.stateset.com/api-reference/purchaseorders/list GET https://api.stateset.com/v1/purchase_orders/list This lists purchase orders. ### Body This is the limit of the purchase orders. This is the offset of the purchase orders. This is the order direction of the purchase orders. ### Response This is the id of the purchase order. This is the date the purchase order was created. This is the date the purchase order was delivered. This is the description of the purchase order. This is the external id of the purchase order. This is the financer of the purchase order. This is the fulfiller of the purchase order. This is the date the purchase order was last updated. This is the date the purchase order was purchased. This is the hash of the purchase order. This is the name of the purchase order. This is the number of the purchase order. This is the status of the purchase order. This is the purchaser of the purchase order. This is the subtotal of the purchase order. This is the total of the purchase order. This is the vendor of the purchase order. This is the transaction id of the purchase order. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/purchase_order/list' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { purchasorder(limit: $limit, offset: $offset, order_by: {createdDate: $order_direction}) { id createdat delivery_date description external_id financer fulfiller lastupdated purchase_date purchase_order_hash purchase_order_name purchase_order_number purchase_order_status purchaser subtotal total vendor transaction_id } } ``` ```js Node.js theme={null} const purchaseorders = await stateset.purchaseorders.list({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} purchaseorders = stateset.purchaseorders.list({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} purchaseorders, err := stateset.purchaseorders.list( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} purchaseorders = Stateset::purchaseorders.List( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} purchaseorders = Stateset.purchaseorders.list( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} purchaseorders s = Stateset.purchaseorders.list( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $purchaseorders = Stateset\purchaseorders::List( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/purchaseorder HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { { "id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "createdat": "2021-04-20T20:00:00.000Z", "delivery_date": "2021-04-20T20:00:00.000Z", "description": "This is a purchase order.", "external_id": "po_1NXWPnCo6bFb1KQto6C8OWvE", "financer": "0x00000000", "fulfiller": "0x00000000", "lastupdated": "2021-04-20T20:00:00.000Z", "purchase_date": "2021-04-20T20:00:00.000Z", "purchase_order_hash": "0x00000000", "purchase_order_name": "Purchase Order", "purchase_order_number": "po_1NXWPnCo6bFb1KQto6C8OWvE", "purchase_order_status": "0x00000000", "purchaser": "0x00000000", "subtotal": "0.00", "total": "0.00", "vendor": "0x00000000", "transaction_id": "0x00000000" } } ``` # Receive Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/receive Mark a purchase order as received. # Receive Purchase Order Use this endpoint to record receipt of a purchase order. # Update Purchase Order Source: https://docs.stateset.com/api-reference/purchaseorders/update PUT https://api.stateset.com/v1/purchase_orders/:id This endpoint updates an existing purchase order ### Body This is the id of the purchase order. This is the date the purchase order was created. This is the date the purchase order was delivered. This is the description of the purchase order. This is the external id of the purchase order. This is the financer of the purchase order. This is the fulfiller of the purchase order. This is the date the purchase order was last updated. This is the date the purchase order was purchased. This is the hash of the purchase order. This is the name of the purchase order. This is the number of the purchase order. This is the status of the purchase order. This is the purchaser of the purchase order. This is the subtotal of the purchase order. This is the total of the purchase order. This is the vendor of the purchase order. This is the transaction id of the purchase order. ### Response This is the id of the purchase order. This is the date the purchase order was created. This is the date the purchase order was delivered. This is the description of the purchase order. This is the external id of the purchase order. This is the financer of the purchase order. This is the fulfiller of the purchase order. This is the date the purchase order was last updated. This is the date the purchase order was purchased. This is the hash of the purchase order. This is the name of the purchase order. This is the number of the purchase order. This is the status of the purchase order. This is the purchaser of the purchase order. This is the subtotal of the purchase order. This is the total of the purchase order. This is the vendor of the purchase order. This is the transaction id of the purchase order. ```bash cURL theme={null} curl -X PUT https://api.stateset.com/v1/purchaseorders/po_1a2b3c4d5e6f \ -H "Authorization: Bearer ${STATESET_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "purchase_order_status": "received", "delivery_date": "2026-01-28T00:00:00.000Z" }' ``` ```graphQL GraphQL theme={null} mutation UpdatePurchaseOrder( $purchaseorder_id: String! $purchaseorder_x: purchaseorders_set_input! ) { update_purchaseorders( where: { id: { _eq: $purchaseorder_id } } _set: $purchaseorder_x ) { returning { id purchase_order_number purchase_order_status description vendor total subtotal delivery_date lastupdated } } } ``` ```js Node.js theme={null} const purchaseOrder = await stateset.purchaseOrders.update( 'po_1a2b3c4d5e6f', { purchase_order_status: 'received', delivery_date: '2026-01-28T00:00:00.000Z', } ); ``` ```python Python theme={null} purchase_order = stateset.purchase_orders.update( "po_1a2b3c4d5e6f", purchase_order_status="received", delivery_date="2026-01-28T00:00:00.000Z", ) ``` ```ruby Ruby theme={null} purchase_order = Stateset::PurchaseOrder.update( 'po_1a2b3c4d5e6f', { purchase_order_status: 'received', delivery_date: '2026-01-28T00:00:00.000Z', } ) ``` ```go Go theme={null} purchaseOrder, err := stateset.PurchaseOrders.Update( "po_1a2b3c4d5e6f", &stateset.PurchaseOrderUpdateParams{ PurchaseOrderStatus: "received", DeliveryDate: "2026-01-28T00:00:00.000Z", }, ) ``` ```java Java theme={null} Map params = new HashMap<>(); params.put("purchase_order_status", "received"); params.put("delivery_date", "2026-01-28T00:00:00.000Z"); PurchaseOrder purchaseOrder = stateset.purchaseOrders().update( "po_1a2b3c4d5e6f", params ); ``` ```php PHP theme={null} $purchaseOrder = $stateset->purchaseOrders->update( 'po_1a2b3c4d5e6f', [ 'purchase_order_status' => 'received', 'delivery_date' => '2026-01-28T00:00:00.000Z', ] ); ``` ```json Response theme={null} { "id": "po_1a2b3c4d5e6f", "createdat": "2026-01-15T12:00:00.000Z", "delivery_date": "2026-01-28T00:00:00.000Z", "description": "Q1 inventory restock — blue t-shirts", "external_id": "ext_po_98765", "financer": "fin_abc123", "fulfiller": "ful_def456", "lastupdated": "2026-01-28T09:30:00.000Z", "purchase_date": "2026-01-15T00:00:00.000Z", "purchase_order_hash": "a1b2c3d4e5f6", "purchase_order_name": "Q1 Blue T-Shirt Restock", "purchase_order_number": "PO-2026-001234", "purchase_order_status": "received", "purchaser": "usr_abc123", "subtotal": "4200.00", "total": "4500.00", "vendor": "Acme Textiles Inc.", "transaction_id": "txn_789xyz" } ``` # API Quickstart Source: https://docs.stateset.com/api-reference/quickstart Get up and running with the StateSet API in 5 minutes **Time to first API call:** Less than 5 minutes\ **Prerequisites:** Basic programming knowledge and a StateSet account ## Overview This quickstart guide will walk you through making your first StateSet API call, then progressively build up to a complete integration. By the end, you'll be able to: * ✅ Authenticate with the API * ✅ Create and manage orders * ✅ Handle webhooks * ✅ Implement error handling * ✅ Use advanced features ## Step 1: Get Your API Keys Create your account at [stateset.com/sign-up](https://stateset.com/sign-up) Go to **Dashboard → Settings → API Keys** Click **"Create API Key"** and save it securely - you'll only see it once! **Security First:** Never commit API keys to version control. Use environment variables instead. ## Step 2: Set Up Your Environment ```bash theme={null} # Install the StateSet SDK npm install stateset-node dotenv # Create .env file echo "STATESET_API_KEY=sk_test_your_key_here" > .env ``` ```javascript theme={null} // index.js require('dotenv').config(); const { StateSetClient } = require('stateset-node'); const stateset = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); console.log('StateSet client initialized!'); ``` ```bash theme={null} # Install the StateSet SDK pip install stateset-python python-dotenv # Create .env file echo "STATESET_API_KEY=sk_test_your_key_here" > .env ``` ```python theme={null} # main.py import os from dotenv import load_dotenv from stateset import StateSet load_dotenv() stateset = StateSet( api_key=os.getenv('STATESET_API_KEY') ) print('StateSet client initialized!') ``` ```bash theme={null} # Set your API key as an environment variable export STATESET_API_KEY="sk_test_your_key_here" # Test the connection curl https://api.stateset.com/v1/ping \ -H "Authorization: Bearer $STATESET_API_KEY" ``` ## Step 3: Make Your First API Call Let's start with a simple request to list orders: ```javascript Node.js theme={null} async function getOrders() { try { const orders = await stateset.orders.list({ limit: 10, status: 'pending' }); console.log(`Found ${orders.data.length} orders`); orders.data.forEach(order => { console.log(`- Order ${order.order_number}: ${order.status}`); }); } catch (error) { console.error('Error fetching orders:', error.message); } } getOrders(); ``` ```python Python theme={null} def get_orders(): try: orders = stateset.orders.list( limit=10, status='pending' ) print(f"Found {len(orders.data)} orders") for order in orders.data: print(f"- Order {order.order_number}: {order.status}") except Exception as e: print(f"Error fetching orders: {e}") get_orders() ``` ```bash cURL theme={null} curl https://api.stateset.com/v1/orders?limit=10&status=pending \ -H "Authorization: Bearer $STATESET_API_KEY" \ -H "Content-Type: application/json" ``` ## Step 4: Create Your First Resource Now let's create an order: ```javascript Node.js theme={null} async function createOrder() { try { const order = await stateset.orders.create({ customer: { email: 'customer@example.com', first_name: 'John', last_name: 'Doe' }, items: [ { sku: 'WIDGET-001', quantity: 2, price: 2999, // in cents name: 'Premium Widget' } ], shipping_address: { line1: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' }, payment: { method: 'card', payment_intent_id: 'pi_test_123' } }); console.log('Order created successfully!'); console.log(`Order ID: ${order.id}`); console.log(`Order Number: ${order.order_number}`); console.log(`Total: $${(order.totals.total / 100).toFixed(2)}`); return order; } catch (error) { console.error('Error creating order:', error.message); if (error.details) { console.error('Validation errors:', error.details); } } } createOrder(); ``` ```python Python theme={null} def create_order(): try: order = stateset.orders.create( customer={ 'email': 'customer@example.com', 'first_name': 'John', 'last_name': 'Doe' }, items=[ { 'sku': 'WIDGET-001', 'quantity': 2, 'price': 2999, # in cents 'name': 'Premium Widget' } ], shipping_address={ 'line1': '123 Main St', 'city': 'San Francisco', 'state': 'CA', 'postal_code': '94105', 'country': 'US' }, payment={ 'method': 'card', 'payment_intent_id': 'pi_test_123' } ) print('Order created successfully!') print(f'Order ID: {order.id}') print(f'Order Number: {order.order_number}') print(f'Total: ${order.totals.total / 100:.2f}') return order except Exception as e: print(f'Error creating order: {e}') if hasattr(e, 'details'): print(f'Validation errors: {e.details}') create_order() ``` ## Step 5: Handle Webhooks Set up webhook handling for real-time events: ```javascript Express.js theme={null} const express = require('express'); const crypto = require('crypto'); const app = express(); // Middleware to capture raw body for signature verification app.use('/webhooks', express.raw({ type: 'application/json' })); function verifyWebhookSignature(payload, signature, secret) { const elements = signature.split(' '); const timestamp = elements.find(e => e.startsWith('t=')).slice(2); const signatures = elements.filter(e => e.startsWith('v1=')); const signedPayload = `${timestamp}.${payload}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex'); return signatures.some(sig => sig.slice(3) === expectedSignature ); } app.post('/webhooks/stateset', async (req, res) => { const signature = req.headers['stateset-signature']; const secret = process.env.STATESET_WEBHOOK_SECRET; try { // Verify webhook signature if (!verifyWebhookSignature(req.body, signature, secret)) { return res.status(401).json({ error: 'Invalid signature' }); } const event = JSON.parse(req.body); // Handle different event types switch (event.type) { case 'order.created': console.log('New order:', event.data.object.id); await handleNewOrder(event.data.object); break; case 'order.shipped': console.log('Order shipped:', event.data.object.id); await notifyCustomerShipped(event.data.object); break; case 'return.created': console.log('Return initiated:', event.data.object.id); await processReturn(event.data.object); break; default: console.log('Unhandled event type:', event.type); } res.json({ received: true }); } catch (error) { console.error('Webhook error:', error); res.status(400).json({ error: 'Webhook processing failed' }); } }); app.listen(3000, () => { console.log('Webhook server listening on port 3000'); }); ``` ```python Flask theme={null} from flask import Flask, request, jsonify import hmac import hashlib import json import os app = Flask(__name__) def verify_webhook_signature(payload, signature, secret): elements = signature.split(' ') timestamp = next(e[2:] for e in elements if e.startswith('t=')) signatures = [e[3:] for e in elements if e.startswith('v1=')] signed_payload = f"{timestamp}.{payload}" expected_sig = hmac.new( secret.encode(), signed_payload.encode(), hashlib.sha256 ).hexdigest() return expected_sig in signatures @app.route('/webhooks/stateset', methods=['POST']) def handle_webhook(): signature = request.headers.get('stateset-signature') secret = os.getenv('STATESET_WEBHOOK_SECRET') payload = request.get_data(as_text=True) try: # Verify webhook signature if not verify_webhook_signature(payload, signature, secret): return jsonify({'error': 'Invalid signature'}), 401 event = json.loads(payload) # Handle different event types if event['type'] == 'order.created': print(f"New order: {event['data']['object']['id']}") handle_new_order(event['data']['object']) elif event['type'] == 'order.shipped': print(f"Order shipped: {event['data']['object']['id']}") notify_customer_shipped(event['data']['object']) elif event['type'] == 'return.created': print(f"Return initiated: {event['data']['object']['id']}") process_return(event['data']['object']) else: print(f"Unhandled event type: {event['type']}") return jsonify({'received': True}) except Exception as e: print(f"Webhook error: {e}") return jsonify({'error': 'Webhook processing failed'}), 400 if __name__ == '__main__': app.run(port=3000) ``` ## Step 6: Implement Error Handling Add robust error handling to your integration: ```javascript Node.js theme={null} class StateSetAPIHandler { constructor(apiKey) { this.client = new StateSetClient({ apiKey }); this.maxRetries = 3; } async executeWithRetry(operation, data) { let lastError; for (let attempt = 1; attempt <= this.maxRetries; attempt++) { try { return await operation(data); } catch (error) { lastError = error; // Don't retry on validation errors if (error.code === 'VALIDATION_ERROR') { throw error; } // Retry with exponential backoff for rate limits if (error.code === 'RATE_LIMITED' && attempt < this.maxRetries) { const delay = Math.min(1000 * Math.pow(2, attempt), 10000); console.log(`Rate limited. Retrying in ${delay}ms...`); await new Promise(resolve => setTimeout(resolve, delay)); continue; } // Retry on network errors if (error.code === 'NETWORK_ERROR' && attempt < this.maxRetries) { const delay = 1000 * attempt; console.log(`Network error. Retrying in ${delay}ms...`); await new Promise(resolve => setTimeout(resolve, delay)); continue; } } } throw lastError; } async createOrder(orderData) { return this.executeWithRetry( async (data) => await this.client.orders.create(data), orderData ); } handleError(error) { const errorHandlers = { 'VALIDATION_ERROR': () => { console.error('Validation failed:', error.details); // Show validation errors to user }, 'INSUFFICIENT_INVENTORY': () => { console.error('Not enough inventory:', error.details); // Update UI with available quantity }, 'PAYMENT_FAILED': () => { console.error('Payment failed:', error.message); // Prompt for different payment method }, 'RATE_LIMITED': () => { console.error('Rate limited. Please slow down requests.'); // Implement request queuing }, 'UNAUTHORIZED': () => { console.error('Authentication failed. Check API key.'); // Refresh authentication } }; const handler = errorHandlers[error.code] || (() => { console.error('Unexpected error:', error.message); }); handler(); } } ``` ```python Python theme={null} import time from typing import Optional, Callable, Any class StateSetAPIHandler: def __init__(self, api_key: str): self.client = StateSet(api_key=api_key) self.max_retries = 3 def execute_with_retry( self, operation: Callable, data: Any, max_retries: Optional[int] = None ) -> Any: max_retries = max_retries or self.max_retries last_error = None for attempt in range(1, max_retries + 1): try: return operation(data) except Exception as error: last_error = error # Don't retry on validation errors if hasattr(error, 'code') and error.code == 'VALIDATION_ERROR': raise error # Retry with exponential backoff for rate limits if hasattr(error, 'code') and error.code == 'RATE_LIMITED': if attempt < max_retries: delay = min(2 ** attempt, 10) print(f"Rate limited. Retrying in {delay}s...") time.sleep(delay) continue # Retry on network errors if hasattr(error, 'code') and error.code == 'NETWORK_ERROR': if attempt < max_retries: delay = attempt print(f"Network error. Retrying in {delay}s...") time.sleep(delay) continue raise last_error def create_order(self, order_data: dict) -> dict: return self.execute_with_retry( lambda data: self.client.orders.create(**data), order_data ) def handle_error(self, error: Exception) -> None: error_handlers = { 'VALIDATION_ERROR': lambda: print(f"Validation failed: {error.details}"), 'INSUFFICIENT_INVENTORY': lambda: print(f"Not enough inventory: {error.details}"), 'PAYMENT_FAILED': lambda: print(f"Payment failed: {error.message}"), 'RATE_LIMITED': lambda: print("Rate limited. Please slow down requests."), 'UNAUTHORIZED': lambda: print("Authentication failed. Check API key.") } handler = error_handlers.get( getattr(error, 'code', 'UNKNOWN'), lambda: print(f"Unexpected error: {error}") ) handler() ``` ## Step 7: Use Advanced Features ### Pagination Handle large datasets efficiently: ```javascript theme={null} async function getAllOrders() { const allOrders = []; let cursor = null; do { const response = await stateset.orders.list({ limit: 100, cursor: cursor }); allOrders.push(...response.data); cursor = response.pagination.next_cursor; } while (cursor); console.log(`Total orders: ${allOrders.length}`); return allOrders; } ``` ### Filtering and Searching ```javascript theme={null} // Complex filtering const orders = await stateset.orders.list({ status_in: ['pending', 'processing'], created_after: '2024-01-01T00:00:00Z', total_amount_gte: 10000, // $100.00 in cents customer_email_like: '%@example.com', sort: 'created_at', order: 'desc' }); // Full-text search const searchResults = await stateset.orders.search({ query: 'john doe widget', fields: ['customer.email', 'customer.name', 'items.name'], limit: 20 }); ``` ### Batch Operations ```javascript theme={null} // Batch update multiple orders const updates = await stateset.orders.batchUpdate({ filters: { status: 'pending', created_before: '2024-01-01T00:00:00Z' }, updates: { status: 'cancelled', metadata: { cancelled_reason: 'expired' } } }); console.log(`Updated ${updates.affected_count} orders`); ``` ### Idempotency Ensure safe retries with idempotency keys: ```javascript theme={null} const { v4: uuidv4 } = require('uuid'); async function createOrderSafely(orderData) { const idempotencyKey = `order-${uuidv4()}`; try { return await stateset.orders.create(orderData, { idempotencyKey: idempotencyKey }); } catch (error) { if (error.code === 'DUPLICATE_REQUEST') { console.log('Order already created:', error.details.existing_id); return error.details.existing_resource; } throw error; } } ``` ## Complete Example: Order Management System Here's a complete example that ties everything together: ```javascript Node.js theme={null} const { StateSetClient } = require('stateset-node'); const express = require('express'); require('dotenv').config(); class OrderManagementSystem { constructor() { this.stateset = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); this.app = express(); this.setupRoutes(); } setupRoutes() { this.app.use(express.json()); // Create order endpoint this.app.post('/api/orders', async (req, res) => { try { const order = await this.createOrder(req.body); res.json({ success: true, order }); } catch (error) { this.handleApiError(error, res); } }); // Get orders endpoint this.app.get('/api/orders', async (req, res) => { try { const orders = await this.getOrders(req.query); res.json({ success: true, orders }); } catch (error) { this.handleApiError(error, res); } }); // Update order status this.app.patch('/api/orders/:id/status', async (req, res) => { try { const order = await this.updateOrderStatus( req.params.id, req.body.status ); res.json({ success: true, order }); } catch (error) { this.handleApiError(error, res); } }); // Webhook endpoint this.app.post('/webhooks/stateset', express.raw({ type: 'application/json' }), async (req, res) => { await this.handleWebhook(req, res); } ); } async createOrder(orderData) { // Validate order data this.validateOrderData(orderData); // Check inventory await this.checkInventory(orderData.items); // Create order with idempotency const idempotencyKey = `order-${Date.now()}-${orderData.customer.email}`; const order = await this.stateset.orders.create(orderData, { idempotencyKey }); // Send confirmation email await this.sendOrderConfirmation(order); return order; } async getOrders(filters) { const orders = await this.stateset.orders.list({ limit: filters.limit || 20, status: filters.status, created_after: filters.from_date, created_before: filters.to_date, sort: filters.sort || 'created_at', order: filters.order || 'desc' }); return orders; } async updateOrderStatus(orderId, newStatus) { // Validate status transition const order = await this.stateset.orders.get(orderId); this.validateStatusTransition(order.status, newStatus); // Update order const updated = await this.stateset.orders.update(orderId, { status: newStatus }); // Trigger relevant workflows await this.triggerStatusWorkflow(updated); return updated; } async handleWebhook(req, res) { // Verify signature if (!this.verifyWebhook(req)) { return res.status(401).json({ error: 'Invalid signature' }); } const event = JSON.parse(req.body); try { switch (event.type) { case 'order.created': await this.onOrderCreated(event.data.object); break; case 'order.shipped': await this.onOrderShipped(event.data.object); break; case 'return.created': await this.onReturnCreated(event.data.object); break; } res.json({ received: true }); } catch (error) { console.error('Webhook processing error:', error); res.status(500).json({ error: 'Processing failed' }); } } validateOrderData(data) { const required = ['customer', 'items', 'shipping_address']; for (const field of required) { if (!data[field]) { throw new Error(`Missing required field: ${field}`); } } if (!data.items.length) { throw new Error('Order must contain at least one item'); } } async checkInventory(items) { for (const item of items) { const inventory = await this.stateset.inventory.get(item.sku); if (inventory.available < item.quantity) { throw new Error( `Insufficient inventory for ${item.sku}. ` + `Available: ${inventory.available}` ); } } } validateStatusTransition(currentStatus, newStatus) { const validTransitions = { 'pending': ['processing', 'cancelled'], 'processing': ['shipped', 'cancelled'], 'shipped': ['delivered', 'returned'], 'delivered': ['returned'], 'cancelled': [], 'returned': [] }; if (!validTransitions[currentStatus].includes(newStatus)) { throw new Error( `Invalid status transition from ${currentStatus} to ${newStatus}` ); } } handleApiError(error, res) { const statusMap = { 'VALIDATION_ERROR': 400, 'UNAUTHORIZED': 401, 'FORBIDDEN': 403, 'NOT_FOUND': 404, 'RATE_LIMITED': 429, 'INTERNAL_ERROR': 500 }; const status = statusMap[error.code] || 500; res.status(status).json({ success: false, error: { code: error.code, message: error.message, details: error.details } }); } start(port = 3000) { this.app.listen(port, () => { console.log(`Order Management System running on port ${port}`); }); } } // Start the system const oms = new OrderManagementSystem(); oms.start(); ``` ```python Python theme={null} from flask import Flask, request, jsonify from stateset import StateSet import os from datetime import datetime from dotenv import load_dotenv load_dotenv() class OrderManagementSystem: def __init__(self): self.stateset = StateSet(api_key=os.getenv('STATESET_API_KEY')) self.app = Flask(__name__) self.setup_routes() def setup_routes(self): @self.app.route('/api/orders', methods=['POST']) def create_order(): try: order = self.create_order(request.json) return jsonify({'success': True, 'order': order}) except Exception as e: return self.handle_api_error(e) @self.app.route('/api/orders', methods=['GET']) def get_orders(): try: orders = self.get_orders(request.args) return jsonify({'success': True, 'orders': orders}) except Exception as e: return self.handle_api_error(e) @self.app.route('/api/orders//status', methods=['PATCH']) def update_status(order_id): try: order = self.update_order_status( order_id, request.json['status'] ) return jsonify({'success': True, 'order': order}) except Exception as e: return self.handle_api_error(e) @self.app.route('/webhooks/stateset', methods=['POST']) def handle_webhook(): return self.handle_webhook(request) def create_order(self, order_data): # Validate order data self.validate_order_data(order_data) # Check inventory self.check_inventory(order_data['items']) # Create order with idempotency idempotency_key = f"order-{datetime.now().timestamp()}-{order_data['customer']['email']}" order = self.stateset.orders.create( **order_data, idempotency_key=idempotency_key ) # Send confirmation self.send_order_confirmation(order) return order def get_orders(self, filters): orders = self.stateset.orders.list( limit=filters.get('limit', 20), status=filters.get('status'), created_after=filters.get('from_date'), created_before=filters.get('to_date'), sort=filters.get('sort', 'created_at'), order=filters.get('order', 'desc') ) return orders def update_order_status(self, order_id, new_status): # Get current order order = self.stateset.orders.get(order_id) # Validate transition self.validate_status_transition(order.status, new_status) # Update order updated = self.stateset.orders.update( order_id, status=new_status ) # Trigger workflows self.trigger_status_workflow(updated) return updated def validate_order_data(self, data): required = ['customer', 'items', 'shipping_address'] for field in required: if field not in data: raise ValueError(f"Missing required field: {field}") if not data['items']: raise ValueError("Order must contain at least one item") def check_inventory(self, items): for item in items: inventory = self.stateset.inventory.get(item['sku']) if inventory.available < item['quantity']: raise ValueError( f"Insufficient inventory for {item['sku']}. " f"Available: {inventory.available}" ) def validate_status_transition(self, current_status, new_status): valid_transitions = { 'pending': ['processing', 'cancelled'], 'processing': ['shipped', 'cancelled'], 'shipped': ['delivered', 'returned'], 'delivered': ['returned'], 'cancelled': [], 'returned': [] } if new_status not in valid_transitions.get(current_status, []): raise ValueError( f"Invalid status transition from {current_status} to {new_status}" ) def handle_api_error(self, error): status_map = { 'VALIDATION_ERROR': 400, 'UNAUTHORIZED': 401, 'FORBIDDEN': 403, 'NOT_FOUND': 404, 'RATE_LIMITED': 429, 'INTERNAL_ERROR': 500 } error_code = getattr(error, 'code', 'INTERNAL_ERROR') status = status_map.get(error_code, 500) return jsonify({ 'success': False, 'error': { 'code': error_code, 'message': str(error), 'details': getattr(error, 'details', None) } }), status def start(self, port=3000): self.app.run(port=port, debug=True) # Start the system if __name__ == '__main__': oms = OrderManagementSystem() oms.start() ``` ## Next Steps Now that you have a working integration, explore these advanced features: Use our GraphQL API for flexible queries Process multiple resources efficiently Subscribe to real-time events via WebSockets Implement full-text search and filtering ## Resources ### Documentation * [API Reference](/api-reference/introduction) - Complete API documentation * [SDKs](/api-reference/sdks) - Language-specific SDKs * [Authentication](/api-reference/authentication) - Auth methods and security * [Error Handling](/api-reference/errors) - Error codes and handling ### Code Examples * [GitHub Examples](https://github.com/stateset/examples) - Sample implementations * [Postman Collection](https://postman.com/stateset) - Pre-built API requests * [CodeSandbox Templates](https://codesandbox.io/s/stateset) - Live playground ### Support * [Discord Community](https://discord.gg/VfcaqgZywq) - Get help from the community * [API Status](https://status.stateset.com) - Check service status * [Support Email](mailto:api-support@stateset.com) - Direct support ## Troubleshooting **Problem:** Getting 401 Unauthorized errors **Solutions:** * Verify your API key is correct and active * Check you're using the right environment (test vs live) * Ensure Bearer prefix in Authorization header * Verify API key has required permissions **Problem:** Getting 429 Too Many Requests errors **Solutions:** * Implement exponential backoff * Cache frequently accessed data * Use batch operations where possible * Consider upgrading your plan for higher limits **Problem:** Webhooks not being received **Solutions:** * Verify webhook URL is publicly accessible * Check webhook signature verification * Ensure your server responds with 2xx status * Test with webhook simulator in dashboard **Problem:** Getting validation errors **Solutions:** * Check required fields are included * Verify data types match specification * Ensure enum values are valid * Review error details for specific issues *** 🎉 **Congratulations!** You've successfully integrated with the StateSet API. You're now ready to build powerful commerce applications! For questions or feedback, reach out on [Discord](https://discord.gg/VfcaqgZywq) or email [api-support@stateset.com](mailto:api-support@stateset.com). # Rate Limiting & Performance Source: https://docs.stateset.com/api-reference/rate-limiting Optimize your API usage with rate limiting strategies and performance best practices Understanding and working with StateSet's rate limits ensures reliable, high-performance integrations. ## Overview StateSet implements intelligent rate limiting to ensure fair usage and maintain optimal performance for all users. Our system uses a sliding window algorithm with burst capacity to handle traffic spikes while preventing abuse. ### Key Concepts * **Request Quota**: Maximum requests allowed per time window * **Burst Capacity**: Short-term allowance for traffic spikes * **Sliding Window**: Continuous evaluation of request rate * **Adaptive Throttling**: Dynamic adjustment based on system load * **Priority Queuing**: Critical endpoints get preferential treatment ## Rate Limits by Plan | Plan | Requests/Min | Requests/Hour | Requests/Day | Burst Capacity | Concurrent | | -------------- | ------------ | ------------- | ------------ | -------------- | ---------- | | **Free** | 60 | 1,000 | 10,000 | 100/sec | 10 | | **Starter** | 100 | 5,000 | 50,000 | 200/sec | 25 | | **Growth** | 1,000 | 30,000 | 500,000 | 1,000/sec | 100 | | **Scale** | 5,000 | 150,000 | 2,000,000 | 5,000/sec | 500 | | **Enterprise** | Custom | Custom | Unlimited | Custom | Unlimited | | Endpoint Category | Multiplier | Example Endpoints | | -------------------- | ---------- | ---------------------------- | | **Read Operations** | 1x | GET /orders, GET /customers | | **Write Operations** | 2x | POST /orders, PUT /products | | **Search/Analytics** | 5x | POST /search, GET /analytics | | **Bulk Operations** | 10x | POST /batch, POST /import | | **Webhooks** | 0.5x | POST /webhooks/simulate | | **Health Checks** | 0x | GET /health, GET /ping | | Resource | Limit | Notes | | ------------------ | ---------- | ----------------------------------- | | Max request size | 10 MB | 100 MB for file uploads | | Max response size | 50 MB | Use pagination for larger datasets | | Max items per page | 1,000 | Default: 100 | | Max batch size | 1,000 | Async processing for larger batches | | Max search results | 10,000 | Use cursor for deep pagination | | Request timeout | 30 seconds | 5 minutes for bulk operations | ## Rate Limit Headers Every API response includes rate limit information: ```http theme={null} HTTP/1.1 200 OK X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 995 X-RateLimit-Reset: 1704070800 X-RateLimit-Reset-After: 45 X-RateLimit-Bucket: api X-RateLimit-Retry-After: 0 X-Request-Id: req_1NXWPnCo6bFb1KQto6C8OWvE ``` ### Header Descriptions | Header | Description | Example | | ------------------------- | -------------------------------- | ------------ | | `X-RateLimit-Limit` | Max requests in current window | `1000` | | `X-RateLimit-Remaining` | Requests remaining in window | `995` | | `X-RateLimit-Reset` | Unix timestamp when limit resets | `1704070800` | | `X-RateLimit-Reset-After` | Seconds until limit resets | `45` | | `X-RateLimit-Bucket` | Rate limit bucket identifier | `api` | | `X-RateLimit-Retry-After` | Seconds to wait if rate limited | `10` | ## Handling Rate Limits ### Exponential Backoff Implementation ```javascript Node.js theme={null} class RateLimitHandler { constructor(options = {}) { this.maxRetries = options.maxRetries || 5; this.baseDelay = options.baseDelay || 1000; this.maxDelay = options.maxDelay || 32000; this.jitter = options.jitter || true; } async executeWithRetry(fn) { let lastError; for (let attempt = 0; attempt <= this.maxRetries; attempt++) { try { const response = await fn(); // Check rate limit headers this.trackRateLimit(response.headers); return response; } catch (error) { lastError = error; if (error.status === 429) { const delay = this.calculateDelay(error, attempt); console.log(`Rate limited. Waiting ${delay}ms before retry ${attempt + 1}/${this.maxRetries}`); if (attempt < this.maxRetries) { await this.sleep(delay); continue; } } // Don't retry on other errors throw error; } } throw lastError; } calculateDelay(error, attempt) { // Use server-provided retry delay if available const retryAfter = error.headers?.['x-ratelimit-retry-after']; if (retryAfter) { return parseInt(retryAfter) * 1000; } // Calculate exponential backoff let delay = Math.min( this.baseDelay * Math.pow(2, attempt), this.maxDelay ); // Add jitter to prevent thundering herd if (this.jitter) { delay = delay * (0.5 + Math.random() * 0.5); } return Math.floor(delay); } trackRateLimit(headers) { const remaining = parseInt(headers['x-ratelimit-remaining']); const limit = parseInt(headers['x-ratelimit-limit']); if (remaining < limit * 0.2) { console.warn(`Rate limit warning: ${remaining}/${limit} requests remaining`); } } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Usage const rateLimiter = new RateLimitHandler(); async function makeApiCall() { return rateLimiter.executeWithRetry(async () => { return await fetch('https://api.stateset.com/v1/orders', { headers: { 'Authorization': `Bearer ${API_KEY}` } }); }); } ``` ```python Python theme={null} import time import random from typing import Callable, Optional, Any import requests class RateLimitHandler: def __init__( self, max_retries: int = 5, base_delay: float = 1.0, max_delay: float = 32.0, jitter: bool = True ): self.max_retries = max_retries self.base_delay = base_delay self.max_delay = max_delay self.jitter = jitter def execute_with_retry(self, fn: Callable) -> Any: last_error = None for attempt in range(self.max_retries + 1): try: response = fn() # Track rate limit status self.track_rate_limit(response.headers) return response except requests.HTTPError as error: last_error = error if error.response.status_code == 429: delay = self.calculate_delay(error.response, attempt) print(f"Rate limited. Waiting {delay:.2f}s before retry {attempt + 1}/{self.max_retries}") if attempt < self.max_retries: time.sleep(delay) continue # Don't retry other errors raise error raise last_error def calculate_delay( self, response: requests.Response, attempt: int ) -> float: # Use server-provided retry delay if available retry_after = response.headers.get('X-RateLimit-Retry-After') if retry_after: return float(retry_after) # Calculate exponential backoff delay = min( self.base_delay * (2 ** attempt), self.max_delay ) # Add jitter to prevent thundering herd if self.jitter: delay *= (0.5 + random.random() * 0.5) return delay def track_rate_limit(self, headers: dict) -> None: remaining = int(headers.get('X-RateLimit-Remaining', 0)) limit = int(headers.get('X-RateLimit-Limit', 1)) if remaining < limit * 0.2: print(f"Rate limit warning: {remaining}/{limit} requests remaining") # Usage rate_limiter = RateLimitHandler() def make_api_call(): return rate_limiter.execute_with_retry(lambda: requests.get( 'https://api.stateset.com/v1/orders', headers={'Authorization': f'Bearer {API_KEY}'} )) ``` ### Circuit Breaker Pattern Prevent cascading failures with circuit breaker: ```javascript theme={null} class CircuitBreaker { constructor(options = {}) { this.failureThreshold = options.failureThreshold || 5; this.successThreshold = options.successThreshold || 2; this.timeout = options.timeout || 60000; this.state = 'CLOSED'; this.failures = 0; this.successes = 0; this.nextAttempt = Date.now(); } async execute(fn) { if (this.state === 'OPEN') { if (Date.now() < this.nextAttempt) { throw new Error('Circuit breaker is OPEN'); } this.state = 'HALF_OPEN'; } try { const result = await fn(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { this.failures = 0; if (this.state === 'HALF_OPEN') { this.successes++; if (this.successes >= this.successThreshold) { this.state = 'CLOSED'; this.successes = 0; } } } onFailure() { this.successes = 0; this.failures++; if (this.failures >= this.failureThreshold) { this.state = 'OPEN'; this.nextAttempt = Date.now() + this.timeout; console.error(`Circuit breaker opened. Will retry at ${new Date(this.nextAttempt)}`); } } getState() { return { state: this.state, failures: this.failures, successes: this.successes, nextAttempt: this.state === 'OPEN' ? new Date(this.nextAttempt) : null }; } } ``` ## Performance Optimization ### 1. Request Batching Combine multiple operations into single requests: ```javascript theme={null} // Instead of multiple individual requests const orders = []; for (const customerId of customerIds) { const order = await stateset.orders.list({ customer_id: customerId }); orders.push(...order.data); } // Use batch operations const orders = await stateset.orders.batchGet({ customer_ids: customerIds }); // Or use GraphQL for complex queries const query = ` query GetMultipleOrders($customerIds: [ID!]!) { orders(where: { customer_id: { _in: $customerIds } }) { id status total customer { email } } } `; ``` ### 2. Response Caching Implement intelligent caching to reduce API calls: ```javascript theme={null} class CachedAPIClient { constructor(client, cache) { this.client = client; this.cache = cache; } async get(resource, id, options = {}) { const cacheKey = `${resource}:${id}`; const ttl = options.ttl || 300; // 5 minutes default // Check cache const cached = await this.cache.get(cacheKey); if (cached && !options.force) { return JSON.parse(cached); } // Fetch from API const data = await this.client[resource].get(id); // Cache result await this.cache.setex(cacheKey, ttl, JSON.stringify(data)); return data; } async list(resource, filters = {}, options = {}) { const cacheKey = `${resource}:list:${JSON.stringify(filters)}`; const ttl = options.ttl || 60; // 1 minute for lists // Check cache const cached = await this.cache.get(cacheKey); if (cached && !options.force) { return JSON.parse(cached); } // Fetch from API const data = await this.client[resource].list(filters); // Cache result await this.cache.setex(cacheKey, ttl, JSON.stringify(data)); return data; } async invalidate(resource, id = null) { if (id) { await this.cache.del(`${resource}:${id}`); } else { // Invalidate all cached lists for this resource const keys = await this.cache.keys(`${resource}:list:*`); if (keys.length) { await this.cache.del(...keys); } } } } ``` ### 3. Pagination Strategies Efficiently handle large datasets: ```javascript theme={null} class PaginationHelper { async *iterateAll(resource, filters = {}) { let cursor = null; do { const response = await stateset[resource].list({ ...filters, limit: 100, cursor }); for (const item of response.data) { yield item; } cursor = response.pagination.next_cursor; // Rate limit friendly delay await new Promise(r => setTimeout(r, 100)); } while (cursor); } async getAllPages(resource, filters = {}) { const items = []; for await (const item of this.iterateAll(resource, filters)) { items.push(item); } return items; } async getParallel(resource, filters = {}, concurrency = 3) { // First request to get total count const first = await stateset[resource].list({ ...filters, limit: 100 }); const totalPages = Math.ceil(first.pagination.total_count / 100); const results = [first.data]; // Parallel fetch remaining pages const promises = []; for (let page = 2; page <= totalPages; page++) { promises.push( this.fetchPage(resource, filters, page, concurrency) ); } const pages = await Promise.all(promises); results.push(...pages.flat()); return results.flat(); } async fetchPage(resource, filters, page, concurrency) { // Rate limiting with concurrency control await this.rateLimitQueue(concurrency); const response = await stateset[resource].list({ ...filters, limit: 100, offset: (page - 1) * 100 }); return response.data; } } ``` ### 4. Field Selection Request only the data you need: ```javascript theme={null} // REST API - Use sparse fieldsets const orders = await stateset.orders.list({ fields: ['id', 'status', 'total', 'customer.email'] }); // GraphQL - Precise field selection const query = ` query GetOrders { orders(limit: 10) { id status total customer { email } } } `; ``` ### 5. Compression Enable response compression: ```javascript theme={null} const response = await fetch('https://api.stateset.com/v1/orders', { headers: { 'Authorization': `Bearer ${API_KEY}`, 'Accept-Encoding': 'gzip, deflate, br' } }); // SDK automatically handles compression const stateset = new StateSetClient({ apiKey: API_KEY, compression: true // Default: true }); ``` ## Request Prioritization ### Priority Queuing System ```javascript theme={null} class PriorityRequestQueue { constructor() { this.queues = { high: [], medium: [], low: [] }; this.processing = false; this.concurrency = 5; this.active = 0; } async add(request, priority = 'medium') { return new Promise((resolve, reject) => { this.queues[priority].push({ request, resolve, reject, timestamp: Date.now() }); this.process(); }); } async process() { if (this.processing) return; this.processing = true; while (this.hasRequests() && this.active < this.concurrency) { const item = this.getNext(); if (!item) break; this.active++; this.execute(item).finally(() => { this.active--; this.process(); }); } this.processing = false; } getNext() { // Priority order: high > medium > low for (const priority of ['high', 'medium', 'low']) { if (this.queues[priority].length > 0) { return this.queues[priority].shift(); } } return null; } hasRequests() { return Object.values(this.queues).some(q => q.length > 0); } async execute(item) { try { const result = await item.request(); item.resolve(result); } catch (error) { item.reject(error); } } } // Usage const queue = new PriorityRequestQueue(); // High priority request const criticalOrder = await queue.add( () => stateset.orders.create(orderData), 'high' ); // Low priority analytics const analytics = await queue.add( () => stateset.analytics.get(query), 'low' ); ``` ## Monitoring and Analytics ### Rate Limit Monitoring ```javascript theme={null} class RateLimitMonitor { constructor() { this.metrics = { requests: 0, rateLimited: 0, remaining: null, limit: null }; } track(response) { this.metrics.requests++; const headers = response.headers; this.metrics.remaining = parseInt(headers['x-ratelimit-remaining']); this.metrics.limit = parseInt(headers['x-ratelimit-limit']); if (response.status === 429) { this.metrics.rateLimited++; this.onRateLimit(headers); } // Alert when approaching limit const usage = (this.metrics.limit - this.metrics.remaining) / this.metrics.limit; if (usage > 0.8) { this.alertHighUsage(usage); } } onRateLimit(headers) { console.error('Rate limited!', { retryAfter: headers['x-ratelimit-retry-after'], resetAt: new Date(parseInt(headers['x-ratelimit-reset']) * 1000) }); // Send alert alerting.send({ type: 'RATE_LIMIT', severity: 'high', details: this.metrics }); } alertHighUsage(usage) { console.warn(`High API usage: ${(usage * 100).toFixed(1)}%`); if (usage > 0.9) { // Implement throttling this.throttle(); } } throttle() { // Add delay between requests this.throttleDelay = 1000; console.log('Throttling enabled: 1s delay between requests'); } getMetrics() { return { ...this.metrics, usagePercent: ((this.metrics.limit - this.metrics.remaining) / this.metrics.limit * 100).toFixed(1), rateLimitPercent: (this.metrics.rateLimited / this.metrics.requests * 100).toFixed(2) }; } } ``` ### Performance Metrics ```javascript theme={null} class PerformanceTracker { constructor() { this.metrics = new Map(); } async track(name, fn) { const start = performance.now(); const startMemory = process.memoryUsage(); try { const result = await fn(); const duration = performance.now() - start; const memoryDelta = process.memoryUsage().heapUsed - startMemory.heapUsed; this.record(name, { duration, memoryDelta, success: true }); return result; } catch (error) { const duration = performance.now() - start; this.record(name, { duration, success: false, error: error.message }); throw error; } } record(name, metrics) { if (!this.metrics.has(name)) { this.metrics.set(name, { count: 0, totalDuration: 0, avgDuration: 0, maxDuration: 0, minDuration: Infinity, errors: 0 }); } const stats = this.metrics.get(name); stats.count++; stats.totalDuration += metrics.duration; stats.avgDuration = stats.totalDuration / stats.count; stats.maxDuration = Math.max(stats.maxDuration, metrics.duration); stats.minDuration = Math.min(stats.minDuration, metrics.duration); if (!metrics.success) { stats.errors++; } // Log slow requests if (metrics.duration > 5000) { console.warn(`Slow API call: ${name} took ${metrics.duration.toFixed(2)}ms`); } } getReport() { const report = {}; for (const [name, stats] of this.metrics) { report[name] = { ...stats, avgDuration: stats.avgDuration.toFixed(2), errorRate: ((stats.errors / stats.count) * 100).toFixed(2) + '%' }; } return report; } } // Usage const tracker = new PerformanceTracker(); const orders = await tracker.track('fetchOrders', async () => { return await stateset.orders.list({ limit: 100 }); }); console.log(tracker.getReport()); ``` ## Best Practices ### 1. Implement Graceful Degradation ```javascript theme={null} class ResilientAPIClient { async getOrdersWithFallback() { try { // Try primary method return await this.fetchFromAPI(); } catch (error) { if (error.status === 429) { // Fall back to cached data return await this.fetchFromCache(); } else if (error.status >= 500) { // Fall back to secondary system return await this.fetchFromBackup(); } throw error; } } } ``` ### 2. Use Webhooks Instead of Polling ```javascript theme={null} // Bad: Polling for updates setInterval(async () => { const orders = await stateset.orders.list({ updated_after: lastCheck }); processUpdates(orders); }, 60000); // Good: Use webhooks app.post('/webhook', (req, res) => { const event = req.body; if (event.type === 'order.updated') { processUpdate(event.data.object); } res.sendStatus(200); }); ``` ### 3. Optimize Batch Sizes ```javascript theme={null} class BatchProcessor { async processBatch(items, batchSize = 100) { const results = []; for (let i = 0; i < items.length; i += batchSize) { const batch = items.slice(i, i + batchSize); const result = await stateset.batch.process(batch); results.push(...result); // Rate limit friendly delay if (i + batchSize < items.length) { await new Promise(r => setTimeout(r, 1000)); } } return results; } } ``` ## Troubleshooting **Solutions:** * Implement request queuing and batching * Cache frequently accessed data * Use webhooks instead of polling * Consider upgrading your plan * Optimize request patterns **Solutions:** * Use field selection to reduce payload size * Enable compression * Implement pagination for large datasets * Use regional endpoints if available * Check network latency **Possible causes:** * Hitting endpoint-specific limits * Burst rate exceeded * Account-level restrictions * Check rate limit headers for details **Solutions:** * Increase failure threshold * Implement better error handling * Check for systematic issues * Review timeout settings * Monitor API status page ## Related Resources * [API Quickstart](/api-reference/quickstart) - Get started quickly * [Error Handling](/api-reference/errors) - Handle errors gracefully * [Webhooks](/api-reference/webhooks) - Real-time event notifications * [Batch Operations](/api-reference/batch) - Process data efficiently *** **Need help optimizing your integration?** Contact [api-support@stateset.com](mailto:api-support@stateset.com) or visit our [Discord community](https://discord.gg/VfcaqgZywq). # Cancel Refund Source: https://docs.stateset.com/api-reference/refunds/cancel POST https://api.stateset.com/v1/refunds/:id/cancel Cancel a pending or processing refund This endpoint cancels a refund that is in pending or processing status. Once a refund is completed, it cannot be cancelled. ## Authentication This endpoint requires a valid API key with `refunds:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the refund to cancel ## Request Body Reason for cancellation Whether to notify customer of cancellation ### Response Returns the cancelled refund object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/refunds/refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "reason": "Customer requested to keep the product", "notify_customer": true }' ``` ```javascript Node.js theme={null} const refund = await stateset.refunds.cancel( 'refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { reason: "Customer requested to keep the product", notify_customer: true } ); ``` ```python Python theme={null} refund = stateset.refunds.cancel( 'refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', reason="Customer requested to keep the product", notify_customer=True ) ``` ```json Response theme={null} { "id": "refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "refund", "order_id": "order_123456", "customer_id": "cust_abc123", "type": "partial", "status": "cancelled", "previous_status": "processing", "reason": "product_damaged", "reason_details": "Item arrived with scratches on the surface", "cancellation": { "reason": "Customer requested to keep the product", "cancelled_at": "2024-06-21T10:00:00Z", "cancelled_by": "user_456" }, "amounts": { "subtotal": 4999, "tax": 450, "shipping": 0, "total": 5449, "currency": "USD" }, "timeline": [ { "status": "created", "timestamp": "2024-01-20T13:30:00Z", "actor": "customer" }, { "status": "approved", "timestamp": "2024-01-20T13:30:01Z", "actor": "system" }, { "status": "processing", "timestamp": "2024-01-20T13:30:02Z", "actor": "system" }, { "status": "cancelled", "timestamp": "2024-06-21T10:00:00Z", "actor": "user_456", "note": "Customer requested to keep the product" } ], "updated_at": "2024-06-21T10:00:00Z", "notifications": { "customer_notified": true, "notification_sent_at": "2024-06-21T10:00:05Z" } } ``` # Create Refund Source: https://docs.stateset.com/api-reference/refunds/create POST https://api.stateset.com/v1/refunds Create a refund for an order or specific items This endpoint creates a refund request that can process partial or full refunds. It handles payment reversals, inventory adjustments, and customer notifications. ## Authentication This endpoint requires a valid API key with `refunds:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Original order ID to refund Refund type: "full", "partial", "item\_return", "shipping", "tax\_only" Refund reason code Detailed explanation of refund reason Items to refund (required for partial/item refunds) Original order line item ID Quantity to refund Override refund amount in cents Whether to restock this item Location to restock to Refund amounts breakdown Items subtotal to refund in cents Tax amount to refund in cents Shipping amount to refund in cents Manual adjustment amount (positive or negative) Total refund amount in cents Refund payment method Refund method: "original\_payment", "store\_credit", "gift\_card", "check", "manual" Original payment ID to refund to Store credit account ID Return shipping details Whether return shipping label is needed Return carrier Return service type Pre-generated return label ID Processing options Auto-approve if within policy Send customer notification Process payment refund immediately Internal notes about the refund Additional custom fields ### Response Returns the created refund object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/refunds' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "order_id": "order_123456", "type": "partial", "reason": "product_damaged", "reason_details": "Item arrived with scratches on the surface", "items": [ { "line_item_id": "li_abc123", "quantity": 1, "restock": false } ], "amounts": { "subtotal": 4999, "tax": 450, "shipping": 0, "total": 5449 }, "payment_method": { "type": "original_payment", "payment_id": "pay_xyz789" }, "processing": { "auto_approve": true, "notify_customer": true, "process_immediately": true } }' ``` ```javascript Node.js theme={null} const refund = await stateset.refunds.create({ order_id: "order_123456", type: "partial", reason: "product_damaged", reason_details: "Item arrived with scratches on the surface", items: [ { line_item_id: "li_abc123", quantity: 1, restock: false } ], amounts: { subtotal: 4999, tax: 450, shipping: 0, total: 5449 }, payment_method: { type: "original_payment", payment_id: "pay_xyz789" }, processing: { auto_approve: true, notify_customer: true, process_immediately: true } }); ``` ```python Python theme={null} refund = stateset.refunds.create( order_id="order_123456", type="partial", reason="product_damaged", reason_details="Item arrived with scratches on the surface", items=[ { "line_item_id": "li_abc123", "quantity": 1, "restock": False } ], amounts={ "subtotal": 4999, "tax": 450, "shipping": 0, "total": 5449 }, payment_method={ "type": "original_payment", "payment_id": "pay_xyz789" }, processing={ "auto_approve": True, "notify_customer": True, "process_immediately": True } ) ``` ```json Response theme={null} { "id": "refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "refund", "order_id": "order_123456", "customer_id": "cust_abc123", "type": "partial", "status": "processing", "reason": "product_damaged", "reason_details": "Item arrived with scratches on the surface", "items": [ { "line_item_id": "li_abc123", "product_id": "prod_123", "product_name": "Wireless Headphones", "quantity": 1, "refund_amount": 4999, "restock": false, "restock_status": "not_restocking" } ], "amounts": { "subtotal": 4999, "tax": 450, "shipping": 0, "adjustment": 0, "total": 5449, "currency": "USD" }, "payment_method": { "type": "original_payment", "payment_id": "pay_xyz789", "last4": "4242", "brand": "visa" }, "payment_status": "pending", "transaction_id": null, "processing": { "auto_approved": true, "approved_at": "2024-01-20T13:30:00Z", "approved_by": "system" }, "shipping": { "return_required": false, "return_label_id": null }, "timeline": [ { "status": "created", "timestamp": "2024-01-20T13:30:00Z", "actor": "customer" }, { "status": "approved", "timestamp": "2024-01-20T13:30:01Z", "actor": "system" }, { "status": "processing", "timestamp": "2024-01-20T13:30:02Z", "actor": "system" } ], "created_at": "2024-01-20T13:30:00Z", "updated_at": "2024-01-20T13:30:02Z", "estimated_completion": "2024-01-23T13:30:00Z", "notes": null, "metadata": {} } ``` # Get Refund Source: https://docs.stateset.com/api-reference/refunds/get GET https://api.stateset.com/v1/refunds/:id Retrieve details of a specific refund This endpoint retrieves detailed information about a specific refund, including its current status, timeline, and associated transactions. ## Authentication This endpoint requires a valid API key with `refunds:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the refund ### Response Returns the refund object if found. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/refunds/refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const refund = await stateset.refunds.retrieve( 'refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} refund = stateset.refunds.retrieve( 'refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "refund", "order_id": "order_123456", "customer_id": "cust_abc123", "type": "partial", "status": "completed", "reason": "product_damaged", "reason_details": "Item arrived with scratches on the surface", "items": [ { "line_item_id": "li_abc123", "product_id": "prod_123", "product_name": "Wireless Headphones", "sku": "WH-001", "quantity": 1, "refund_amount": 4999, "restock": false, "restock_status": "not_restocking", "images": [ "https://refunds.stateset.com/images/refund_0901f083_damage_1.jpg" ] } ], "amounts": { "subtotal": 4999, "tax": 450, "shipping": 0, "adjustment": 0, "total": 5449, "currency": "USD" }, "payment_method": { "type": "original_payment", "payment_id": "pay_xyz789", "last4": "4242", "brand": "visa" }, "payment_status": "completed", "transaction_id": "txn_refund_456789", "processing": { "auto_approved": true, "approved_at": "2024-01-20T13:30:00Z", "approved_by": "system", "completed_at": "2024-01-23T13:30:00Z" }, "shipping": { "return_required": false, "return_label_id": null, "return_tracking": null }, "timeline": [ { "status": "created", "timestamp": "2024-01-20T13:30:00Z", "actor": "customer", "note": "Refund requested by customer" }, { "status": "approved", "timestamp": "2024-01-20T13:30:01Z", "actor": "system", "note": "Auto-approved per return policy" }, { "status": "processing", "timestamp": "2024-01-20T13:30:02Z", "actor": "system", "note": "Payment refund initiated" }, { "status": "completed", "timestamp": "2024-01-23T13:30:00Z", "actor": "system", "note": "Refund processed successfully" } ], "created_at": "2024-01-20T13:30:00Z", "updated_at": "2024-01-23T13:30:00Z", "notes": "Customer contacted support about damage during shipping", "metadata": { "support_ticket_id": "ticket_789", "quality_issue_logged": true } } ``` # List Refunds Source: https://docs.stateset.com/api-reference/refunds/list GET https://api.stateset.com/v1/refunds List all refunds with filtering and pagination options This endpoint returns a paginated list of refunds. You can filter by status, date range, customer, and more. ## Authentication This endpoint requires a valid API key with `refunds:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of refunds to return (1-100) Number of refunds to skip Filter by status: "pending", "approved", "processing", "completed", "rejected", "cancelled" Filter by type: "full", "partial", "item\_return", "shipping", "tax\_only" Filter by specific order Filter by customer Filter refunds created after date (ISO 8601) Filter refunds created before date (ISO 8601) Filter by refund reason code Sort by field: "created\_at", "updated\_at", "amount", "status" Sort order: "asc" or "desc" ### Response Returns a paginated list of refund objects. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/refunds?status=processing&limit=20' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const refunds = await stateset.refunds.list({ status: 'processing', limit: 20 }); ``` ```python Python theme={null} refunds = stateset.refunds.list( status='processing', limit=20 ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "refund_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "refund", "order_id": "order_123456", "customer_id": "cust_abc123", "type": "partial", "status": "processing", "reason": "product_damaged", "amounts": { "total": 5449, "currency": "USD" }, "created_at": "2024-06-20T13:30:00Z", "estimated_completion": "2024-06-23T13:30:00Z" }, { "id": "refund_1234f083-bb2d-54d6-bg6d-1b0e3gd75f41", "object": "refund", "order_id": "order_234567", "customer_id": "cust_def456", "type": "full", "status": "processing", "reason": "order_cancelled", "amounts": { "total": 15999, "currency": "USD" }, "created_at": "2024-06-20T12:00:00Z", "estimated_completion": "2024-06-23T12:00:00Z" } ], "has_more": true, "total_count": 156, "url": "/v1/refunds", "summary": { "total_amount": 847532, "average_processing_time": 72, "status_breakdown": { "pending": 12, "approved": 8, "processing": 45, "completed": 87, "rejected": 3, "cancelled": 1 } } } ``` # Reporting Source: https://docs.stateset.com/api-reference/reporting Overview of the Stateset One Platform Reporting # Reporting ## Advanced Reporting Capabilities Stateset One offers a comprehensive set of advanced reporting capabilities to help users analyze and visualize their data effectively. Some of the key features include: ### Customizable Reports Users can create customized reports tailored to their specific needs. The platform provides a user-friendly interface to define report parameters, select relevant data sources, apply filters, and specify the desired output format. ### Data Visualization Stateset One includes & integrates a range of data visualization tools to transform raw data into meaningful visual representations. Users can create charts, graphs, dashboards, and other visual elements to gain insights into their data quickly. The platform supports various visualization types, such as bar charts, pie charts, line graphs, and heatmaps. ### Drill-Down Capabilities With drill-down capabilities, users can dig deeper into their data to uncover more granular details. By interacting with visualizations or reports, users can access underlying data layers, enabling a more comprehensive analysis of trends, patterns, and outliers. ### Filtering and Segmentation Stateset One allows users to apply filters and segment their data for focused analysis. Users can define criteria based on specific dimensions or variables, such as time periods, geographical locations, customer segments, or product categories. This feature enables users to examine data subsets and compare performance across different segments. ### Scheduled Exports Stateset One provides scheduled export functionality, allowing users to automate the generation and delivery of reports at specified intervals. Key features of this capability include: #### Flexible Export Formats Users can choose from a variety of export formats for their reports, such as PDF, Excel, CSV, or HTML. This flexibility ensures compatibility with different systems and caters to the diverse needs of stakeholders who may require specific file formats. ### Example Code for Exporting Data ```javascript theme={null} const returnFields = [ "id", "status", "order_id", "rma", "tracking_number", "description", "customerEmail", "zendesk_number", "action_needed", "reason_category", "issue", "order_date", "shipped_date", "requested_date", "serial_number", "scanned_serial_number", "condition", "amount", "customer_id", "tax_refunded", "total_refunded", "created_date", "flat_rate_shipping", "warehouse_received_date", "warehouse_condition_date", "country" ]; const opts = { returnFields }; // Current Time var time = Math.floor(Date.now() / 1000); // The ID of your GCS bucket const bucketName = 'returns'; // The path to your file to upload const filePath = `../stateset-app/static/data/returns/returns-data-${time}.csv`; // The new ID for your GCS file const destFileName = `returns-data-${time}.csv`; // Upload to Google Cloud Function async function uploadFile() { // Uploads a local file to the bucket await storage.bucket(bucketName).upload(filePath, { destination: destFileName, }); return res.status(200).json({ status: `${filename}-${time} uploaded to ${bucketName}.` }) } // Get the Return Data const return_records = await graphQLClient.request(GET_MY_RETURNS); // JSON 2 CSV Parser const json2csvParser = new Parser({ returnFields, quote: '', delimiter: ',' }); // Stateset CSV const statesetCSV = json2csvParser.parse(return_records.returns); // Parse the Response convert to CSV let statesetWriter = createWriteStream(`../stateset-app/static/data/returns/returns-data-${time}.csv`) statesetWriter.write(statesetCSV); // Upload File uploadFile().catch(console.error); ``` #### Example for Sending Email with Attachment ```Python theme={null} import base64 import io import os from google.cloud import storage from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import ( Mail, Attachment, FileContent, FileName, FileType, To, Disposition) sg = SendGridAPIClient(process.env.SENDGRID_API) def send_mail(data, context): message = Mail( from_email='', to_emails= [To('email@customer.com'), To('partner@customer.com'), To('manager@customer.com')], subject='Returns Report', html_content='This is the returns report autogenerated via Stateset.' ) storage_client = storage.Client(process.env.STORAGE_CLIENT) bucket = storage_client.get_bucket(process.env.STORAGE_BUCKET) blob = bucket.blob(data['name']) data = blob.download_as_bytes() bytes = io.BytesIO(data) bytes.seek(0) data = bytes.read() encoded = base64.b64encode(data) csv_file = str(encoded,'utf-8') attachment = Attachment() attachment.file_content = FileContent(csv_file) attachment.file_type = FileType('text/csv') attachment.file_name = FileName('returns-export.csv') attachment.disposition = Disposition('attachment') message.attachment = attachment response = sg.send(message) print(response.status_code, response.body, response.headers) ``` # Approve Return Source: https://docs.stateset.com/api-reference/return/approve POST https://api.stateset.com/v1/returns/:id/approve This endpoint approves a return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return/:id/approve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation returnApproveMutation { returnApprove(id: "${returnId}") { return { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} returns = stateset.returns.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} returns, err := stateset.Returns.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Return returns = stateset.Returns.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $returns = $stateset->returns->approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "return", "approved": true } ``` # Cancel Return Source: https://docs.stateset.com/api-reference/return/cancel POST https://api.stateset.com/v1/returns/:id/cancel This endpoint updates an existing return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return/:id/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation returnCancelMutation { returnCancel(id: "${returnId}") { return { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} returns = stateset.returns.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} returns, err := stateset.Returns.Cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Return returns = stateset.Returns.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $returns = $stateset->returns->cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "return", "cancelled": true } ``` # Close Return Source: https://docs.stateset.com/api-reference/return/close POST https://api.stateset.com/v1/returns/:id/close This endpoint closes an existing return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return/:id/close' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation returnCloseMutation { returnClose(id: "${returnId}") { return { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```python Python theme={null} returns = stateset.returns.close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} returns, err := stateset.Returns.Close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```java Java theme={null} Return returns = stateset.Returns.close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```php PHP theme={null} $returns = $stateset->returns->close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```cpp C++ theme={null} auto returns = stateset.returns.close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```rust Rust theme={null} let returns = stateset.returns.close({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "closed": true } ``` # Create Return Source: https://docs.stateset.com/api-reference/return/create POST https://api.stateset.com/v1/return Create a new return record with automatic RMA generation and workflow initiation This endpoint creates a new return and automatically triggers the returns management workflow, including label generation and customer notifications. ## Authentication This endpoint requires a valid API key with `returns:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body The unique identifier of the order being returned. Must be a valid existing order. Array of items being returned from the order. Product SKU being returned Number of units being returned Return reason. Options: `defective`, `not_as_described`, `wrong_item`, `damaged`, `other` Item condition. Options: `A` (like new), `B` (good), `C` (fair), `D` (poor) Email address of the customer. Used for sending return labels and notifications. Primary reason for the return. Options: `defective`, `not_satisfied`, `wrong_item`, `arrived_late`, `damaged_in_transit`, `other` Type of return. Options: `replacement`, `refund`, `store_credit` Additional notes or comments from the customer about the return. Customer's address for pickup (if different from order address). Street address line 1 Street address line 2 City name State/Province code (e.g., "CA", "NY") Postal/ZIP code ISO 3166-1 alpha-2 country code (e.g., "US", "CA") Associated support ticket ID for tracking. Additional custom metadata to store with the return. ### Response The ID provided in the data tab may be used to identify the return The order ID provided in the data tab may be used to identify the order The serial number provided in the data tab may be used to identify the serial number The description provided in the data tab may be used to identify the description The status provided in the data tab may be used to identify the status The reported condition provided in the data tab may be used to identify the reported condition The tracking number provided in the data tab may be used to identify the tracking number The zendesk number provided in the data tab may be used to identify the zendesk number The action needed provided in the data tab may be used to identify the action needed The rma provided in the data tab may be used to identify the rma The country provided in the data tab may be used to identify the country ```bash Basic Return theme={null} curl -X POST https://api.stateset.com/v1/return \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "order_id": "ORD-789456", "customer_email": "customer@example.com", "reason_code": "defective", "type": "replacement", "items": [ { "sku": "SHOE-RED-10", "quantity": 1, "reason": "defective", "condition": "B" } ], "customer_notes": "Sole is separating from the shoe" }' ``` ```bash Complete Return with Address theme={null} curl -X POST https://api.stateset.com/v1/return \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: unique-return-key-123" \ -d '{ "order_id": "ORD-789456", "customer_email": "customer@example.com", "reason_code": "wrong_item", "type": "refund", "items": [ { "sku": "SHIRT-BLUE-L", "quantity": 2, "reason": "wrong_item", "condition": "A" }, { "sku": "PANTS-BLACK-32", "quantity": 1, "reason": "not_as_described", "condition": "A" } ], "shipping_address": { "street1": "123 Main Street", "street2": "Apt 4B", "city": "New York", "state": "NY", "zip": "10001", "country": "US" }, "zendesk_ticket_id": "TICKET-98765", "metadata": { "source": "web_portal", "priority": "high" } }' ``` ```graphQL GraphQL theme={null} mutation InsertNewReturn( $return_x: returns_insert_input! ) { insert_returns ( objects: [$return_x] ) { returning { id order_id serial_number description status reported_condition tracking_number zendesk_number action_needed rma country } } }`; ``` ```js Node.js theme={null} const returns = await stateset.returns.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' }); ``` ```python Python theme={null} returns = stateset.returns.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' }) ``` ```ruby Ruby theme={null} returns = stateset.returns.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' }) ``` ```go Go theme={null} returns, err := stateset.Returns.Create( 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' ) ``` ```java Java theme={null} Returns returns = stateset.returns.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' }) ``` ```php PHP theme={null} $returns = $stateset->returns->create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' }) ``` ```csharp C# theme={null} var returns = stateset.Returns.Create( 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'order_id': 'O-12332312', 'serial_number': 'st123976879tm', 'description:' 'Return for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'R-123312', 'country': 'US' ); ``` ```json Success Response (201) theme={null} { "id": "RET-0901f083-aa1c-43c5-af5c", "rma": "RMA-2024-1014", "order_id": "ORD-789456", "customer_email": "customer@example.com", "status": "NEW", "type": "replacement", "reason_code": "defective", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "workflow_id": "wf-return-0901f083", "items": [ { "id": "RLI-123", "sku": "SHOE-RED-10", "quantity": 1, "reason": "defective", "condition": "B", "product_name": "Red Running Shoe Size 10", "refund_amount": 89.99 } ], "shipping": { "carrier": "fedex", "tracking_number": "7799832198765", "label_url": "https://api.stateset.com/labels/RET-0901f083.pdf", "label_created_at": "2024-01-15T10:30:15Z" }, "totals": { "subtotal": 89.99, "tax_refund": 7.20, "shipping_refund": 0.00, "total_refund": 97.19 }, "timeline": [ { "event": "return_created", "timestamp": "2024-01-15T10:30:00Z", "description": "Return request created" }, { "event": "label_generated", "timestamp": "2024-01-15T10:30:15Z", "description": "Shipping label generated and emailed" } ] } ``` ```json Error Response (400) theme={null} { "error": { "code": "INVALID_ORDER", "message": "Order ORD-789456 not found or not eligible for return", "details": { "order_status": "returned", "days_since_purchase": 45, "return_window": 30 } } } ``` ```json Error Response (422) theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "errors": [ { "field": "items[0].quantity", "message": "Quantity cannot exceed original order quantity", "original_quantity": 1, "requested_quantity": 2 }, { "field": "reason_code", "message": "Invalid reason code. Must be one of: defective, not_satisfied, wrong_item, arrived_late, damaged_in_transit, other" } ] } } ``` # Delete Return Source: https://docs.stateset.com/api-reference/return/delete DELETE https://api.return.com/v1/returns/:id This endpoint deletes an existing return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/return' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteReturn ($id: String!) { delete_returns(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const returns = await stateset.returns.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} returns = stateset.returns.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} returns, err := stateset.Returns.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Return returns = stateset.returns.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const returns = await stateset.returns.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} returns = Stateset::Return.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $returns = $stateset->returns->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/return HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "deleted": true } ``` # Exchange Return Source: https://docs.stateset.com/api-reference/return/exchange POST https://api.stateset.com/v1/returns/:id/exchange This endpoint processes an exchange for a returned item. ### Body The ID provided in the data tab may be used to identify the return The product ID of the item to exchange for The variant ID if exchanging for a different variant (size, color, etc.) The reason for the exchange The price difference between original and exchange items (positive if customer owes, negative if refund due) The shipping method for the exchange item Whether to expedite the exchange shipment ### Response The ID provided in the data tab may be used to identify the return The object type The new order ID for the exchange The status of the exchange (e.g., "pending", "processing", "shipped") The original product that was returned The new product being sent as exchange The price difference between items Status of any additional payment or refund Tracking number for the exchange shipment Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/returns/:id/exchange' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "exchange_product_id": "prod_abc789", "exchange_variant_id": "var_size_large", "exchange_reason": "Wrong size ordered", "price_difference": 0, "shipping_method": "standard", "expedited": false }' ``` ```graphQL GraphQL theme={null} mutation returnExchangeMutation { returnExchange( id: "${returnId}", exchangeProductId: "${exchangeProductId}", exchangeVariantId: "${exchangeVariantId}", exchangeReason: "${exchangeReason}", priceDifference: ${priceDifference}, shippingMethod: "${shippingMethod}", expedited: ${expedited} ) { return { id, status, exchange_order_id, exchange_status, tracking_number } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.exchange({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', exchange_product_id: 'prod_abc789', exchange_variant_id: 'var_size_large', exchange_reason: 'Wrong size ordered', price_difference: 0, shipping_method: 'standard', expedited: false }); ``` ```python Python theme={null} returns = stateset.returns.exchange({ 'id': 'rt_1NXWPnCo6bFb1KQto6C8OWvE', 'exchange_product_id': 'prod_abc789', 'exchange_variant_id': 'var_size_large', 'exchange_reason': 'Wrong size ordered', 'price_difference': 0, 'shipping_method': 'standard', 'expedited': False }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.exchange({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', exchange_product_id: 'prod_abc789', exchange_variant_id: 'var_size_large', exchange_reason: 'Wrong size ordered', price_difference: 0, shipping_method: 'standard', expedited: false }) ``` ```go Go theme={null} returns, err := stateset.Returns.exchange({ ID: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', ExchangeProductID: 'prod_abc789', ExchangeVariantID: 'var_size_large', ExchangeReason: 'Wrong size ordered', PriceDifference: 0, ShippingMethod: 'standard', Expedited: false }) ``` ```java Java theme={null} Return returns = stateset.Returns.exchange({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', exchangeProductId: 'prod_abc789', exchangeVariantId: 'var_size_large', exchangeReason: 'Wrong size ordered', priceDifference: 0, shippingMethod: 'standard', expedited: false }); ``` ```php PHP theme={null} $returns = $stateset->returns->exchange([ 'id' => 'rt_1NXWPnCo6bFb1KQto6C8OWvE', 'exchange_product_id' => 'prod_abc789', 'exchange_variant_id' => 'var_size_large', 'exchange_reason' => 'Wrong size ordered', 'price_difference' => 0, 'shipping_method' => 'standard', 'expedited' => false ]); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Exchange(new { Id = 'rt_1NXWPnCo6bFb1KQto6C8OWvE', ExchangeProductId = 'prod_abc789', ExchangeVariantId = 'var_size_large', ExchangeReason = 'Wrong size ordered', PriceDifference = 0, ShippingMethod = 'standard', Expedited = false }); ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "exchanged": true, "exchange_order_id": "ord_exch_789xyz", "exchange_status": "processing", "original_product_id": "prod_xyz123", "exchange_product_id": "prod_abc789", "exchange_variant_id": "var_size_large", "price_difference": 0, "payment_status": "no_payment_required", "tracking_number": "1Z999AA10123456785", "estimated_delivery": "2024-01-18" } ``` # Retrieve Return Source: https://docs.stateset.com/api-reference/return/get GET https://api.stateset.com/v1/return/:id/retrieve This endpoint retrieves a return. ### Body This is the id of the return. ### Response This is the id of the return. This is the date the return was created. This is the amount of the return. This is the action needed for the return. This is the condition of the return. This is the email of the customer. This is the id of the customer. This is the description of the return. This is the id of the user who entered the return. This is the flat rate shipping of the return. This is the date of the order. This is the id of the order. This is the reason category of the return. This is the reported condition of the return. This is the requested date of the return. This is the rma of the return. This is the serial number of the return. This is the shipped date of the return. This is the status of the return. This is the tax refunded of the return. This is the total refunded of the return. This is the tracking number of the return. This is the line items of the return. This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/return/retrieve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { returns(limit: $limit, offset: $offset, order_by: {created_date: $order_direction}) { id created_date amount action_needed condition customerEmail customer_id description enteredBy flat_rate_shipping order_date order_id reason_category reported_condition requested_date rma serial_number shipped_date status tax_refunded total_refunded tracking_number return_line_items { amount condition flat_rate_shipping id name price return_id serial_number sku tax_refunded } } } ``` ```js Node.js theme={null} const returns = await stateset.returns.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} returns = stateset.returns.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} returns, err := stateset.Returns.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} returns = Stateset::Returns.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Returns returns = Stateset.Returns.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Returns returns = Stateset.Returns.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $returns = Stateset\Returns::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/return HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "returns": [ { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": null, "action_needed": null, "condition": null, "customerEmail": "customer@gmail.com", "customer_id": null, "description": null, "enteredBy": null, "flat_rate_shipping": null, "order_date": null, "order_id": "524213310335630636", "reason_category": null, "reported_condition": null, "requested_date": null, "rma": "#1014-R5", "serial_number": null, "shipped_date": null, "status": "RCV", "tax_refunded": null, "total_refunded": null, "tracking_number": null, "return_line_items": [] }, ] } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Return not found", "details": { "resource": "return", "id": "ret_abc123" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` # Inspect Return Source: https://docs.stateset.com/api-reference/return/inspect POST https://api.stateset.com/v1/returns/:id/inspect This endpoint records inspection details for a returned item. ### Body The ID provided in the data tab may be used to identify the return The type of inspection performed (e.g., "physical", "functional", "cosmetic") The assessed condition of the returned item (e.g., "like\_new", "good", "fair", "poor", "damaged") Detailed notes from the inspection List of defects or issues found during inspection Whether the item can be resold Recommended restocking fee based on condition ### Response The ID provided in the data tab may be used to identify the return The object type The unique identifier for the inspection record The date when the inspection was performed The final condition assessment Whether the item can be resold The recommended action based on inspection (e.g., "restock", "liquidate", "dispose") Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/returns/:id/inspect' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "inspection_type": "physical", "condition_assessment": "good", "inspector_notes": "Minor wear on packaging, product unused", "defects_found": ["packaging_damage"], "resellable": true, "restocking_fee": 15.00 }' ``` ```graphQL GraphQL theme={null} mutation returnInspectMutation { returnInspect( id: "${returnId}", inspectionType: "${inspectionType}", conditionAssessment: "${conditionAssessment}", inspectorNotes: "${inspectorNotes}", defectsFound: ${defectsFound}, resellable: ${resellable}, restockingFee: ${restockingFee} ) { return { id, status, inspection_id, condition_assessment, resellable, recommended_action } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.inspect({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', inspection_type: 'physical', condition_assessment: 'good', inspector_notes: 'Minor wear on packaging, product unused', defects_found: ['packaging_damage'], resellable: true, restocking_fee: 15.00 }); ``` ```python Python theme={null} returns = stateset.returns.inspect({ 'id': 'rt_1NXWPnCo6bFb1KQto6C8OWvE', 'inspection_type': 'physical', 'condition_assessment': 'good', 'inspector_notes': 'Minor wear on packaging, product unused', 'defects_found': ['packaging_damage'], 'resellable': True, 'restocking_fee': 15.00 }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.inspect({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', inspection_type: 'physical', condition_assessment: 'good', inspector_notes: 'Minor wear on packaging, product unused', defects_found: ['packaging_damage'], resellable: true, restocking_fee: 15.00 }) ``` ```go Go theme={null} returns, err := stateset.Returns.inspect({ ID: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', InspectionType: 'physical', ConditionAssessment: 'good', InspectorNotes: 'Minor wear on packaging, product unused', DefectsFound: []string{'packaging_damage'}, Resellable: true, RestockingFee: 15.00 }) ``` ```java Java theme={null} Return returns = stateset.Returns.inspect({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', inspectionType: 'physical', conditionAssessment: 'good', inspectorNotes: 'Minor wear on packaging, product unused', defectsFound: ['packaging_damage'], resellable: true, restockingFee: 15.00 }); ``` ```php PHP theme={null} $returns = $stateset->returns->inspect([ 'id' => 'rt_1NXWPnCo6bFb1KQto6C8OWvE', 'inspection_type' => 'physical', 'condition_assessment' => 'good', 'inspector_notes' => 'Minor wear on packaging, product unused', 'defects_found' => ['packaging_damage'], 'resellable' => true, 'restocking_fee' => 15.00 ]); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Inspect(new { Id = 'rt_1NXWPnCo6bFb1KQto6C8OWvE', InspectionType = 'physical', ConditionAssessment = 'good', InspectorNotes = 'Minor wear on packaging, product unused', DefectsFound = new[] { 'packaging_damage' }, Resellable = true, RestockingFee = 15.00 }); ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "inspected": true, "inspection_id": "insp_ret_123", "inspection_date": "2024-01-15T10:45:00Z", "condition_assessment": "good", "resellable": true, "restocking_fee": 15.00, "defects_found": ["packaging_damage"], "recommended_action": "restock" } ``` # List Returns Source: https://docs.stateset.com/api-reference/return/list GET https://api.stateset.com/api/returns This endpoint retrieves a paginated list of return requests based on specified filters and sorting options. ### Body This is the limit of the returns. This is the offset of the returns. This is the order direction of the returns. This is the status of the returns. ### Response This is the id of the return. This is the date the return was created. This is the amount of the return. This is the action needed for the return. This is the condition of the return. This is the email of the customer. This is the id of the customer. This is the description of the return. This is the id of the user who entered the return. This is the flat rate shipping of the return. This is the date of the order. This is the id of the order. This is the reason category of the return. This is the reported condition of the return. This is the requested date of the return. This is the rma of the return. This is the serial number of the return. This is the shipped date of the return. This is the status of the return. This is the tax refunded of the return. This is the total refunded of the return. This is the tracking number of the return. This is the line items of the return. This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.app/api/returns' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "desc", "status": "Requested" }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: OrderDirection!, $status: ReturnStatus!) { returns(limit: $limit, offset: $offset, order_by: {created_date: $order_direction}, where: {status: {_eq: $status }}) { id created_date amount action_needed condition customerEmail customer_id description enteredBy flat_rate_shipping order_date order_id reason_category reported_condition requested_date rma serial_number shipped_date status tax_refunded total_refunded tracking_number return_line_items { id amount condition flat_rate_shipping name price return_id serial_number sku tax_refunded } } } ``` ```js Node.js theme={null} const returns = await stateset.returns.list({ limit: 10, offset: 0, order_direction: 'desc', status: 'Requested' }); ``` ```py Python theme={null} returns = stateset.returns.list({ "limit": 10, "offset": 0, "order_direction": "desc", "status": "Requested" }) ``` ```go Golang theme={null} returns, err := stateset.Returns.List( 10, // limit 0, // offset "desc", // order_direction "Requested", // status ) if err != nil { // Handle error } ``` ```ruby Ruby theme={null} returns = Stateset::Returns.list( limit: 10, offset: 0, order_direction: 'desc', status: 'Requested' ) ``` ```java Java theme={null} Returns returns = Stateset.Returns.list( 10, // limit 0, // offset "desc", // order_direction "Requested" // status ); ``` ```csharp C# theme={null} Returns returns = Stateset.Returns.List( limit: 10, offset: 0, order_direction: "desc", status: "Requested" ); ``` ```php PHP theme={null} $returns = Stateset\Returns::list([ 'limit' => 10, 'offset' => 0, 'order_direction' => 'desc', 'status' => 'Requested' ]); ``` ```http HTTP theme={null} GET /api/returns HTTP/1.1 Host: stateset-proxy-server.stateset.cloud.stateset.app Content-Type: application/json Authorization: Bearer { "limit": 10, "offset": 0, "order_direction": "desc", "status": "Requested" } ``` ```json Response theme={null} { "returns": [ { "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": "150.00", "action_needed": "Inspection", "condition": "Damaged", "customerEmail": "customer@example.com", "customer_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "description": "The product arrived damaged.", "enteredBy": "1c0a3e4b-7e2d-4b1a-8d6c-3f2e4a5b6c7d", "flat_rate_shipping": "10.00", "order_date": "2023-06-20T15:30:00+00:00", "order_id": "2b8e4f64-1234-5678-9abc-def012345678", "reason_category": "Product Damage", "reported_condition": "Damaged", "requested_date": "2023-06-28T19:30:00+00:00", "rma": "RMA123456", "serial_number": "SN789456123", "shipped_date": "2023-06-29T10:00:00+00:00", "status": "Approved", "tax_refunded": "5.00", "total_refunded": "165.00", "tracking_number": "TRK1234567890", "return_line_items": [ { "id": "a3f5c10b-58cc-4372-a567-0e02b2c3d480", "amount": "75.00", "condition": "Damaged", "flat_rate_shipping": "5.00", "name": "Widget Pro", "price": "75.00", "return_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "serial_number": "SN789456123", "sku": "SKU12345", "tax_refunded": "2.50" } ] } ] } ``` # Refund Return Source: https://docs.stateset.com/api-reference/return/refund POST https://api.stateset.com/v1/return/:id/refund This endpoint refunds an existing return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return/:id/refund' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation returnRefundMutation( $returnLineItems: [ReturnRefundLineItemInput!]!, $refundShipping: RefundShippingInput, $orderTransactions: [ReturnRefundOrderTransactionInput!] ) { returnRefund( returnRefundInput: { returnId: "${returnId}", returnRefundLineItems: $returnLineItems, refundShipping: $refundShipping, orderTransactions: $orderTransactions } ) { refund { id } userErrors { field message } } } ``` ```js Node.js theme={null} const returns = await stateset.returns.refund({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```python Python theme={null} returns = stateset.returns.refund({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.refund({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} returns, err := stateset.Returns.Refund( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Return returns = stateset.returns.refund( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $returns = $stateset->returns->refund( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} var returns = stateset.Returns.Refund( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```vb Visual Basic .NET theme={null} Dim returns = stateset.Returns.Refund( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "refunded": true } ``` # Reject Return Source: https://docs.stateset.com/api-reference/return/reject POST https://api.stateset.com/v1/returns/:id/reject This endpoint rejects a return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return/:id/reject' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation returnRejectMutation { returnreject(id: "${returnId}") { return { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} returns = stateset.returns.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} returns, err := stateset.Returns.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Return returns = stateset.Returns.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $returns = $stateset->returns->reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var returns = await stateset.Returns.reject({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "return", "rejected": true } ``` # ReOpen Return Source: https://docs.stateset.com/api-reference/return/reopen POST https://api.stateset.com/v1/return/:id/reopen This endpoint updates an existing return. ### Body The ID provided in the data tab may be used to identify the return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return/:id/reopen' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation returnReopenMutation { returnReopen(id: "${returnId}") { return { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```python Python theme={null} returns = stateset.returns.reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} returns, err := stateset.Returns.Reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```java Java theme={null} Return returns = stateset.Returns.reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```php PHP theme={null} $returns = $stateset->returns->reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Reopen({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "reopened": true } ``` # Restock Return Source: https://docs.stateset.com/api-reference/return/restock POST https://api.stateset.com/v1/returns/:id/restock This endpoint restocks a returned item back into inventory. ### Body The ID provided in the data tab may be used to identify the return The warehouse ID where the item will be restocked The specific location within the warehouse The condition code for inventory classification (e.g., "new", "refurbished", "open\_box") The quantity to restock Whether a restocking fee was applied to this return ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the item was successfully restocked The ID of the inventory adjustment record The new inventory level after restocking The warehouse where the item was restocked The timestamp when the item was restocked Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/returns/:id/restock' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "warehouse_id": "wh_east_01", "location_id": "loc_a1_shelf_3", "condition_code": "new", "quantity": 1, "restocking_fee_applied": true }' ``` ```graphQL GraphQL theme={null} mutation returnRestockMutation { returnRestock( id: "${returnId}", warehouseId: "${warehouseId}", locationId: "${locationId}", conditionCode: "${conditionCode}", quantity: ${quantity}, restockingFeeApplied: ${restockingFeeApplied} ) { return { id, status, inventory_adjustment_id, new_inventory_level, restocked_at } userErrors { field message } } } `; ``` ```js Node.js theme={null} const returns = await stateset.returns.restock({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', warehouse_id: 'wh_east_01', location_id: 'loc_a1_shelf_3', condition_code: 'new', quantity: 1, restocking_fee_applied: true }); ``` ```python Python theme={null} returns = stateset.returns.restock({ 'id': 'rt_1NXWPnCo6bFb1KQto6C8OWvE', 'warehouse_id': 'wh_east_01', 'location_id': 'loc_a1_shelf_3', 'condition_code': 'new', 'quantity': 1, 'restocking_fee_applied': True }) ``` ```ruby Ruby theme={null} returns = Stateset::Return.restock({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', warehouse_id: 'wh_east_01', location_id: 'loc_a1_shelf_3', condition_code: 'new', quantity: 1, restocking_fee_applied: true }) ``` ```go Go theme={null} returns, err := stateset.Returns.restock({ ID: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', WarehouseID: 'wh_east_01', LocationID: 'loc_a1_shelf_3', ConditionCode: 'new', Quantity: 1, RestockingFeeApplied: true }) ``` ```java Java theme={null} Return returns = stateset.Returns.restock({ id: 'rt_1NXWPnCo6bFb1KQto6C8OWvE', warehouseId: 'wh_east_01', locationId: 'loc_a1_shelf_3', conditionCode: 'new', quantity: 1, restockingFeeApplied: true }); ``` ```php PHP theme={null} $returns = $stateset->returns->restock([ 'id' => 'rt_1NXWPnCo6bFb1KQto6C8OWvE', 'warehouse_id' => 'wh_east_01', 'location_id' => 'loc_a1_shelf_3', 'condition_code' => 'new', 'quantity' => 1, 'restocking_fee_applied' => true ]); ``` ```csharp C# theme={null} var returns = await stateset.Returns.Restock(new { Id = 'rt_1NXWPnCo6bFb1KQto6C8OWvE', WarehouseId = 'wh_east_01', LocationId = 'loc_a1_shelf_3', ConditionCode = 'new', Quantity = 1, RestockingFeeApplied = true }); ``` ```json Response theme={null} { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return", "restocked": true, "inventory_adjustment_id": "inv_adj_456", "new_inventory_level": 150, "warehouse_id": "wh_east_01", "location_id": "loc_a1_shelf_3", "condition_code": "new", "restocked_at": "2024-01-15T11:00:00Z" } ``` # Update Return Source: https://docs.stateset.com/api-reference/return/update PUT https://api.stateset.com/v1/returns/ This endpoint updates an existing return. ### Body The ID provided in the data tab may be used to identify the return The return object ### Response The ID of the return The ID of the order The description of the return The issue of the return The status of the return The tracking number of the return The action needed of the return The customer email of the return The RMA of the return The serial number of the return The scanned serial number of the return The zendesk number of the return The entered by of the return The order date of the return The shipped date of the return The requested date of the return The condition of the return The reported condition of the return The created date of the return The amount of the return The flat rate shipping of the return ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'status': 'RCV' 'condition': 'B' }' ``` ```graphQL GraphQL theme={null} mutation ( $return_id: String $return_x: returns_set_input! ) { update_returns ( where: { id : { _eq: $return_id }} _set: $return_x ) { returning { id order_id description issue status tracking_number action_needed customerEmail rma serial_number scanned_serial_number zendesk_number enteredBy order_date shipped_date requested_date condition reported_condition created_date amount flat_rate_shipping } } }`; ``` ```js Node.js theme={null} const returns = await stateset.returns.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} returns = stateset.Return.modify( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```ruby Ruby theme={null} returns = Stateset::Return.update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```go Go theme={null} returns, err := stateset.Returns.Update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```java Java theme={null} Return[] returns = stateset.returns.update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```php PHP theme={null} $returns = $stateset->returns->update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```json Response theme={null} { "returns": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": null, "action_needed": null, "condition": null, "customerEmail": "customer@gmail.com", "customer_id": null, "description": null, "enteredBy": null, "flat_rate_shipping": null, "order_date": null, "order_id": "524213310335630636", "reason_category": null, "reported_condition": null, "requested_date": null, "rma": "#1014-R5", "serial_number": null, "shipped_date": null, "status": "RCV", "tax_refunded": null, "total_refunded": null, "tracking_number": null, }, ] } ``` # Create Return Line Item Source: https://docs.stateset.com/api-reference/returnlineitem/create POST https://api.stateset.com/v1/return_line_items/create This endpoint creates a new return line item. ### Body This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ### Response This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/return_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```graphQL GraphQL theme={null} mutation addReturnLineItem($return_line_item: return_line_items_insert_input!) { insert_return_line_items(objects: [$return_line_item]) { returning { id sku name price condition serial_number amount return_id } } } ``` ```js Node.js theme={null} const returnLineItem = await stateset.returnItem.create({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} return_line_item = stateset.return_line_item.create( { "return_line_item": { "sku": "123456789", "name": "Example Item", "price": 100, "condition": "New", "serial_number": "123456789", "amount": 1, "return_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" } } ) ``` ```ruby Ruby theme={null} return_line_item = Stateset::ReturnItem.create( { "return_line_item": { "sku": "123456789", "name": "Example Item", "price": 100, "condition": "New", "serial_number": "123456789", "amount": 1, "return_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" } } ) ``` ```php PHP theme={null} $return_line_item = $stateset->return_line_item->create( [ "return_line_item" => [ "sku" => "123456789", "name" => "Example Item", "price" => 100, "condition" => "New", "serial_number" => "123456789", "amount" => 1, "return_id" => "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ] ] ); ``` ```go Golang theme={null} ReturnLineItem , err := stateset.ReturnLineItem.Create( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "123456789", "Example Item", 100, "New", "123456789", 1, "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ) ``` ```java Java theme={null} ReturnLineItem returnLineItem = stateset.returnLineItem.create( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "123456789", "Example Item", 100, "New", "123456789", 1, "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ); ``` ```csharp C# theme={null} var returnLineItem = stateset.ReturnLineItem.Create( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "123456789", "Example Item", 100, "New", "123456789", 1, "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ); ``` ```json Response theme={null} { "data": { "insert_return_line_items": { "returning": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "123456789", "name": "Example Item", "price": 100, "condition": "New", "serial_number": "123456789", "amount": 1, "return_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" } ] } } } ``` # Delete Return Line Item Source: https://docs.stateset.com/api-reference/returnlineitem/delete DELETE https://api.return.com/v1/return_line_items/:id This endpoint deletes an existing return line item. ### Body The ID of the return line item you want to delete ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.return.com/v1/return_line_items/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```js Node.js theme={null} const returnLineItem = await stateset.returnItem.del({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```graphQL GraphQL theme={null} mutation deleteReturnLineItem ($return_line_item_id: uuid!) { delete_return_line_items(where: {id: {_eq: $return_line_item_id}}) { affected_rows } } ``` ```python Python theme={null} return_line_item = stateset.return_line_item.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```ruby Ruby theme={null} return_line_item = Stateset::ReturnLineItem.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```php PHP theme={null} $return_line_item = Stateset\ReturnItem::del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```go Golang theme={null} returnLineItem, err := stateset.ReturnLineItem.Delete( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```java Java theme={null} ReturnLineItem returnLineItem = stateset.returnLineItem.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```csharp C# theme={null} var returnLineItem = await Stateset.ReturnLineItem.Delete( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```json Response theme={null} { "id": "rli_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return_line_item", "deleted": true } ``` # Get Return Line Item Source: https://docs.stateset.com/api-reference/returnlineitem/get GET https://api.stateset.com/v1/return_line_item This endpoint gets or creates a new return line item. ### Body This is the id of the return line item. ### Response This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/return_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", }' ``` ```javascript Node.js theme={null} var returnLineItem = await stateset.returnItem.retreive({ id: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", }); ``` ```python Python theme={null} return_line_item = stateset.return_line_item.retrieve( id="0901f083-aa1c-43c5-af5c-0a9d2fc64e30", ) ``` ```ruby Ruby theme={null} return_line_item = Stateset::ReturnLineItem.retrieve( id: "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", ) ``` ```php PHP theme={null} $return_line_item = Stateset\ReturnLineItem::retrieve( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ); ``` ```go Go theme={null} returnLineItem, err := stateset.ReturnLineItem.Retrieve( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", ) ``` ```java Java theme={null} ReturnLineItem returnLineItem = stateset.returnLineItem.retrieve( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ); ``` ```json Response theme={null} { "data": { "insert_return_line_items": { "returning": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "123456789", "name": "Example Item", "price": 100, "condition": "New", "serial_number": "123456789", "amount": 1, "return_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" } ] } } } ``` # Update Return Line Item Source: https://docs.stateset.com/api-reference/returnlineitem/update PUT https://api.stateset.com/v1/return_line_items/:id This endpoint updates an existing return line item. ### Body This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ### Response This is the id of the return line item. This is the amount of the return line item. This is the condition of the return line item. This is the flat rate shipping of the return line item. This is the name of the return line item. This is the price of the return line item. This is the id of the return associated with the line item. This is the serial number of the return line item. This is the sku of the return line item. This is the tax refunded of the return line item. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/return_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```js Node.js theme={null} const returnLineItem = await stateset.returnItem.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```graphQL GraphQL theme={null} mutation ( $id: uuid $return_line_item: return_line_items_set_input! ) { update_return_line_items ( where: { id : { _eq: $id }} _set: $return_line_item ) { returning { id sku name price tax_refunded condition amount flat_rate_shipping } } } ``` ```python Python theme={null} return_line_item = stateset.ReturnItem.modify( id='0901f083-aa1c-43c5-af5c-0a9d2fc64e30', return_line_item={ 'sku': 'example_1', 'name': 'Example 1', 'price': 100, 'tax_refunded': 0, 'condition': 'new', 'amount': 1, 'flat_rate_shipping': 0 } ) ``` ```ruby Ruby theme={null} return_line_item = Stateset::ReturnItem.update( id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', return_line_item: { sku: 'example_1', name: 'Example 1', price: 100, tax_refunded: 0, condition: 'new', amount: 1, flat_rate_shipping: 0 } ) ``` ```php PHP theme={null} $return_line_item = $stateset->return_line_item->update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', [ 'sku' => 'example_1', 'name' => 'Example 1', 'price' => 100, 'tax_refunded' => 0, 'condition' => 'new', 'amount' => 1, 'flat_rate_shipping' => 0 ] ); ``` ```go Golang theme={null} returnLineItem, err := stateset.ReturnLineItem.Update( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", stateset.ReturnLineItem{ Sku: "example_1", Name: "Example 1", Price: 100, TaxRefunded: 0, Condition: "new", Amount: 1, FlatRateShipping: 0 } ) ``` ```java Java theme={null} ReturnLineItem returnLineItem = stateset.returnLineItem.update( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", new ReturnLineItem( "example_1", "Example 1", 100, 0, "new", 1, 0 ) ); ``` ```csharp CSharp theme={null} var returnLineItem = await stateset.ReturnLineItem.Update( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", new ReturnLineItem() { Sku = "example_1", Name = "Example 1", Price = 100, TaxRefunded = 0, Condition = "new", Amount = 1, FlatRateShipping = 0 } ); ``` ```json Response theme={null} { "data": { "insert_return_line_items": { "returning": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "123456789", "name": "Example Item", "price": 100, "condition": "New", "serial_number": "123456789", "amount": 1, "return_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" } ] } } } ``` # SDKs & Libraries Source: https://docs.stateset.com/api-reference/sdks Official and community SDKs for integrating with StateSet StateSet provides official SDKs for popular languages to accelerate your integration development. ## Official SDKs Full-featured SDK with TypeScript support Pythonic interface with async support High-performance SDK for Go applications Idiomatic Ruby SDK with Rails integration Modern PHP SDK with PSR compliance .NET SDK with async/await support Enterprise-ready Java SDK Native iOS/macOS SDK ## Node.js / TypeScript ### Installation ```bash npm theme={null} npm install @stateset/stateset-node ``` ```bash yarn theme={null} yarn add @stateset/stateset-node ``` ```bash pnpm theme={null} pnpm add @stateset/stateset-node ``` ### Quick Start ```typescript theme={null} import { StateSet } from '@stateset/stateset-node'; // Initialize client const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY, // Optional configuration environment: 'production', // or 'sandbox' timeout: 30000, // 30 seconds maxRetries: 3, apiVersion: '2024-01-01' }); // TypeScript types are included const order: StateSet.Order = await stateset.orders.create({ customer: { email: 'customer@example.com', first_name: 'John', last_name: 'Doe' }, items: [{ sku: 'WIDGET-001', quantity: 2, price: 2999 }], shipping_address: { line1: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' } }); ``` ### Advanced Features #### Async Iteration ```typescript theme={null} // Iterate through all orders for await (const order of stateset.orders.list()) { console.log(order.id); } // With filters for await (const order of stateset.orders.list({ status: 'pending' })) { await processOrder(order); } ``` #### Request Interceptors ```typescript theme={null} // Add request interceptor stateset.interceptors.request.use((config) => { config.headers['X-Custom-Header'] = 'value'; console.log(`Making request to ${config.url}`); return config; }); // Add response interceptor stateset.interceptors.response.use( (response) => { console.log(`Request completed in ${response.duration}ms`); return response; }, (error) => { console.error('Request failed:', error); throw error; } ); ``` #### Event Emitters ```typescript theme={null} // Listen for events stateset.on('request', (event) => { console.log('Request:', event); }); stateset.on('response', (event) => { console.log('Response:', event); }); stateset.on('error', (error) => { console.error('Error:', error); }); stateset.on('rateLimit', (info) => { console.warn('Rate limited:', info); }); ``` #### Custom HTTP Client ```typescript theme={null} import axios from 'axios'; const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY, httpClient: axios.create({ timeout: 60000, proxy: { host: 'proxy.example.com', port: 8080 } }) }); ``` ### TypeScript Support ```typescript theme={null} import { StateSet } from '@stateset/stateset-node'; import type { Order, Customer, Return, OrderCreateParams, PaginatedResponse } from '@stateset/stateset-node'; // Full type safety async function createOrder( params: OrderCreateParams ): Promise { return await stateset.orders.create(params); } // Generic pagination async function getAllOrders(): Promise { const response: PaginatedResponse = await stateset.orders.list(); return response.data; } // Type guards function isOrder(obj: any): obj is Order { return obj && obj.object === 'order'; } ``` ## Python ### Installation ```bash theme={null} pip install stateset-python ``` ### Quick Start ```python theme={null} from stateset import StateSet import os # Initialize client stateset = StateSet( api_key=os.getenv('STATESET_API_KEY'), # Optional configuration environment='production', # or 'sandbox' timeout=30, # seconds max_retries=3, api_version='2024-01-01' ) # Create an order order = stateset.orders.create( customer={ 'email': 'customer@example.com', 'first_name': 'John', 'last_name': 'Doe' }, items=[{ 'sku': 'WIDGET-001', 'quantity': 2, 'price': 2999 }], shipping_address={ 'line1': '123 Main St', 'city': 'San Francisco', 'state': 'CA', 'postal_code': '94105', 'country': 'US' } ) ``` ### Async Support ```python theme={null} import asyncio from stateset import AsyncStateSet async def main(): # Async client async with AsyncStateSet(api_key=api_key) as stateset: # Concurrent requests orders = await asyncio.gather( stateset.orders.get('ord_123'), stateset.orders.get('ord_456'), stateset.orders.get('ord_789') ) # Async iteration async for order in stateset.orders.list_async(): print(order.id) asyncio.run(main()) ``` ### Context Managers ```python theme={null} from stateset import StateSet # Automatic resource cleanup with StateSet(api_key=api_key) as stateset: orders = stateset.orders.list() for order in orders: print(order.id) ``` ### Type Hints ```python theme={null} from typing import List, Optional from stateset import StateSet from stateset.types import Order, Customer, OrderCreateParams def create_order( stateset: StateSet, params: OrderCreateParams ) -> Order: """Create a new order with type safety.""" return stateset.orders.create(**params) def get_customer_orders( stateset: StateSet, customer_id: str, status: Optional[str] = None ) -> List[Order]: """Get all orders for a customer.""" filters = {'customer_id': customer_id} if status: filters['status'] = status return list(stateset.orders.list(**filters)) ``` ## Go ### Installation ```bash theme={null} go get github.com/stateset/stateset-go ``` ### Quick Start ```go theme={null} package main import ( "context" "fmt" "os" "github.com/stateset/stateset-go" "github.com/stateset/stateset-go/order" ) func main() { // Initialize client client := stateset.NewClient( os.Getenv("STATESET_API_KEY"), &stateset.Config{ Environment: stateset.Production, Timeout: 30 * time.Second, MaxRetries: 3, }, ) // Create an order params := &order.CreateParams{ Customer: &order.CustomerParams{ Email: stateset.String("customer@example.com"), FirstName: stateset.String("John"), LastName: stateset.String("Doe"), }, Items: []*order.ItemParams{{ SKU: stateset.String("WIDGET-001"), Quantity: stateset.Int64(2), Price: stateset.Int64(2999), }}, ShippingAddress: &order.AddressParams{ Line1: stateset.String("123 Main St"), City: stateset.String("San Francisco"), State: stateset.String("CA"), PostalCode: stateset.String("94105"), Country: stateset.String("US"), }, } order, err := client.Orders.Create(context.Background(), params) if err != nil { panic(err) } fmt.Printf("Order created: %s\n", order.ID) } ``` ### Error Handling ```go theme={null} import ( "errors" "github.com/stateset/stateset-go" ) func handleOrder(client *stateset.Client, orderID string) error { order, err := client.Orders.Get(context.Background(), orderID) if err != nil { var statesetErr *stateset.Error if errors.As(err, &statesetErr) { switch statesetErr.Code { case stateset.ErrorCodeRateLimit: // Handle rate limiting time.Sleep(time.Duration(statesetErr.RetryAfter) * time.Second) return handleOrder(client, orderID) // Retry case stateset.ErrorCodeNotFound: // Handle not found return fmt.Errorf("order %s not found", orderID) default: return fmt.Errorf("API error: %v", statesetErr) } } return err } // Process order return nil } ``` ### Concurrent Operations ```go theme={null} func fetchOrdersConcurrently(client *stateset.Client, orderIDs []string) ([]*order.Order, error) { var wg sync.WaitGroup orders := make([]*order.Order, len(orderIDs)) errors := make([]error, len(orderIDs)) for i, id := range orderIDs { wg.Add(1) go func(index int, orderID string) { defer wg.Done() ord, err := client.Orders.Get(context.Background(), orderID) orders[index] = ord errors[index] = err }(i, id) } wg.Wait() // Check for errors for _, err := range errors { if err != nil { return nil, err } } return orders, nil } ``` ## Ruby ### Installation ```ruby theme={null} # Gemfile gem 'stateset-ruby' ``` ```bash theme={null} bundle install # or gem install stateset-ruby ``` ### Quick Start ```ruby theme={null} require 'stateset' # Initialize client Stateset.api_key = ENV['STATESET_API_KEY'] # Or configure globally Stateset.configure do |config| config.api_key = ENV['STATESET_API_KEY'] config.environment = :production # or :sandbox config.timeout = 30 config.max_retries = 3 end # Create an order order = Stateset::Order.create( customer: { email: 'customer@example.com', first_name: 'John', last_name: 'Doe' }, items: [{ sku: 'WIDGET-001', quantity: 2, price: 2999 }], shipping_address: { line1: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' } ) puts "Order created: #{order.id}" ``` ### Rails Integration ```ruby theme={null} # config/initializers/stateset.rb Stateset.configure do |config| config.api_key = Rails.application.credentials.stateset[:api_key] config.environment = Rails.env.production? ? :production : :sandbox config.logger = Rails.logger end # app/models/concerns/stateset_syncable.rb module StatesetSyncable extend ActiveSupport::Concern included do after_create :sync_to_stateset after_update :update_in_stateset end def sync_to_stateset StatesetSyncJob.perform_later(self) end def update_in_stateset StatesetUpdateJob.perform_later(self) end end # app/models/order.rb class Order < ApplicationRecord include StatesetSyncable def to_stateset_params { external_id: id, customer: { email: customer.email, first_name: customer.first_name, last_name: customer.last_name }, items: items.map(&:to_stateset_params) } end end ``` ### Error Handling ```ruby theme={null} begin order = Stateset::Order.create(params) rescue Stateset::RateLimitError => e # Handle rate limiting sleep(e.retry_after) retry rescue Stateset::ValidationError => e # Handle validation errors e.errors.each do |error| puts "#{error.field}: #{error.message}" end rescue Stateset::APIError => e # Handle other API errors puts "API Error: #{e.message}" end ``` ## PHP ### Installation ```bash theme={null} composer require stateset/stateset-php ``` ### Quick Start ```php theme={null} $_ENV['STATESET_API_KEY'], 'environment' => 'production', // or 'sandbox' 'timeout' => 30, 'maxRetries' => 3 ]); // Create an order try { $order = $stateset->orders->create([ 'customer' => [ 'email' => 'customer@example.com', 'first_name' => 'John', 'last_name' => 'Doe' ], 'items' => [[ 'sku' => 'WIDGET-001', 'quantity' => 2, 'price' => 2999 ]], 'shipping_address' => [ 'line1' => '123 Main St', 'city' => 'San Francisco', 'state' => 'CA', 'postal_code' => '94105', 'country' => 'US' ] ]); echo "Order created: {$order->id}\n"; } catch (ApiException $e) { echo "Error: {$e->getMessage()}\n"; } ``` ### Laravel Integration ```php theme={null} // config/stateset.php return [ 'api_key' => env('STATESET_API_KEY'), 'environment' => env('STATESET_ENVIRONMENT', 'production'), 'timeout' => 30, 'max_retries' => 3, ]; // app/Providers/StatesetServiceProvider.php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Stateset\StatesetClient; class StatesetServiceProvider extends ServiceProvider { public function register() { $this->app->singleton(StatesetClient::class, function ($app) { return new StatesetClient(config('stateset')); }); } } // app/Services/OrderService.php namespace App\Services; use Stateset\StatesetClient; class OrderService { protected $stateset; public function __construct(StatesetClient $stateset) { $this->stateset = $stateset; } public function createOrder(array $data) { return $this->stateset->orders->create($data); } } ``` ## .NET / C\# ### Installation ```bash theme={null} dotnet add package StateSet.Net ``` ### Quick Start ```csharp theme={null} using StateSet; using StateSet.Models; using System; using System.Threading.Tasks; class Program { static async Task Main(string[] args) { // Initialize client var client = new StateSetClient( Environment.GetEnvironmentVariable("STATESET_API_KEY"), new StateSetOptions { Environment = StateSetEnvironment.Production, Timeout = TimeSpan.FromSeconds(30), MaxRetries = 3 } ); // Create an order var order = await client.Orders.CreateAsync(new OrderCreateParams { Customer = new CustomerParams { Email = "customer@example.com", FirstName = "John", LastName = "Doe" }, Items = new List { new OrderItemParams { Sku = "WIDGET-001", Quantity = 2, Price = 2999 } }, ShippingAddress = new AddressParams { Line1 = "123 Main St", City = "San Francisco", State = "CA", PostalCode = "94105", Country = "US" } }); Console.WriteLine($"Order created: {order.Id}"); } } ``` ### Dependency Injection (ASP.NET Core) ```csharp theme={null} // Startup.cs or Program.cs public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddStateSet(options => { options.ApiKey = Configuration["StateSet:ApiKey"]; options.Environment = StateSetEnvironment.Production; }); services.AddScoped(); } } // Services/OrderService.cs public interface IOrderService { Task CreateOrderAsync(OrderDto orderDto); } public class OrderService : IOrderService { private readonly IStateSetClient _stateset; public OrderService(IStateSetClient stateset) { _stateset = stateset; } public async Task CreateOrderAsync(OrderDto orderDto) { return await _stateset.Orders.CreateAsync(orderDto.ToStateSetParams()); } } ``` ## Java ### Installation #### Maven ```xml theme={null} com.stateset stateset-java 3.0.0 ``` #### Gradle ```gradle theme={null} implementation 'com.stateset:stateset-java:3.0.0' ``` ### Quick Start ```java theme={null} import com.stateset.StateSet; import com.stateset.model.Order; import com.stateset.param.OrderCreateParams; import com.stateset.exception.StateSetException; public class Main { public static void main(String[] args) { // Initialize client StateSet.apiKey = System.getenv("STATESET_API_KEY"); // Or use builder StateSet stateset = StateSet.builder() .setApiKey(System.getenv("STATESET_API_KEY")) .setEnvironment(StateSet.Environment.PRODUCTION) .setTimeout(30000) .setMaxRetries(3) .build(); try { // Create an order OrderCreateParams params = OrderCreateParams.builder() .setCustomer( OrderCreateParams.Customer.builder() .setEmail("customer@example.com") .setFirstName("John") .setLastName("Doe") .build() ) .addItem( OrderCreateParams.Item.builder() .setSku("WIDGET-001") .setQuantity(2) .setPrice(2999L) .build() ) .setShippingAddress( OrderCreateParams.Address.builder() .setLine1("123 Main St") .setCity("San Francisco") .setState("CA") .setPostalCode("94105") .setCountry("US") .build() ) .build(); Order order = Order.create(params); System.out.println("Order created: " + order.getId()); } catch (StateSetException e) { System.err.println("Error: " + e.getMessage()); } } } ``` ### Spring Boot Integration ```java theme={null} // Configuration @Configuration public class StateSetConfig { @Value("${stateset.api-key}") private String apiKey; @Bean public StateSet statesetClient() { return StateSet.builder() .setApiKey(apiKey) .setEnvironment(StateSet.Environment.PRODUCTION) .build(); } } // Service @Service public class OrderService { private final StateSet stateset; @Autowired public OrderService(StateSet stateset) { this.stateset = stateset; } public Order createOrder(OrderRequest request) throws StateSetException { OrderCreateParams params = convertToParams(request); return Order.create(params); } } ``` ## Swift ### Installation #### Swift Package Manager ```swift theme={null} dependencies: [ .package(url: "https://github.com/stateset/stateset-swift.git", from: "2.0.0") ] ``` #### CocoaPods ```ruby theme={null} pod 'StateSet', '~> 2.0' ``` ### Quick Start ```swift theme={null} import StateSet // Initialize client let client = StateSetClient( apiKey: ProcessInfo.processInfo.environment["STATESET_API_KEY"]!, environment: .production, timeout: 30, maxRetries: 3 ) // Create an order let customer = CustomerParams( email: "customer@example.com", firstName: "John", lastName: "Doe" ) let item = OrderItemParams( sku: "WIDGET-001", quantity: 2, price: 2999 ) let address = AddressParams( line1: "123 Main St", city: "San Francisco", state: "CA", postalCode: "94105", country: "US" ) let params = OrderCreateParams( customer: customer, items: [item], shippingAddress: address ) client.orders.create(params) { result in switch result { case .success(let order): print("Order created: \(order.id)") case .failure(let error): print("Error: \(error.localizedDescription)") } } ``` ### Async/Await Support ```swift theme={null} // iOS 13+, macOS 10.15+ @available(iOS 13.0, *) func createOrder() async throws { let order = try await client.orders.create(params) print("Order created: \(order.id)") } // SwiftUI Integration struct OrderView: View { @StateObject private var viewModel = OrderViewModel() var body: some View { Button("Create Order") { Task { await viewModel.createOrder() } } } } @MainActor class OrderViewModel: ObservableObject { @Published var order: Order? @Published var isLoading = false @Published var error: Error? private let client = StateSetClient() func createOrder() async { isLoading = true do { order = try await client.orders.create(params) } catch { self.error = error } isLoading = false } } ``` ## SDK Features Comparison | Feature | Node.js | Python | Go | Ruby | PHP | .NET | Java | Swift | | ---------------- | ------------ | ------------ | -------- | ------ | -------- | ------ | ------------------- | ------ | | **Type Safety** | ✅ TypeScript | ✅ Type Hints | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | | **Async/Await** | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ CompletableFuture | ✅ | | **Auto-Retry** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | **Webhooks** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | **Pagination** | ✅ Auto | ✅ Auto | ✅ Manual | ✅ Auto | ✅ Manual | ✅ Auto | ✅ Manual | ✅ Auto | | **Streaming** | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | | **Interceptors** | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | | **File Upload** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | **GraphQL** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ## Common Patterns ### Error Handling Across SDKs All SDKs follow similar error handling patterns: ```javascript theme={null} // JavaScript/TypeScript try { const order = await stateset.orders.create(params); } catch (error) { if (error.code === 'rate_limited') { // Handle rate limiting } else if (error.code === 'validation_error') { // Handle validation errors } else { // Handle other errors } } ``` ```python theme={null} # Python try: order = stateset.orders.create(**params) except RateLimitError as e: # Handle rate limiting pass except ValidationError as e: # Handle validation errors pass except StateSetError as e: # Handle other errors pass ``` ### Idempotency Across SDKs All SDKs support idempotency keys: ```javascript theme={null} // JavaScript const order = await stateset.orders.create(params, { idempotencyKey: 'unique-key-123' }); ``` ```python theme={null} # Python order = stateset.orders.create( **params, idempotency_key='unique-key-123' ) ``` ```go theme={null} // Go params.IdempotencyKey = stateset.String("unique-key-123") order, err := client.Orders.Create(ctx, params) ``` ## Community SDKs Community SDKs are not officially maintained by StateSet. Use at your own discretion. * **Rust**: [stateset-rust](https://github.com/community/stateset-rust) * **Kotlin**: [stateset-kotlin](https://github.com/community/stateset-kotlin) * **Dart/Flutter**: [stateset-dart](https://github.com/community/stateset-dart) * **Elixir**: [stateset-elixir](https://github.com/community/stateset-elixir) * **Clojure**: [stateset-clj](https://github.com/community/stateset-clj) ## SDK Development ### Contributing We welcome contributions to our SDKs! See our [SDK Development Guide](https://github.com/stateset/sdk-development) for: * Code style guidelines * Testing requirements * Release process * API coverage requirements ### Reporting Issues * **Bug Reports**: [GitHub Issues](https://github.com/stateset/stateset-\{language}/issues) * **Feature Requests**: [Discord Community](https://discord.gg/VfcaqgZywq) * **Security Issues**: [security@stateset.com](mailto:security@stateset.com) ## Related Resources * [API Reference](/api-reference/introduction) - Complete API documentation * [Quickstart Guide](/api-reference/quickstart) - Get started quickly * [Authentication](/api-reference/authentication) - Auth methods * [Error Handling](/api-reference/errors) - Error codes and handling * [Code Examples](https://github.com/stateset/examples) - Sample implementations *** **Need SDK support?** Contact [sdk-support@stateset.com](mailto:sdk-support@stateset.com) or visit our [Discord community](https://discord.gg/VfcaqgZywq). # Search API Source: https://docs.stateset.com/api-reference/search POST https://api.stateset.com/v1/search Powerful search endpoint for finding records across multiple resources with advanced filtering and faceting. ### Body The search query string. Supports fuzzy matching and operators Array of resource types to search. If empty, searches all resources. Options: \["orders", "customers", "products", "inventory", "returns", "warranties", "tickets"] Advanced filters to narrow search results Filter by date range Date field to filter on (e.g., "created\_at", "updated\_at") Start date (ISO 8601) End date (ISO 8601) Filter by status values Filter by tags Filter by custom field values Fields to generate facet counts for Sort configuration Field to sort by Sort order: "asc" or "desc" Pagination configuration Page number (1-based) Results per page (max 100) Whether to include highlighted snippets in results Whether to include search suggestions for typos ### Response Array of search results Unique identifier of the result Type of resource (e.g., "order", "customer") Relevance score The actual resource data Highlighted text snippets (if enabled) Facet counts for requested fields Search suggestions for possible typos Total number of results found Current page number Results per page Time taken to execute the query in milliseconds ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/search' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "query": "john doe refund", "resources": ["orders", "customers", "returns"], "filters": { "date_range": { "field": "created_at", "from": "2024-01-01", "to": "2024-12-31" }, "status": ["active", "pending"] }, "facets": ["resource_type", "status", "tags"], "sort": { "field": "created_at", "order": "desc" }, "pagination": { "page": 1, "per_page": 20 }, "highlight": true, "suggest": true }' ``` ```graphQL GraphQL theme={null} query searchQuery { search( query: "${query}", resources: ${resources}, filters: ${filters}, facets: ${facets}, sort: ${sort}, pagination: ${pagination}, highlight: ${highlight}, suggest: ${suggest} ) { results { id resource_type score data highlights } facets suggestions total_results query_time_ms } } ``` ```js Node.js theme={null} const searchResults = await stateset.search({ query: 'john doe refund', resources: ['orders', 'customers', 'returns'], filters: { date_range: { field: 'created_at', from: '2024-01-01', to: '2024-12-31' }, status: ['active', 'pending'] }, facets: ['resource_type', 'status', 'tags'], sort: { field: 'created_at', order: 'desc' }, pagination: { page: 1, per_page: 20 }, highlight: true, suggest: true }); ``` ```python Python theme={null} search_results = stateset.search({ 'query': 'john doe refund', 'resources': ['orders', 'customers', 'returns'], 'filters': { 'date_range': { 'field': 'created_at', 'from': '2024-01-01', 'to': '2024-12-31' }, 'status': ['active', 'pending'] }, 'facets': ['resource_type', 'status', 'tags'], 'sort': { 'field': 'created_at', 'order': 'desc' }, 'pagination': { 'page': 1, 'per_page': 20 }, 'highlight': True, 'suggest': True }) ``` ```ruby Ruby theme={null} search_results = Stateset.search({ query: 'john doe refund', resources: ['orders', 'customers', 'returns'], filters: { date_range: { field: 'created_at', from: '2024-01-01', to: '2024-12-31' }, status: ['active', 'pending'] }, facets: ['resource_type', 'status', 'tags'], sort: { field: 'created_at', order: 'desc' }, pagination: { page: 1, per_page: 20 }, highlight: true, suggest: true }) ``` ```go Go theme={null} searchResults, err := stateset.Search(SearchParams{ Query: "john doe refund", Resources: []string{"orders", "customers", "returns"}, Filters: Filters{ DateRange: DateRange{ Field: "created_at", From: "2024-01-01", To: "2024-12-31" }, Status: []string{"active", "pending"} }, Facets: []string{"resource_type", "status", "tags"}, Sort: Sort{ Field: "created_at", Order: "desc" }, Pagination: Pagination{ Page: 1, PerPage: 20 }, Highlight: true, Suggest: true }) ``` ```java Java theme={null} SearchResults searchResults = stateset.search(new SearchParams() .setQuery("john doe refund") .setResources(Arrays.asList("orders", "customers", "returns")) .setFilters(new Filters() .setDateRange(new DateRange() .setField("created_at") .setFrom("2024-01-01") .setTo("2024-12-31")) .setStatus(Arrays.asList("active", "pending"))) .setFacets(Arrays.asList("resource_type", "status", "tags")) .setSort(new Sort() .setField("created_at") .setOrder("desc")) .setPagination(new Pagination() .setPage(1) .setPerPage(20)) .setHighlight(true) .setSuggest(true)); ``` ```php PHP theme={null} $search_results = $stateset->search([ 'query' => 'john doe refund', 'resources' => ['orders', 'customers', 'returns'], 'filters' => [ 'date_range' => [ 'field' => 'created_at', 'from' => '2024-01-01', 'to' => '2024-12-31' ], 'status' => ['active', 'pending'] ], 'facets' => ['resource_type', 'status', 'tags'], 'sort' => [ 'field' => 'created_at', 'order' => 'desc' ], 'pagination' => [ 'page' => 1, 'per_page' => 20 ], 'highlight' => true, 'suggest' => true ]); ``` ```csharp C# theme={null} var searchResults = await stateset.Search(new SearchParams { Query = "john doe refund", Resources = new[] { "orders", "customers", "returns" }, Filters = new Filters { DateRange = new DateRange { Field = "created_at", From = "2024-01-01", To = "2024-12-31" }, Status = new[] { "active", "pending" } }, Facets = new[] { "resource_type", "status", "tags" }, Sort = new Sort { Field = "created_at", Order = "desc" }, Pagination = new Pagination { Page = 1, PerPage = 20 }, Highlight = true, Suggest = true }); ``` ```json Response theme={null} { "results": [ { "id": "ord_123abc", "resource_type": "order", "score": 0.95, "data": { "id": "ord_123abc", "customer_name": "John Doe", "total": 299.99, "status": "pending", "created_at": "2024-03-15T10:30:00Z" }, "highlights": { "customer_name": "John Doe", "notes": "Customer requested refund for damaged item" } }, { "id": "cust_456def", "resource_type": "customer", "score": 0.88, "data": { "id": "cust_456def", "name": "John Doe", "email": "john.doe@example.com", "status": "active" }, "highlights": { "name": "John Doe" } } ], "facets": { "resource_type": { "order": 5, "customer": 3, "return": 2 }, "status": { "active": 6, "pending": 4 }, "tags": { "vip": 2, "priority": 3 } }, "suggestions": [ { "text": "john doe refunded", "score": 0.92 } ], "total_results": 10, "page": 1, "per_page": 20, "query_time_ms": 23 } ``` ```json Error Response theme={null} { "error": { "code": "invalid_query", "message": "Search query cannot be empty", "details": { "min_query_length": 1, "max_query_length": 1000 } } } ``` # Cancel Shipment Source: https://docs.stateset.com/api-reference/shipments/cancel POST https://api.stateset.com/v1/shipments/:id/cancel Cancel a shipment and void the shipping label This endpoint cancels a shipment and voids the shipping label. Refunds are processed automatically based on carrier policies. ## Authentication This endpoint requires a valid API key with `shipments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the shipment to cancel ## Request Body Cancellation reason: "order\_cancelled", "incorrect\_address", "changed\_shipping\_method", "duplicate", "other" Additional notes about the cancellation ### Response Returns the cancelled shipment with refund information. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/shipments/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "reason": "order_cancelled", "notes": "Customer requested cancellation before shipment" }' ``` ```javascript Node.js theme={null} const shipment = await stateset.shipments.cancel( 'ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { reason: "order_cancelled", notes: "Customer requested cancellation before shipment" } ); ``` ```python Python theme={null} shipment = stateset.shipments.cancel( 'ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', reason="order_cancelled", notes="Customer requested cancellation before shipment" ) ``` ```json Response theme={null} { "id": "ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "shipment", "status": "cancelled", "cancelled_at": "2024-01-19T17:00:00Z", "cancellation": { "reason": "order_cancelled", "notes": "Customer requested cancellation before shipment", "cancelled_by": "user_123" }, "refund": { "status": "processed", "amount": 1250, "currency": "USD", "processed_at": "2024-01-19T17:00:15Z", "reference": "REF-SHIP-001" }, "tracking_number": "1Z999AA10123456784", "carrier": "ups", "metadata": { "cancellation_reference": "CANCEL-2024-001" } } ``` # Create Shipment Source: https://docs.stateset.com/api-reference/shipments/create POST https://api.stateset.com/v1/shipments Create a shipment for outbound orders This endpoint creates a new shipment for one or more orders. It handles carrier integration, label generation, and tracking initialization. ## Authentication This endpoint requires a valid API key with `shipments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Array of order IDs to include in this shipment Origin warehouse ID Carrier for shipment (e.g., "ups", "fedex", "usps", "dhl") Service level (e.g., "ground", "express", "overnight", "2day") Scheduled ship date (ISO 8601) Destination address Recipient name Company name Street address line 1 Street address line 2 City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Contact phone number Contact email for delivery notifications Array of packages in the shipment Package weight Weight value Weight unit ("lb" or "kg") Package dimensions Length Width Height Dimension unit ("in" or "cm") Items in this package Package type (e.g., "box", "envelope", "tube") Insurance options Whether to insure the shipment Insurance value in cents ISO 4217 currency code Whether signature is required on delivery Whether to enable Saturday delivery Customs information for international shipments Type of contents (e.g., "merchandise", "gift", "sample") Array of customs line items Electronic Export Information or Proof of Filing Citation Reference numbers for tracking Purchase order number Invoice number Custom reference 1 Custom reference 2 Label format preference ("pdf", "zpl", "png") Additional custom fields ### Response Returns the created shipment with tracking information and label URLs. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/shipments' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "order_ids": ["order_123456", "order_123457"], "warehouse_id": "wh_001", "carrier": "ups", "service_type": "ground", "ship_date": "2024-01-20T08:00:00Z", "shipping_address": { "name": "John Doe", "company": "Acme Corp", "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US", "phone": "+1-555-123-4567", "email": "john.doe@example.com" }, "packages": [ { "weight": { "value": 5.5, "unit": "lb" }, "dimensions": { "length": 12, "width": 10, "height": 8, "unit": "in" }, "package_type": "box" } ], "insurance": { "enabled": true, "amount": 15000, "currency": "USD" }, "signature_required": true }' ``` ```javascript Node.js theme={null} const shipment = await stateset.shipments.create({ order_ids: ["order_123456", "order_123457"], warehouse_id: "wh_001", carrier: "ups", service_type: "ground", ship_date: "2024-01-20T08:00:00Z", shipping_address: { name: "John Doe", company: "Acme Corp", line1: "123 Main St", city: "Los Angeles", state: "CA", postal_code: "90001", country: "US", phone: "+1-555-123-4567", email: "john.doe@example.com" }, packages: [ { weight: { value: 5.5, unit: "lb" }, dimensions: { length: 12, width: 10, height: 8, unit: "in" }, package_type: "box" } ], signature_required: true }); ``` ```json Response theme={null} { "id": "ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "shipment", "status": "label_created", "created_at": "2024-01-19T14:30:00Z", "ship_date": "2024-01-20T08:00:00Z", "carrier": "ups", "service_type": "ground", "tracking_number": "1Z999AA10123456784", "tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784", "label_url": "https://labels.stateset.com/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30.pdf", "rate": { "amount": 1250, "currency": "USD", "estimated_delivery_date": "2024-01-23T18:00:00Z" }, "packages": [ { "tracking_number": "1Z999AA10123456784", "label_url": "https://labels.stateset.com/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30.pdf", "weight": { "value": 5.5, "unit": "lb" }, "dimensions": { "length": 12, "width": 10, "height": 8, "unit": "in" } } ], "from_address": { "name": "Main Distribution Center", "line1": "456 Warehouse Blvd", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "to_address": { "name": "John Doe", "company": "Acme Corp", "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "order_ids": ["order_123456", "order_123457"], "insurance": { "enabled": true, "amount": 15000, "currency": "USD", "provider": "ups" } } ``` # Get Shipment Source: https://docs.stateset.com/api-reference/shipments/get GET https://api.stateset.com/v1/shipments/:id Retrieve a specific shipment by ID This endpoint retrieves detailed information about a specific shipment including tracking, packages, and delivery status. ## Authentication This endpoint requires a valid API key with `shipments:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the shipment ## Query Parameters Expand related objects. Options: "orders", "packages.items", "events", "documents" ### Response Unique shipment identifier Object type, always "shipment" Current shipment status Master tracking number Tracking URL for customer Shipping carrier Service level Actual or scheduled ship date Actual or estimated delivery date Array of packages in shipment Tracking events (when expanded) ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/shipments/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30?expand=events' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const shipment = await stateset.shipments.retrieve( 'ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { expand: ['events'] } ); ``` ```python Python theme={null} shipment = stateset.shipments.retrieve( 'ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', expand=['events'] ) ``` ```json Response theme={null} { "id": "ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "shipment", "status": "in_transit", "created_at": "2024-01-19T14:30:00Z", "updated_at": "2024-01-20T10:15:00Z", "ship_date": "2024-01-20T08:00:00Z", "delivery_date": "2024-01-23T18:00:00Z", "carrier": "ups", "service_type": "ground", "tracking_number": "1Z999AA10123456784", "tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784", "label_url": "https://labels.stateset.com/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30.pdf", "rate": { "amount": 1250, "currency": "USD", "carrier_account": "ups_12345" }, "packages": [ { "id": "pkg_abc123", "tracking_number": "1Z999AA10123456784", "label_url": "https://labels.stateset.com/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30.pdf", "weight": { "value": 5.5, "unit": "lb" }, "dimensions": { "length": 12, "width": 10, "height": 8, "unit": "in" }, "value": 15000, "reference_number": "PKG-2024-001" } ], "from_address": { "name": "Main Distribution Center", "company": "Stateset", "line1": "456 Warehouse Blvd", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US", "phone": "+1-555-987-6543" }, "to_address": { "name": "John Doe", "company": "Acme Corp", "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US", "phone": "+1-555-123-4567", "email": "john.doe@example.com" }, "order_ids": ["order_123456", "order_123457"], "warehouse_id": "wh_001", "insurance": { "enabled": true, "amount": 15000, "currency": "USD", "provider": "ups", "confirmation_number": "INS123456" }, "signature_required": true, "saturday_delivery": false, "events": [ { "id": "evt_123", "created_at": "2024-01-20T08:05:00Z", "status": "label_created", "description": "Shipping label created", "location": { "city": "Los Angeles", "state": "CA", "country": "US" } }, { "id": "evt_124", "created_at": "2024-01-20T09:30:00Z", "status": "picked_up", "description": "Package picked up by carrier", "location": { "city": "Los Angeles", "state": "CA", "country": "US" } }, { "id": "evt_125", "created_at": "2024-01-20T10:15:00Z", "status": "in_transit", "description": "Package in transit", "location": { "city": "Los Angeles", "state": "CA", "country": "US", "facility": "Los Angeles Distribution Center" } } ], "metadata": { "internal_reference": "SHIP-2024-001", "priority": "standard" } } ``` ```json Error Response (404 Not Found) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Shipment not found", "details": { "resource": "shipment", "id": "shp_abc123" }, "request_id": "req_abc123def456" } } ``` ```json Error Response (401 Unauthorized) theme={null} { "error": { "code": "INVALID_API_KEY", "message": "The API key provided is invalid or has been revoked", "request_id": "req_abc123def456" } } ``` # List Shipments Source: https://docs.stateset.com/api-reference/shipments/list GET https://api.stateset.com/v1/shipments List all shipments with filtering and pagination This endpoint retrieves a paginated list of shipments. Use filters to narrow results by status, date range, carrier, and more. ## Authentication This endpoint requires a valid API key with `shipments:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of items to return (default: 20, max: 100) Number of items to skip Filter by status: "label\_created", "picked\_up", "in\_transit", "out\_for\_delivery", "delivered", "returned", "failed" Filter by carrier: "ups", "fedex", "usps", "dhl" Filter by origin warehouse Filter by associated order Filter by tracking number Filter by ship date start (ISO 8601) Filter by ship date end (ISO 8601) Filter by delivery date start (ISO 8601) Filter by delivery date end (ISO 8601) Filter by destination country code Filter by destination state/province Sort field: "created\_at", "ship\_date", "delivery\_date", "status" Sort order: "asc" or "desc" (default: "desc") ### Response Object type, always "list" Array of shipment objects Whether more items exist Total number of matching shipments ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/shipments?status=in_transit&limit=10' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const shipments = await stateset.shipments.list({ status: 'in_transit', limit: 10, sort_by: 'ship_date', sort_order: 'desc' }); ``` ```python Python theme={null} shipments = stateset.shipments.list( status='in_transit', limit=10, sort_by='ship_date', sort_order='desc' ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "shipment", "status": "in_transit", "created_at": "2024-01-19T14:30:00Z", "ship_date": "2024-01-20T08:00:00Z", "delivery_date": "2024-01-23T18:00:00Z", "carrier": "ups", "service_type": "ground", "tracking_number": "1Z999AA10123456784", "tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784", "packages_count": 1, "total_weight": { "value": 5.5, "unit": "lb" }, "from_address": { "city": "Los Angeles", "state": "CA", "country": "US" }, "to_address": { "name": "John Doe", "city": "Los Angeles", "state": "CA", "country": "US" }, "order_ids": ["order_123456", "order_123457"], "rate": { "amount": 1250, "currency": "USD" } }, { "id": "ship_7823f083-bb2c-54d6-bf6d-1b8e3fc75f41", "object": "shipment", "status": "in_transit", "created_at": "2024-01-19T10:15:00Z", "ship_date": "2024-01-19T14:00:00Z", "delivery_date": "2024-01-22T18:00:00Z", "carrier": "fedex", "service_type": "express", "tracking_number": "772123456789", "tracking_url": "https://www.fedex.com/apps/fedextrack/?tracknumbers=772123456789", "packages_count": 2, "total_weight": { "value": 12.3, "unit": "lb" }, "from_address": { "city": "New York", "state": "NY", "country": "US" }, "to_address": { "name": "Jane Smith", "city": "Chicago", "state": "IL", "country": "US" }, "order_ids": ["order_789012"], "rate": { "amount": 2850, "currency": "USD" } } ], "has_more": true, "total_count": 156, "page_info": { "limit": 10, "offset": 0 } } ``` # Update Shipment Source: https://docs.stateset.com/api-reference/shipments/update PUT https://api.stateset.com/v1/shipments/:id Update shipment details before shipping This endpoint updates shipment details. Only shipments with status "label\_created" can be modified. Once picked up, use the cancel endpoint to void. ## Authentication This endpoint requires a valid API key with `shipments:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the shipment ## Request Body New scheduled ship date (ISO 8601) Updated service level Update signature requirement Update Saturday delivery option Update insurance options Enable/disable insurance Insurance value in cents Update reference numbers Update custom fields ### Response Returns the updated shipment object. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/shipments/ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "ship_date": "2024-01-21T08:00:00Z", "service_type": "express", "insurance": { "enabled": true, "amount": 20000 } }' ``` ```javascript Node.js theme={null} const shipment = await stateset.shipments.update( 'ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { ship_date: "2024-01-21T08:00:00Z", service_type: "express", insurance: { enabled: true, amount: 20000 } } ); ``` ```json Response theme={null} { "id": "ship_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "shipment", "status": "label_created", "updated_at": "2024-01-19T16:00:00Z", "ship_date": "2024-01-21T08:00:00Z", "carrier": "ups", "service_type": "express", "rate": { "amount": 2850, "currency": "USD", "estimated_delivery_date": "2024-01-22T18:00:00Z" }, "insurance": { "enabled": true, "amount": 20000, "currency": "USD" } } ``` # Cancel Subscription Source: https://docs.stateset.com/api-reference/subscriptions/cancel POST https://api.stateset.com/v1/subscriptions/:id/cancel Cancel an active subscription This endpoint cancels a subscription. You can choose to cancel immediately or at the end of the current billing period. ## Authentication This endpoint requires a valid API key with `subscriptions:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the subscription to cancel ## Request Body If true, cancel at end of current period. If false, cancel immediately (default: true) Cancellation reason: "too\_expensive", "missing\_features", "not\_using", "switching\_provider", "other" Additional feedback about cancellation Override to cancel immediately regardless of period ### Response Returns the cancelled subscription object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/subscriptions/sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "cancel_at_period_end": true, "reason": "too_expensive", "feedback": "The pricing increased beyond our budget" }' ``` ```javascript Node.js theme={null} const subscription = await stateset.subscriptions.cancel( 'sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { cancel_at_period_end: true, reason: "too_expensive", feedback: "The pricing increased beyond our budget" } ); ``` ```python Python theme={null} subscription = stateset.subscriptions.cancel( 'sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', cancel_at_period_end=True, reason="too_expensive", feedback="The pricing increased beyond our budget" ) ``` ```json Response theme={null} { "id": "sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "subscription", "status": "active", "cancel_at_period_end": true, "cancel_at": "2024-03-01T00:00:00Z", "cancelled_at": "2024-01-20T15:00:00Z", "cancellation_details": { "reason": "too_expensive", "feedback": "The pricing increased beyond our budget", "cancelled_by": "user_123" }, "current_period_end": "2024-03-01", "ended_at": null, "customer_id": "cust_abc123", "plan": { "id": "plan_monthly_pro", "name": "Professional Monthly" }, "metadata": { "cancellation_flow": "customer_portal", "retention_offered": true, "retention_accepted": false } } ``` # Create Subscription Source: https://docs.stateset.com/api-reference/subscriptions/create POST https://api.stateset.com/v1/subscriptions Create a recurring subscription for a customer This endpoint creates a new subscription for recurring billing. Subscriptions automatically generate invoices and process payments based on the billing cycle. ## Authentication This endpoint requires a valid API key with `subscriptions:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Customer ID for the subscription Subscription plan ID Subscription start date (ISO 8601) Default payment method for automatic billing Number of subscriptions (default: 1) Trial period end date (ISO 8601) Date to anchor billing cycles (ISO 8601) Additional subscription items Product ID Quantity Override price in cents Coupon to apply to subscription Shipping address for physical subscriptions Street address Apartment/Suite City State/Province Postal code Country code Additional custom fields ### Response Returns the created subscription. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/subscriptions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "customer_id": "cust_abc123", "plan_id": "plan_monthly_pro", "start_date": "2024-02-01", "payment_method_id": "pm_card_visa", "trial_end": "2024-02-14", "items": [ { "product_id": "prod_addon_storage", "quantity": 2 } ], "shipping_address": { "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" } }' ``` ```javascript Node.js theme={null} const subscription = await stateset.subscriptions.create({ customer_id: "cust_abc123", plan_id: "plan_monthly_pro", start_date: "2024-02-01", payment_method_id: "pm_card_visa", trial_end: "2024-02-14", items: [ { product_id: "prod_addon_storage", quantity: 2 } ], shipping_address: { line1: "123 Main St", city: "Los Angeles", state: "CA", postal_code: "90001", country: "US" } }); ``` ```json Response theme={null} { "id": "sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "subscription", "customer_id": "cust_abc123", "status": "trialing", "created_at": "2024-01-19T17:00:00Z", "start_date": "2024-02-01", "current_period_start": "2024-02-01", "current_period_end": "2024-03-01", "trial_start": "2024-02-01", "trial_end": "2024-02-14", "plan": { "id": "plan_monthly_pro", "name": "Professional Monthly", "amount": 9900, "currency": "USD", "interval": "month", "interval_count": 1 }, "items": [ { "id": "si_123456", "product_id": "prod_addon_storage", "product_name": "Additional Storage (10GB)", "quantity": 2, "unit_price": 500, "amount": 1000 } ], "quantity": 1, "subtotal": 10900, "tax_amount": 872, "total_amount": 11772, "payment_method_id": "pm_card_visa", "default_payment_method": { "id": "pm_card_visa", "type": "card", "card": { "brand": "visa", "last4": "4242", "exp_month": 12, "exp_year": 2025 } }, "shipping_address": { "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "next_invoice_date": "2024-03-01", "cancel_at_period_end": false } ``` # Get Subscription Source: https://docs.stateset.com/api-reference/subscriptions/get GET https://api.stateset.com/v1/subscriptions/:id Retrieve a specific subscription by ID This endpoint retrieves detailed information about a specific subscription including plan details, billing history, and upcoming invoices. ## Authentication This endpoint requires a valid API key with `subscriptions:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the subscription ## Query Parameters Expand related objects. Options: "customer", "payment\_method", "invoices", "upcoming\_invoice" ### Response Unique subscription identifier Object type, always "subscription" Subscription status: "trialing", "active", "past\_due", "cancelled", "unpaid" Start of current billing period End of current billing period Subscription plan details ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/subscriptions/sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30?expand=upcoming_invoice' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const subscription = await stateset.subscriptions.retrieve( 'sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { expand: ['upcoming_invoice'] } ); ``` ```python Python theme={null} subscription = stateset.subscriptions.retrieve( 'sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', expand=['upcoming_invoice'] ) ``` ```json Response theme={null} { "id": "sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "subscription", "customer_id": "cust_abc123", "status": "active", "created_at": "2024-01-19T17:00:00Z", "start_date": "2024-02-01", "current_period_start": "2024-02-01", "current_period_end": "2024-03-01", "trial_start": "2024-02-01", "trial_end": "2024-02-14", "plan": { "id": "plan_monthly_pro", "name": "Professional Monthly", "amount": 9900, "currency": "USD", "interval": "month", "interval_count": 1, "features": [ "Unlimited orders", "Advanced analytics", "Priority support", "API access" ] }, "items": [ { "id": "si_123456", "product_id": "prod_addon_storage", "product_name": "Additional Storage (10GB)", "quantity": 2, "unit_price": 500, "amount": 1000 } ], "quantity": 1, "subtotal": 10900, "tax_amount": 872, "total_amount": 11772, "payment_method_id": "pm_card_visa", "default_payment_method": { "id": "pm_card_visa", "type": "card", "card": { "brand": "visa", "last4": "4242", "exp_month": 12, "exp_year": 2025 } }, "shipping_address": { "line1": "123 Main St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "next_invoice_date": "2024-03-01", "cancel_at_period_end": false, "upcoming_invoice": { "amount_due": 11772, "currency": "USD", "period_start": "2024-03-01", "period_end": "2024-04-01", "lines": [ { "description": "Professional Monthly", "amount": 9900 }, { "description": "Additional Storage (10GB) × 2", "amount": 1000 } ] }, "metadata": { "sales_rep": "john_smith", "campaign": "Q1_2024" } } ``` # List Subscriptions Source: https://docs.stateset.com/api-reference/subscriptions/list GET https://api.stateset.com/v1/subscriptions List all subscriptions with filtering and pagination This endpoint retrieves a paginated list of subscriptions. Use filters to narrow results by status, customer, plan, and more. ## Authentication This endpoint requires a valid API key with `subscriptions:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of items to return (default: 20, max: 100) Cursor for pagination (subscription ID) Filter by status: "trialing", "active", "past\_due", "cancelled", "unpaid" Filter by customer ID Filter by plan ID Filter by creation date start (ISO 8601) Filter by creation date end (ISO 8601) Show subscriptions ending before date Sort field: "created\_at", "start\_date", "total\_amount" Sort order: "asc" or "desc" ### Response Object type, always "list" Array of subscription objects Whether more items exist ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/subscriptions?status=active&limit=10' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const subscriptions = await stateset.subscriptions.list({ status: 'active', limit: 10, sort_by: 'created_at' }); ``` ```python Python theme={null} subscriptions = stateset.subscriptions.list( status='active', limit=10, sort_by='created_at' ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "subscription", "customer_id": "cust_abc123", "customer_name": "Acme Corporation", "status": "active", "plan": { "id": "plan_monthly_pro", "name": "Professional Monthly", "amount": 9900 }, "total_amount": 11772, "current_period_end": "2024-03-01", "next_invoice_date": "2024-03-01" }, { "id": "sub_7823f083-bb2c-54d6-bf6d-1b8e3fc75f41", "object": "subscription", "customer_id": "cust_def456", "customer_name": "TechCorp Inc", "status": "active", "plan": { "id": "plan_annual_enterprise", "name": "Enterprise Annual", "amount": 99900 }, "total_amount": 99900, "current_period_end": "2025-01-15", "next_invoice_date": "2025-01-15" } ], "has_more": true, "url": "/v1/subscriptions" } ``` # Update Subscription Source: https://docs.stateset.com/api-reference/subscriptions/update PUT https://api.stateset.com/v1/subscriptions/:id Update an existing subscription This endpoint updates subscription details including items, quantities, and payment methods. Plan changes take effect at the next billing cycle. ## Authentication This endpoint requires a valid API key with `subscriptions:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the subscription ## Request Body Change to a different plan (takes effect next billing cycle) Update subscription quantity Update subscription items Item ID to update (omit for new items) Product ID Item quantity Set to true to remove item Update default payment method Apply a coupon Extend or end trial period Update custom fields ### Response Returns the updated subscription object. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/subscriptions/sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "items": [ { "id": "si_123456", "quantity": 3 }, { "product_id": "prod_premium_support", "quantity": 1 } ], "coupon_id": "SAVE20" }' ``` ```javascript Node.js theme={null} const subscription = await stateset.subscriptions.update( 'sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', { items: [ { id: "si_123456", quantity: 3 }, { product_id: "prod_premium_support", quantity: 1 } ], coupon_id: "SAVE20" } ); ``` ```python Python theme={null} subscription = stateset.subscriptions.update( 'sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30', items=[ { "id": "si_123456", "quantity": 3 }, { "product_id": "prod_premium_support", "quantity": 1 } ], coupon_id="SAVE20" ) ``` ```json Response theme={null} { "id": "sub_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "subscription", "updated_at": "2024-01-20T14:00:00Z", "status": "active", "items": [ { "id": "si_123456", "product_id": "prod_addon_storage", "product_name": "Additional Storage (10GB)", "quantity": 3, "unit_price": 500, "amount": 1500 }, { "id": "si_789012", "product_id": "prod_premium_support", "product_name": "Premium Support", "quantity": 1, "unit_price": 2900, "amount": 2900 } ], "discount": { "coupon": { "id": "SAVE20", "percent_off": 20, "duration": "repeating", "duration_in_months": 3 } }, "subtotal": 14300, "discount_amount": 2860, "tax_amount": 915, "total_amount": 12355 } ``` # Create Supplier Source: https://docs.stateset.com/api-reference/suppliers/create POST https://api.stateset.com/v1/suppliers This endpoint creates a new supplier ### Body This is the current user group token you have for the user group that you want to rotate. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The contents of the user group This is the internal ID for this user group. You don't need to record this information, since you will not need to use it. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the environment tag of the user group. Possible values are 'Customer' and 'Testing'. User group id's must be unique to each environment, so you can not create multiple user groups with with same id. If you have a production customer and a test user group with the same id, you will be required to label one as 'Customer' and another as 'Testing' ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/supplier' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Delete Supplier Source: https://docs.stateset.com/api-reference/suppliers/delete DELETE https://api.return.com/v1/suppliers/:id This endpoint deletes an existing supplier. ### Body The data source ID provided in the data tab may be used to identify the data source for the user group This is the current user group token you have for the user group you want to delete ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/suppliers/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```json Response theme={null} { "success": 1 } ``` # Get Supplier Source: https://docs.stateset.com/api-reference/suppliers/get GET https://api.stateset.com/v1/suppliers/:id This endpoint gets or creates a new supplier. ### Body This is the name of the user group. This is the ID you use to identify this user group in your database. This is a JSON mapping of schema id to either the data source that this user group should be associated with or id of the datasource you provided when creating it. This is a JSON object for properties assigned to this user group. These will be accessible through variables in the dashboards and SQL editor ### Response Indicates whether the call was successful. 1 if successful, 0 if not. Indicates whether a new user group was created. The contents of the user group This is the internal ID for this user group. You don't need to record this information, since you will not need to use it. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the properties object if it was provided in the request body ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/supplier' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "new_user_group": true, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # List Suppliers Source: https://docs.stateset.com/api-reference/suppliers/list List suppliers. # List Suppliers Use this endpoint to list suppliers. # Update Supplier Source: https://docs.stateset.com/api-reference/suppliers/update PUT https://api.stateset.com/v1/suppliers/:id This endpoint updates an existing supplier. ### Body This is the name of the user group. This is the ID you use to identify this user group in your database. This is a JSON mapping of schema id to either the data source that this user group should be associated with or id of the datasource you provided when creating it. This is a JSON object for properties assigned to this user group. These will be accessible through variables in the dashboards and SQL editor ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The contents of the user group Indicates whether a new user group was created. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the properties object if it was provided in the request body This is the environment tag of the user group. Possible values are 'Customer' and 'Testing' ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/suppliers/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # Calculate Tax Source: https://docs.stateset.com/api-reference/tax/calculate POST https://api.stateset.com/v1/tax/calculate Calculate taxes for an order based on location and items This endpoint calculates applicable taxes for a given order, considering all active tax rates, exemptions, and nexus rules. It returns a detailed breakdown of all taxes to be collected. ## Authentication This endpoint requires a valid API key with `tax:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Origin address (seller location) Street address City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Destination address (buyer location) Street address City State/Province code Postal/ZIP code ISO 3166-1 alpha-2 country code Items to calculate tax for Line item identifier Quantity Unit price in cents Product category for tax rules Specific tax code override Discount amount in cents Shipping details Shipping cost in cents Override shipping taxability Customer details for exemptions Customer ID Customer type for exemptions Whether customer is tax exempt Tax exemption certificate numbers Transaction date for rate determination (ISO 8601) ISO 4217 currency code (default: USD) ### Response Returns detailed tax calculation breakdown. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/tax/calculate' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "from_address": { "line1": "100 Commerce Way", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" }, "to_address": { "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "line_items": [ { "id": "item_1", "quantity": 2, "unit_price": 2999, "product_category": "clothing" }, { "id": "item_2", "quantity": 1, "unit_price": 999, "product_category": "food_grocery" } ], "shipping": { "amount": 1000 }, "customer": { "id": "cust_abc123", "type": "retail" } }' ``` ```javascript Node.js theme={null} const taxCalculation = await stateset.tax.calculate({ from_address: { line1: "100 Commerce Way", city: "Los Angeles", state: "CA", postal_code: "90001", country: "US" }, to_address: { line1: "123 Main St", city: "San Francisco", state: "CA", postal_code: "94105", country: "US" }, line_items: [ { id: "item_1", quantity: 2, unit_price: 2999, product_category: "clothing" }, { id: "item_2", quantity: 1, unit_price: 999, product_category: "food_grocery" } ], shipping: { amount: 1000 }, customer: { id: "cust_abc123", type: "retail" } }); ``` ```json Response theme={null} { "object": "tax_calculation", "order_total": 7997, "taxable_amount": 6998, "tax_amount": 613, "effective_rate": 0.0876, "line_items": [ { "id": "item_1", "amount": 5998, "taxable_amount": 5998, "tax_amount": 540, "tax_breakdown": [ { "name": "California State Sales Tax", "rate": 0.0725, "amount": 435, "taxable_amount": 5998 }, { "name": "San Francisco County Tax", "rate": 0.0175, "amount": 105, "taxable_amount": 5998 } ] }, { "id": "item_2", "amount": 999, "taxable_amount": 0, "tax_amount": 0, "exemption_reason": "food_grocery_exempt" } ], "shipping": { "amount": 1000, "taxable_amount": 1000, "tax_amount": 73, "tax_breakdown": [ { "name": "California State Sales Tax", "rate": 0.0725, "amount": 73 } ] }, "jurisdictions": [ { "name": "California", "type": "state", "rate": 0.0725, "tax_amount": 508 }, { "name": "San Francisco County", "type": "county", "rate": 0.0175, "tax_amount": 105 } ], "has_nexus": true, "tax_registration": { "state": "CA", "registration_number": "CA-123456789" }, "warnings": [], "metadata": { "calculation_timestamp": "2024-01-20T11:30:00Z", "tax_engine_version": "2024.1" } } ``` # Create Tax Rate Source: https://docs.stateset.com/api-reference/tax/create-rate POST https://api.stateset.com/v1/tax/rates Create a new tax rate for a specific jurisdiction This endpoint creates a new tax rate that can be applied to orders based on location, product category, or customer type. Tax rates support complex jurisdiction hierarchies and exemptions. ## Authentication This endpoint requires a valid API key with `tax:write` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body Tax rate name (e.g., "California State Sales Tax") Unique tax code identifier Tax rate as a decimal (e.g., 0.0725 for 7.25%) Tax type: "sales", "vat", "gst", "pst", "hst", "custom" Tax jurisdiction details ISO 3166-1 alpha-2 country code State/Province code (ISO 3166-2) County name City name Applicable postal/ZIP codes (empty for all) Special tax district name Tax application rules Applicable product categories (empty for all) Exempt product categories Applicable customer types (empty for all) Exempt customer types (e.g., "wholesale", "government") Minimum order amount for tax to apply (in cents) Whether shipping is taxable Whether this tax compounds on other taxes Application order (lower applies first) Tax rate validity period When tax rate becomes effective (ISO 8601) When tax rate expires (ISO 8601) Tax registration details Tax registration/license number Registered business name Registered address Whether prices include this tax (common for VAT) Tax rate status: "active", "pending", "inactive" Additional custom fields ### Response Returns the created tax rate object. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/tax/rates' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "name": "California State Sales Tax", "code": "CA_STATE_SALES", "rate": 0.0725, "type": "sales", "jurisdiction": { "country": "US", "state": "CA" }, "rules": { "exempt_categories": ["food_grocery", "prescription_drugs"], "exempt_customer_types": ["wholesale", "government"], "shipping_taxable": true, "compound": false, "priority": 1 }, "validity": { "effective_date": "2024-01-01T00:00:00Z" }, "registration": { "registration_number": "CA-123456789" }, "is_inclusive": false, "status": "active" }' ``` ```javascript Node.js theme={null} const taxRate = await stateset.tax.rates.create({ name: "California State Sales Tax", code: "CA_STATE_SALES", rate: 0.0725, type: "sales", jurisdiction: { country: "US", state: "CA" }, rules: { exempt_categories: ["food_grocery", "prescription_drugs"], exempt_customer_types: ["wholesale", "government"], shipping_taxable: true, compound: false, priority: 1 }, validity: { effective_date: "2024-01-01T00:00:00Z" }, registration: { registration_number: "CA-123456789" }, is_inclusive: false, status: "active" }); ``` ```python Python theme={null} tax_rate = stateset.tax.rates.create( name="California State Sales Tax", code="CA_STATE_SALES", rate=0.0725, type="sales", jurisdiction={ "country": "US", "state": "CA" }, rules={ "exempt_categories": ["food_grocery", "prescription_drugs"], "exempt_customer_types": ["wholesale", "government"], "shipping_taxable": True, "compound": False, "priority": 1 }, validity={ "effective_date": "2024-01-01T00:00:00Z" }, registration={ "registration_number": "CA-123456789" }, is_inclusive=False, status="active" ) ``` ```json Response theme={null} { "id": "tax_rate_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "tax_rate", "name": "California State Sales Tax", "code": "CA_STATE_SALES", "rate": 0.0725, "type": "sales", "jurisdiction": { "country": "US", "state": "CA", "level": "state", "display_name": "California, United States" }, "rules": { "product_categories": [], "exempt_categories": ["food_grocery", "prescription_drugs"], "customer_types": [], "exempt_customer_types": ["wholesale", "government"], "minimum_amount": null, "shipping_taxable": true, "compound": false, "priority": 1 }, "validity": { "effective_date": "2024-01-01T00:00:00Z", "expiration_date": null, "is_active": true }, "registration": { "registration_number": "CA-123456789", "registered_name": null, "registered_address": null }, "is_inclusive": false, "status": "active", "created_at": "2024-01-20T11:00:00Z", "updated_at": "2024-01-20T11:00:00Z", "created_by": "user_123", "statistics": { "orders_count": 0, "total_tax_collected": 0, "last_applied": null } } ``` # Get Tax Rate Source: https://docs.stateset.com/api-reference/tax/get-rate GET https://api.stateset.com/v1/tax/rates/:id Retrieve details of a specific tax rate This endpoint retrieves detailed information about a specific tax rate, including its jurisdiction details and application statistics. ## Authentication This endpoint requires a valid API key with `tax:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Path Parameters The unique identifier of the tax rate ### Response Returns the tax rate object if found. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/tax/rates/tax_rate_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const taxRate = await stateset.tax.rates.retrieve( 'tax_rate_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```python Python theme={null} tax_rate = stateset.tax.rates.retrieve( 'tax_rate_0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```json Response theme={null} { "id": "tax_rate_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "tax_rate", "name": "California State Sales Tax", "code": "CA_STATE_SALES", "rate": 0.0725, "type": "sales", "jurisdiction": { "country": "US", "state": "CA", "county": null, "city": null, "postal_codes": [], "district": null, "level": "state", "display_name": "California, United States" }, "rules": { "product_categories": [], "exempt_categories": ["food_grocery", "prescription_drugs"], "customer_types": [], "exempt_customer_types": ["wholesale", "government"], "minimum_amount": null, "shipping_taxable": true, "compound": false, "priority": 1 }, "validity": { "effective_date": "2024-01-01T00:00:00Z", "expiration_date": null, "is_active": true }, "registration": { "registration_number": "CA-123456789", "registered_name": "Acme Corporation", "registered_address": { "line1": "123 Commerce St", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" } }, "is_inclusive": false, "status": "active", "created_at": "2024-01-20T11:00:00Z", "updated_at": "2024-01-20T11:00:00Z", "created_by": "user_123", "statistics": { "orders_count": 15234, "total_tax_collected": 1847532, "last_applied": "2024-06-20T14:45:00Z", "monthly_collections": [ { "month": "2024-06", "amount": 342150, "orders": 2834 } ] } } ``` # List Tax Rates Source: https://docs.stateset.com/api-reference/tax/list-rates GET https://api.stateset.com/v1/tax/rates List all tax rates with filtering options This endpoint returns a paginated list of tax rates. You can filter by jurisdiction, type, status, and more. ## Authentication This endpoint requires a valid API key with `tax:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Number of tax rates to return (1-100) Number of tax rates to skip Filter by country code (ISO 3166-1 alpha-2) Filter by state/province code Filter by tax type: "sales", "vat", "gst", "pst", "hst", "custom" Filter by status: "active", "pending", "inactive" Filter by inclusive/exclusive taxes Filter rates effective on a specific date (ISO 8601) ### Response Returns a paginated list of tax rate objects. ```bash cURL theme={null} curl --location 'https://api.stateset.com/v1/tax/rates?country=US&status=active' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```javascript Node.js theme={null} const taxRates = await stateset.tax.rates.list({ country: 'US', status: 'active' }); ``` ```python Python theme={null} tax_rates = stateset.tax.rates.list( country='US', status='active' ) ``` ```json Response theme={null} { "object": "list", "data": [ { "id": "tax_rate_0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "tax_rate", "name": "California State Sales Tax", "code": "CA_STATE_SALES", "rate": 0.0725, "type": "sales", "jurisdiction": { "country": "US", "state": "CA", "level": "state", "display_name": "California, United States" }, "is_inclusive": false, "status": "active", "created_at": "2024-01-20T11:00:00Z" }, { "id": "tax_rate_1234f083-bb2d-54d6-bg6d-1b0e3gd75f41", "object": "tax_rate", "name": "San Francisco County Tax", "code": "SF_COUNTY_SALES", "rate": 0.0175, "type": "sales", "jurisdiction": { "country": "US", "state": "CA", "county": "San Francisco", "level": "county", "display_name": "San Francisco County, California, United States" }, "is_inclusive": false, "status": "active", "created_at": "2024-01-20T11:05:00Z" } ], "has_more": true, "total_count": 127, "url": "/v1/tax/rates" } ``` # Workflow Framework with Temporal Source: https://docs.stateset.com/api-reference/temporal Building resilient and scalable web workflows using the Temporal framework. # StateSet Workflow Framework with Temporal ## Introduction StateSet leverages the Temporal framework to build robust and scalable workflows. Temporal's open-source programming model simplifies complex application logic, enhances reliability, and accelerates feature delivery. By combining serverless API calls with a deterministic execution engine, Temporal provides the backbone for automating critical business processes. In particular, StateSet's Return Management (RMA) process is fully automated using Temporal. This includes: generating and emailing return labels, creating return records in StateSet, facilitating record retrieval, updating customer support platforms, and processing instant refunds. This automation significantly streamlines the return process, improves customer satisfaction, and allows businesses to manage returns more efficiently. ## Core Components of StateSet Workflows StateSet Workflows are built using the following components within the Temporal framework: * **Temporal Client:** The entry point for starting workflows and signaling their execution. * **Temporal Worker:** Executes the workflows and activities, polling the task queue for work. * **Temporal Workflow:** Defines the sequence of steps in the business process to be automated. * **Temporal Activities:** Represents atomic units of work that a workflow executes. ## Temporal Client: Initiating Workflows The Temporal Client is used to start workflows, and send signals. In StateSet, the Temporal client is configured with: * **Namespace:** A logical grouping of workflows. (Stateset is using the `stateset` namespace) * **Task Queue:** A queue that workers poll for workflows and activities. (Stateset is using `stateset-returns-automation`) * **Workflow Path:** The location of the Workflow definition. Here's an example of how Stateset's Return API uses the Temporal Client to initiate a return workflow. ```javascript theme={null} import { Connection, WorkflowClient } from '@temporalio/client'; import { returnApprovedWorkflow } from './workflows.js'; // Import our return workflow import { v4 as uuidv4 } from "uuid"; async function run() { // Connect to the Temporal service const connection = await Connection.connect({ address: 'https://api.stateset.com/temporal/api/namespaces/default', }); // Create a WorkflowClient instance const client = new WorkflowClient({ connection, namespace: 'stateset', }); const return_id = uuidv4(); // Execute the `returnApprovedWorkflow` const return_workflow_result = await client.execute(returnApprovedWorkflow, { taskQueue: 'stateset-returns-automation', // the task queue which the worker will monitor workflowId: 'workflow-' + return_id, // unique ID of this workflow args: [ { "cancel_subscription": true, "condition": "A", "match": true, "country": "US", "customer_email": "john.doe@example.com" }, '228476' // ticket id ], // Arguments for the workflow }); console.log(return_workflow_result); // Logs the workflow result } run().catch((err) => { console.error(err); process.exit(1); }); ``` > The code shows how we connect to the Temporal cluster and execute the `returnApprovedWorkflow` workflow by passing some initial arguments. ## Temporal Worker: Executing Workflows and Activities The Temporal Worker is responsible for executing workflows and activities. It polls the specified task queue for pending tasks and executes them. Here is an example of how a worker is set up to process return workflow: ```javascript theme={null} import { Worker } from '@temporalio/worker'; import { URL } from 'url'; import * as activities from './activities.js'; // Import our activity functions async function run() { // Create a worker instance const worker = await Worker.create({ workflowsPath: new URL('./workflows/return-ticket-approved.js', import.meta.url).pathname, // Path to our workflows activities, // Our activity functions taskQueue: 'stateset-returns-automation', // Task queue to listen on namespace: 'stateset' // The namespace that we're using }); // Start the worker await worker.run(); } run().catch((err) => { console.error(err); process.exit(1); }); ``` > This worker is configured to pick up workflow tasks on the `stateset-returns-automation` task queue and use the code in the `activities.js` file. ## Return Approved Workflow: Orchestrating the Process The `returnApprovedWorkflow` orchestrates the various steps when a return request is approved. It's triggered by the Temporal Client, and it executes the following activities: ```javascript theme={null} import { proxyActivities } from '@temporalio/workflow'; import * as wf from '@temporalio/workflow'; // Proxy Activities (configure activity timeouts) const { generateResponse, createZendeskComment, createReturnRecord, generateUSLabel, generateCALabel, updateWorkflowId, updateMatch, cancelSubscription } = proxyActivities({ startToCloseTimeout: '1 minute', }); /** A workflow that orchestrates a return process*/ export async function returnApprovedWorkflow(body, ticket_id_int) { let workflow_state = []; // Example to track workflow execution. // Extract data from the input body. var cancel_subscription = body.cancel_subscription; var condition = body.condition; var match = body.match; var country = body.country; var customer_email = body.customer_email; // 1. Generate a Customer Response await generateResponse(body); // 2. Generate a Return Label based on Country if (country == "US") { await generateUSLabel(ticket_id_int); } else { await generateCALabel(ticket_id_int); } // 3. Create a Return Record in our system var return_id = await createReturnRecord(ticket_id_int); // 4. Update the Return Record with the Temporal Workflow ID await updateWorkflowId(return_id, wf.workflowInfo().workflowId); // 5. Cancels the customer subscription if cancel_subscription is set to true if (cancel_subscription) { await cancelSubscription(customer_email, ticket_id_int); }; // 6. Wait 3 Days await wf.sleep('3 days'); // 7. Process Instant Refund based on Condition and Match if (condition == "A" && match == true) { const matched_return = await updateMatch(return_id, wf.workflowInfo().workflowId); // refundOrder is not an activity, so it runs synchronously inside of the workflow await refundOrder(return_id); // Creates a comment in zendesk for auditing purposes await createZendeskComment(ticket_id_int, condition); return 'return_and_refund_processed'; } return 'return_processed'; } ``` > This workflow defines the sequence of steps to execute when a return is approved. The workflow is composed of activities which are executed by the temporal worker. ### Activities: The Atomic Units of Work Activities encapsulate the atomic units of work that a workflow executes. Here is an example of a few of the activities that we use in the workflow above. These are the actual calls that are executed by the Temporal Worker. ```javascript theme={null} import axios from 'axios'; // Activity to Generate a Customer Response export async function generateResponse(body) { console.log("generating response"); return true; } // Activity to generate a return label in the US export async function generateUSLabel(ticket_id_int) { console.log("generating US label"); return true; } // Activity to generate a return label in Canada export async function generateCALabel(ticket_id_int) { console.log("generating CA label"); return true; } // Activity to create a record in our system export async function createReturnRecord(ticket_id_int) { console.log("creating return record"); return 'return_' + ticket_id_int; } // Activity to update the record with the workflow id export async function updateWorkflowId(return_id, workflow_id) { console.log("updating workflow id"); return true; } // Activity to update if it was a match for instant refunds export async function updateMatch(return_id, workflow_id) { console.log("updating return match"); return true; } // Activity to create a comment in Zendesk export async function createZendeskComment(ticket_id_int, condition) { console.log("creating zendesk comment"); return true; } // Activity to cancel the customer subscription export async function cancelSubscription(customer_email, ticket_id_int) { console.log("cancelling customer subscription"); return true; } ``` > These activities are functions that do the actual work for the workflow. In this case they're just logging the activity for the sake of example. In a production system, these functions would call our APIs to perform business logic ### Stateset Cloud: Hosted Temporal StateSet provides a hosted Temporal workflow service with deterministic execution and state-of-the-art infrastructure. The hosted service can be accessed at [https://cloud.stateset.com](https://cloud.stateset.com). ```mermaid theme={null} graph LR A[Temporal Client] --> B(Temporal Workflow); B --> C{Temporal Activities}; C --> D[External Services/APIs]; E[Temporal Worker] --> B; E --> C; F[StateSet Cloud] -- Temporal Cluster --> E ``` > This diagram shows the different parts of the temporal framework and how they're organized. ## Conclusion By leveraging the Temporal framework, StateSet implements complex workflow orchestration in a safe, reliable, and scalable way. The separation of concerns between workflows and activities enables StateSet to develop complex features quickly while relying on the powerful Temporal platform. # Create User Source: https://docs.stateset.com/api-reference/users/create POST https://api.stateset.com/v1/users This endpoint creates a new user ### Body This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ### Response This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/users' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "8" }' ``` ```json Response theme={null} { "id": "8" } ``` # Delete User Source: https://docs.stateset.com/api-reference/users/delete DELETE https://api.stateset.com/v1/users/:id This endpoint deletes an existing user. ### Body The ID of the user to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id: "1234", }' ``` ````graphQL GraphQL theme={null} mutation { deleteUser( input: { id: "1234" } ) { success } } ```javascript Node.js var deleted = await stateset.users.del({ id: "1234" }); ```` ```python Python theme={null} deleted = stateset.users.del({ "id": "1234" }) ``` ```ruby Ruby theme={null} deleted = Stateset::Users.del({ "id": "1234" }) ``` ```php PHP theme={null} $deleted = $stateset->users->del([ "id" => "1234" ]); ``` ```go Go theme={null} deleted, err := stateset.Users.Del( "1234" ) ``` ```java Java theme={null} Stateset.Users.del( "1234" ); ``` ```json Response theme={null} { "id": "1234", "object": "user", "deleted": true } ``` # Get User Source: https://docs.stateset.com/api-reference/users/get GET https://api.stateset.com/v1/users/:id This endpoint gets or creates a new user. ### Body This is the id of the user. ### Response This is the id of the user. This is the active of the user. This is the avatar of the user. This is the bio of the user. This is the birthday of the user. This is the country of the user. This is the email of the user. This is the firstName of the user. This is the lastName of the user. This is the last\_seen of the user. This is the last\_typed of the user. This is the location of the user. This is the organization of the user. This is the phone of the user. This is the regions of the user. This is the title of the user. This is the twitter of the user. This is the username of the user. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": 1 }' ``` ```graphQL GraphQL theme={null} query { user { id active avatar bio birthday country email firstName lastName last_seen last_typed location organization phone regions title twitter username } } ``` ```javascript Node.js theme={null} var user = await stateset.users.get({ "id" }) ``` ```python Python theme={null} user = stateset.users.get( "id" ) ``` ```ruby Ruby theme={null} user = Stateset::Users.get( "id" ) ``` ```php PHP theme={null} $user = Stateset\Users::get([ "id" => "1" ]); ``` ```go Go theme={null} user, err := stateset.Users.get( "id" ) ``` ```` ```java Java User user = stateset.users.get( "id" ); ```` ```json Response theme={null} { "id": 1, "active": true, "avatar": "", "bio": "This is the bio of the user.", "birthday": "2020-01-01", "country": "US", "email": "someone@there.com", } ``` # List Users Source: https://docs.stateset.com/api-reference/users/list GET https://api.stateset.com/v1/users/:id This endpoint gets or creates a new user. ### Body This is the limit of the users. This is the offset of the users. This is the order direction of the users. ### Response This is the id of the user. This is the active of the user. This is the avatar of the user. This is the bio of the user. This is the birthday of the user. This is the country of the user. This is the email of the user. This is the firstName of the user. This is the lastName of the user. This is the last\_seen of the user. This is the last\_typed of the user. This is the location of the user. This is the organization of the user. This is the phone of the user. This is the regions of the user. This is the title of the user. This is the twitter of the user. This is the username of the user. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL GraphQL theme={null} query { user { id active avatar bio birthday country email firstName lastName last_seen last_typed location organization phone regions title twitter username } } ``` ```javascript Node.js theme={null} var user = await stateset.users.list({ limit: 10, offset: 0, order_direction: "asc" }) ``` ```python Python theme={null} user = stateset.users.list( limit=10, offset=0, order_direction="asc" ) ``` ```ruby Ruby theme={null} user = Stateset::Users.list( limit: 10, offset: 0, order_direction: "asc" ) ``` ```php PHP theme={null} $user = Stateset\Users::list([ "limit" => 10, "offset" => 0, "order_direction" => "asc" ]); ``` ```go Go theme={null} user, err := stateset.Users.List( 10, 0, "asc" ) ``` ```java Java theme={null} User user = stateset.users.list( 10, 0, "asc" ); ``` ```json Response theme={null} { "id": 1, "active": true, "avatar": "", "bio": "This is the bio of the user.", "birthday": "2020-01-01", "country": "US", "email": "someone@there.com", } ``` ## Users | Name | Type | Description | | ------------ | -------------------------- | ------------------------------------------------ | | id | Text (Primary Key, Unique) | Unique identifier for the user | | active | Boolean | Indicates if the user is currently active | | avatar | Text | URL or path to the user's avatar image | | bio | Text | Biography or description of the user | | birthday | Date | Date of birth of the user | | country | Text | Country of residence of the user | | email | Text | Email address of the user | | firstName | Text | First name of the user | | lastName | Text | Last name of the user | | last\_seen | Date/Time | Date and time when the user was last seen | | last\_typed | Date/Time | Date and time when the user last typed a message | | location | Text | Location or address of the user | | organization | Text | Organization or company the user belongs to | | phone | Text | Phone number of the user | | regions | Text | Regions or areas associated with the user | | title | Text | Title or job position of the user | | twitter | Text | Twitter handle or username of the user | | username | Text | Unique username of the user | # Update User Source: https://docs.stateset.com/api-reference/users/update PUT https://api.stateset.com/v1/users/:id This endpoint updates an existing user. ### Body This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ### Response This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # Create Vendor Source: https://docs.stateset.com/api-reference/vendors/create POST https://api.stateset.com/v1/vendors This endpoint creates a new vendor ### Body This is the current user group token you have for the user group that you want to rotate. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The contents of the user group This is the internal ID for this user group. You don't need to record this information, since you will not need to use it. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the environment tag of the user group. Possible values are 'Customer' and 'Testing'. User group id's must be unique to each environment, so you can not create multiple user groups with with same id. If you have a production customer and a test user group with the same id, you will be required to label one as 'Customer' and another as 'Testing' ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/vendor' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Delete Vendor Source: https://docs.stateset.com/api-reference/vendors/delete DELETE https://api.return.com/v1/vendors/:id This endpoint deletes an existing vendor. ### Body The data source ID provided in the data tab may be used to identify the data source for the user group This is the current user group token you have for the user group you want to delete ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/vendors/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1" "current_token": "abcdef" }' ``` ```json Response theme={null} { "success": 1 } ``` # Get Vendor Source: https://docs.stateset.com/api-reference/vendors/get GET https://api.stateset.com/v1/vendors/:id This endpoint gets or creates a new vendor. ### Body This is the id of the vendor. ### Response This is the id of the vendor. This is the name of the vendor. This is the notes of the vendor. This is the subtype of the vendor. This is the type of the vendor. This is the owner of the vendor. This is the source of the vendor. This is the annual revenue of the vendor. This is the avatar of the vendor. This is the billing city of the vendor. This is the billing country of the vendor. This is the billing latitude of the vendor. This is the billing longitude of the vendor. This is the billing state of the vendor. This is the billing street of the vendor. This is the created at of the vendor. This is the description of the vendor. This is the employees of the vendor. This is the fax of the vendor. This is the industry of the vendor. This is the is active of the vendor. This is the is public of the vendor. This is the last modified by of the vendor. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/vendor' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "new_user_group": true, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Vendors Vendors describes the general data about the vendor in Stateset. ## The vendor object #### Attributes | Name | Type | Description | | ------------------ | --------- | ------------------------------------------------------- | | id | Text | Unique identifier for the vendor | | vendorName | Text | Name of the vendor | | vendorNotes | Text | Notes or additional information about the vendor | | vendorSubtype | Text | Subtype or specific category of the vendor | | vendorType | Text | Type or general category of the vendor | | vendor\_owner | Text | Owner or responsible person for the vendor | | vendor\_source | Text | Source or origin of the vendor | | annualRevenue | Text | Annual revenue associated with the vendor | | avatar | Text | URL or path to the vendor's avatar image | | billingCity | Text | City of the billing address | | billingCountry | Text | Country of the billing address | | billingLatitude | Text | Latitude coordinate of the billing address | | billingLongitude | Text | Longitude coordinate of the billing address | | billingState | Text | State or province of the billing address | | billingStreet | Text | Street address of the billing address | | created\_at | Date/Time | Date and time when the vendor was created | | description | Text | Description or additional details about the vendor | | employees | Text | Number or range of employees associated with the vendor | | fax | Text | Fax number of the vendor | | industry | Text | Industry or sector of the vendor | | is\_active | Boolean | Indicates whether the vendor is currently active | | is\_public | Boolean | Indicates whether the vendor is public or private | | last\_modified\_by | Text | Last person who modified the vendor | | numberOfEmployees | Text | Number of employees associated with the vendor | | ownership | Text | Ownership type or structure of the vendor | | parentVendor | Text | Parent vendor associated with the vendor | | phone | Text | Phone number of the vendor | | rating | Text | Rating or evaluation of the vendor | | shippingCity | Text | City of the shipping address | | shippingCountry | Text | Country of the shipping address | | shippingLatitude | Text | Latitude coordinate of the shipping address | | shippingLongitude | Text | Longitude coordinate of the shipping address | | shippingState | Text | State or province of the shipping address | | shippingStreet | Text | Street address of the shipping address | | stockTicker | Text | Stock ticker symbol associated with the vendor | | website | Text | Website URL of the vendor | | yearStarted | Text | Year the vendor started or established | # List Vendor Source: https://docs.stateset.com/api-reference/vendors/list GET https://api.stateset.com/v1/vendor/list This endpoint gets or creates a new vendor. ### Body This is the limit of the vendors. This is the offset of the vendors. This is the order direction of the vendors. ### Response This is the id of the vendor. This is the name of the vendor. This is the notes of the vendor. This is the subtype of the vendor. This is the type of the vendor. This is the owner of the vendor. This is the source of the vendor. This is the annual revenue of the vendor. This is the avatar of the vendor. This is the billing city of the vendor. This is the billing country of the vendor. This is the billing latitude of the vendor. This is the billing longitude of the vendor. This is the billing state of the vendor. This is the billing street of the vendor. This is the created at of the vendor. This is the description of the vendor. This is the employees of the vendor. This is the fax of the vendor. This is the industry of the vendor. This is the is active of the vendor. This is the is public of the vendor. This is the last modified by of the vendor. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/vendor' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "new_user_group": true, "user_group": { "team_id": 3, "token": "", "name": "Example 1", "provided_id": "example_1" } } ``` # Vendors Vendors describes the general data about the vendor in Stateset. ## The vendor object #### Attributes | Name | Type | Description | | ------------------ | --------- | ------------------------------------------------------- | | id | Text | Unique identifier for the vendor | | vendorName | Text | Name of the vendor | | vendorNotes | Text | Notes or additional information about the vendor | | vendorSubtype | Text | Subtype or specific category of the vendor | | vendorType | Text | Type or general category of the vendor | | vendor\_owner | Text | Owner or responsible person for the vendor | | vendor\_source | Text | Source or origin of the vendor | | annualRevenue | Text | Annual revenue associated with the vendor | | avatar | Text | URL or path to the vendor's avatar image | | billingCity | Text | City of the billing address | | billingCountry | Text | Country of the billing address | | billingLatitude | Text | Latitude coordinate of the billing address | | billingLongitude | Text | Longitude coordinate of the billing address | | billingState | Text | State or province of the billing address | | billingStreet | Text | Street address of the billing address | | created\_at | Date/Time | Date and time when the vendor was created | | description | Text | Description or additional details about the vendor | | employees | Text | Number or range of employees associated with the vendor | | fax | Text | Fax number of the vendor | | industry | Text | Industry or sector of the vendor | | is\_active | Boolean | Indicates whether the vendor is currently active | | is\_public | Boolean | Indicates whether the vendor is public or private | | last\_modified\_by | Text | Last person who modified the vendor | | numberOfEmployees | Text | Number of employees associated with the vendor | | ownership | Text | Ownership type or structure of the vendor | | parentVendor | Text | Parent vendor associated with the vendor | | phone | Text | Phone number of the vendor | | rating | Text | Rating or evaluation of the vendor | | shippingCity | Text | City of the shipping address | | shippingCountry | Text | Country of the shipping address | | shippingLatitude | Text | Latitude coordinate of the shipping address | | shippingLongitude | Text | Longitude coordinate of the shipping address | | shippingState | Text | State or province of the shipping address | | shippingStreet | Text | Street address of the shipping address | | stockTicker | Text | Stock ticker symbol associated with the vendor | | website | Text | Website URL of the vendor | | yearStarted | Text | Year the vendor started or established | # Update Vendor Source: https://docs.stateset.com/api-reference/vendors/update PUT https://api.stateset.com/v1/vendors/:id This endpoint updates an existing vendor. ### Body This is the name of the user group. This is the ID you use to identify this user group in your database. This is a JSON mapping of schema id to either the data source that this user group should be associated with or id of the datasource you provided when creating it. This is a JSON object for properties assigned to this user group. These will be accessible through variables in the dashboards and SQL editor ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The contents of the user group Indicates whether a new user group was created. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the properties object if it was provided in the request body This is the environment tag of the user group. Possible values are 'Customer' and 'Testing' ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/vendor' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # Approve Warranty Source: https://docs.stateset.com/api-reference/warranty/approve POST https://api.stateset.com/v1/warranties/:id/approve This endpoint approves a warranty. ### Body The ID provided in the data tab may be used to identify the warranty ### Response The ID provided in the data tab may be used to identify the warranty The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/approve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation warrantyApproveMutation { warrantyApprove(id: "${warrantyId}") { warranty { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.warranties.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Approve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "approved": true } ``` # Cancel Warranty Source: https://docs.stateset.com/api-reference/warranty/cancel POST https://api.stateset.com/v1/warranties/:id/cancel This endpoint cancels a warranty. ### Body The ID provided in the data tab may be used to identify the warranty ### Response The ID provided in the data tab may be used to identify the warranty The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation warrantyCancelMutation { warrantyCancel(id: "${warrantyId}") { warranty { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.warranties.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "cancelled": true } ``` # Close Warranty Source: https://docs.stateset.com/api-reference/warranty/close POST https://api.stateset.com/v1/warranties/:id/close This endpoint closes a warranty. ### Body The ID provided in the data tab may be used to identify the warranty The resolution or outcome of the warranty claim ### Response The ID provided in the data tab may be used to identify the warranty The object type The timestamp when the warranty was closed Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/close' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "resolution": "Replaced product under warranty" }' ``` ```graphQL GraphQL theme={null} mutation warrantyCloseMutation { warrantyClose(id: "${warrantyId}", resolution: "${resolution}") { warranty { id, status, closed_at } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.close({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', resolution: 'Replaced product under warranty' }); ``` ```python Python theme={null} warranties = stateset.warranties.close({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'resolution': 'Replaced product under warranty' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.close({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', resolution: 'Replaced product under warranty' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.close({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', Resolution: 'Replaced product under warranty' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.close({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', resolution: 'Replaced product under warranty' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->close([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'resolution' => 'Replaced product under warranty' ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Close(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', Resolution = 'Replaced product under warranty' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "closed": true, "closed_at": "2024-01-15T10:30:00Z", "resolution": "Replaced product under warranty" } ``` # Create Warranty Source: https://docs.stateset.com/api-reference/warranty/create POST https://api.stateset.com/v1/warranty This endpoint creates a new warranty ### Body This is the unique identifier for the warranty. This is the unique identifier for the order. This is the unique identifier for the serial number. This is the description of the warranty. This is the status of the warranty. This is the reported condition of the warranty. This is the tracking number of the warranty. This is the zendesk number of the warranty. This is the action needed of the warranty. This is the rma of the warranty. This is the country of the warranty. This is the created date of the warranty. ### Response This is the id of the warranty. Indicates whether any action is needed for the warranty. Indicates if advanced replacement is available for the warranty. The monetary amount associated with the warranty. Describes the condition of the item or situation. Date and time when the condition was recorded or observed. Country associated with the warranty entry. Date and time when the warranty entry was created. Email address of the customer associated with the warranty. Unique identifier for the customer associated with the warranty. Brief description or additional details about the warranty. Name or identifier of the person who entered the warranty. Issue or problem associated with the warranty. Indicates whether the warranty matches the specified conditions. Date and time when the order associated with the warranty was placed. Unique identifier for the order associated with the warranty. Category or reason associated with the warranty. Color of the replacement item for the warranty. Model of the replacement item for the warranty. Indicates if a replacement order has been created for the warranty. Condition as reported by the customer or user. Date and time when a specific request was made for the warranty. Return Merchandise Authorization (RMA) number for the warranty. Serial number obtained through scanning for the warranty. Unique serial number associated with the item in the warranty. ShipStation order ID associated with the warranty. Date and time when the item was shipped or dispatched. Single Sign-On (SSO) ID associated with the warranty. Current status or state of the warranty. Stripe invoice ID associated with the warranty. The amount of tax refunded for the warranty. The total amount refunded for the warranty. Tracking number associated with the shipment for the warranty. Date and time when the item was received in the warehouse. This is an array of warranty line items. The monetary amount associated with the warranty line item. Describes the condition of the replaced item. Indicates whether the shipping rate is a flat rate. Unique identifier for the warranty line item. Name or description of the warranty line item. The price of the warranty line item. Unique identifier for the warranty associated with the line item. Unique serial number associated with the warranty item. Stock Keeping Unit (SKU) of the replaced item. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/warranty' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```graphQL GraphQL theme={null} mutation InsertNewWarranty( $warranty: warranties_insert_input! ) { insert_warranties ( objects: [$warranty] ) { returning { id order_id serial_number customer_id description status tracking_number zendesk_number action_needed issue shipped_date requested_date enteredBy customerEmail rma country } } } ``` ```js Node.js theme={null} const warranty = await stateset.warranties.create({ warranty: 'W-23213322', warranty_line_items: [ {id: 'WI-232133223'}, ], }); ``` ```py Python theme={null} warranty = stateset.warranties.create({ warranty: 'W-23213322', warranty_line_items: [ {id: 'WI-232133223'}, ], }) ``` ```go Golang theme={null} warranty, err := stateset.Warranties.Create(&stateset.WarrantyParams{ Warranty: 'W-23213322', WarrantyLineItems: []*stateset.WarrantyLineItemParams{ {ID: 'WI-232133223'}, }, }) ``` ```rb Ruby theme={null} warranty = Stateset::Warranty.create({ warranty: 'W-23213322', warranty_line_items: [ {id: 'WI-232133223'}, ], }) ``` ```java Java theme={null} Warranty warranty = Warranty.create({ warranty: 'W-23213322', warranty_line_items: [ {id: 'WI-232133223'}, ], }) ``` ```php PHP theme={null} $warranty = Warranty::create([ 'warranty' => 'W-23213322', 'warranty_line_items' => [ ['id' => 'WI-232133223'], ], ]); ``` ```json Response theme={null} { "warranties": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": null, "action_needed": null, "condition": null, "customerEmail": "customer@gmail.com", "customer_id": null, "description": null, "enteredBy": null, "flat_rate_shipping": null, "order_date": null, "order_id": "524213310335630636", "reason_category": null, "reported_condition": null, "requested_date": null, "rma": "#1014-R5", "serial_number": null, "shipped_date": null, "status": "RCV", "tax_refunded": null, "total_refunded": null, "tracking_number": null, "warranty_line_items": [] }, ] } ``` # Delete Warranty Source: https://docs.stateset.com/api-reference/warranty/delete DELETE https://api.stateset.com/v1/warranty This endpoint deletes an existing warranty. ### Body The ID provided in the data tab may be used to identify the warranty ### Response The ID provided in the data tab may be used to identify the warranty The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/warranty' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "w_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteWarranty ($id: String!) { delete_warranties(where: {id: {_eq: $id}}) { affected_rows } } ``` ```javascript Node.js theme={null} const deleted = await stateset.warranty.del( 'w_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```python Python theme={null} deleted = stateset.warranty.del( 'w_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} deleted = Stateset::Warranty.del( 'w_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```php PHP theme={null} $deleted = $stateset->warranty->del( 'w_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```go Go theme={null} Warranty, err := stateset.Warranty.Delete( 'w_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Warranty warranties = stateset.warranties.del( "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" ); ``` ```json Response theme={null} { "id": "w_1NXWPnCo6bFb1KQto6C8OWvE", "object": "warranty", "deleted": true } ``` # Extend Warranty Source: https://docs.stateset.com/api-reference/warranty/extend POST https://api.stateset.com/v1/warranties/:id/extend This endpoint extends a warranty period. ### Body The ID provided in the data tab may be used to identify the warranty The number of days to extend the warranty The new expiry date for the warranty ### Response The ID provided in the data tab may be used to identify the warranty The object type The original expiry date of the warranty The new expiry date of the warranty Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/extend' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "extension_period": 365, "new_expiry_date": "2025-12-31" }' ``` ```graphQL GraphQL theme={null} mutation warrantyExtendMutation { warrantyExtend(id: "${warrantyId}", extensionPeriod: ${extensionPeriod}, newExpiryDate: "${newExpiryDate}") { warranty { id, original_expiry_date, new_expiry_date } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.extend({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', extension_period: 365, new_expiry_date: '2025-12-31' }); ``` ```python Python theme={null} warranties = stateset.warranties.extend({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'extension_period': 365, 'new_expiry_date': '2025-12-31' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.extend({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', extension_period: 365, new_expiry_date: '2025-12-31' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.extend({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', ExtensionPeriod: 365, NewExpiryDate: '2025-12-31' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.extend({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', extensionPeriod: 365, newExpiryDate: '2025-12-31' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->extend([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'extension_period' => 365, 'new_expiry_date' => '2025-12-31' ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Extend(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', ExtensionPeriod = 365, NewExpiryDate = '2025-12-31' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "extended": true, "original_expiry_date": "2024-12-31", "new_expiry_date": "2025-12-31", "extension_period": 365 } ``` # Get Warranty Source: https://docs.stateset.com/api-reference/warranty/get GET https://api.stateset.com/v1/warranty This endpoint gets or creates a new warranty. ### Body This is the id of the warranty. ### Response This is the id of the warranty. Indicates whether any action is needed for the warranty. Indicates if advanced replacement is available for the warranty. The monetary amount associated with the warranty. Describes the condition of the item or situation. Date and time when the condition was recorded or observed. Country associated with the warranty entry. Date and time when the warranty entry was created. Email address of the customer associated with the warranty. Unique identifier for the customer associated with the warranty. Brief description or additional details about the warranty. Name or identifier of the person who entered the warranty. Issue or problem associated with the warranty. Indicates whether the warranty matches the specified conditions. Date and time when the order associated with the warranty was placed. Unique identifier for the order associated with the warranty. Category or reason associated with the warranty. Color of the replacement item for the warranty. Model of the replacement item for the warranty. Indicates if a replacement order has been created for the warranty. Condition as reported by the customer or user. Date and time when a specific request was made for the warranty. Return Merchandise Authorization (RMA) number for the warranty. Serial number obtained through scanning for the warranty. Unique serial number associated with the item in the warranty. ShipStation order ID associated with the warranty. Date and time when the item was shipped or dispatched. Single Sign-On (SSO) ID associated with the warranty. Current status or state of the warranty. Stripe invoice ID associated with the warranty. The amount of tax refunded for the warranty. The total amount refunded for the warranty. Tracking number associated with the shipment for the warranty. Date and time when the item was received in the warehouse. This is an array of warranty line items. The monetary amount associated with the warranty line item. Describes the condition of the replaced item. Indicates whether the shipping rate is a flat rate. Unique identifier for the warranty line item. Name or description of the warranty line item. The price of the warranty line item. Unique identifier for the warranty associated with the line item. Unique serial number associated with the warranty item. Stock Keeping Unit (SKU) of the replaced item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/return' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} query getMyWarrantyData($last_received_id: String, $last_received_ts: String, $first_received_date: date, $id: String) { warranties(where: {id: {_eq: $id}}) { id order_id description status issue tracking_number action_needed customerEmail rma serial_number scanned_serial_number zendesk_number enteredBy order_date shipped_date requested_date condition reported_condition amount tax_refunded total_refunded created_date reason_category country advanced_replacement replacement_color stripe_invoice_id shipstation_order_id } warranty_line_items(where: {warranty_id: {_eq: $id}}) { id sku name price condition tax_refunded flat_rate_shipping warranty_id serial_number amount image_1 image_2 image_3 match } }`; ``` ```javascript Node.js theme={null} const warranties = await stateset.warranties.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.warranties.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```php PHP theme={null} $warranties = $stateset->warranties->retrieve([ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ]); ``` ```http HTTP theme={null} GET /v1/warranty HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "warranties": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": null, "action_needed": null, "condition": null, "customerEmail": "customer@gmail.com", "customer_id": null, "description": null, "enteredBy": null, "flat_rate_shipping": null, "order_date": null, "order_id": "524213310335630636", "reason_category": null, "reported_condition": null, "requested_date": null, "rma": "#1014-R5", "serial_number": null, "shipped_date": null, "status": "RCV", "tax_refunded": null, "total_refunded": null, "tracking_number": null, "warranty_line_items": [] }, ] } ``` ### Warranty | Name | Type | Description | | --------------------------- | --------- | -------------------------------------------------------------------- | | id | Integer | Unique identifier for the warranty entry | | action\_needed | Boolean | Indicates whether any action is needed for the warranty | | advanced\_replacement | Boolean | Indicates if advanced replacement is available for the warranty | | amount | Decimal | The monetary amount associated with the warranty | | condition | String | Describes the condition of the item or situation | | condition\_date | Date/Time | Date and time when the condition was recorded or observed | | country | String | Country associated with the warranty entry | | created\_date | Date/Time | Date and time when the warranty entry was created | | customerEmail | String | Email address of the customer associated with the warranty | | customer\_id | Integer | Unique identifier for the customer associated with the warranty | | description | String | Brief description or additional details about the warranty | | enteredBy | String | Name or identifier of the person who entered the warranty | | issue | String | Issue or problem associated with the warranty | | match | Boolean | Indicates whether the warranty matches the specified conditions | | order\_date | Date/Time | Date and time when the order associated with the warranty was placed | | order\_id | Integer | Unique identifier for the order associated with the warranty | | reason\_category | String | Category or reason associated with the warranty | | replacement\_color | String | Color of the replacement item for the warranty | | replacement\_order\_created | Boolean | Indicates if a replacement order has been created for the warranty | | reported\_condition | String | Condition as reported by the customer or user | | requested\_date | Date/Time | Date and time when a specific request was made for the warranty | | rma | String | Return Merchandise Authorization (RMA) number for the warranty | | scanned\_serial\_number | String | Serial number obtained through scanning for the warranty | | serial\_number | String | Unique serial number associated with the item in the warranty | | shipstation\_order\_id | String | ShipStation order ID associated with the warranty | | shipped\_date | Date/Time | Date and time when the item was shipped or dispatched | | sso\_id | String | Single Sign-On (SSO) ID associated with the warranty | | status | String | Current status or state of the warranty | | stripe\_invoice\_id | String | Stripe invoice ID associated with the warranty | | tax\_refunded | Decimal | The amount of tax refunded for the warranty | | total\_refunded | Decimal | The total amount refunded for the warranty | | tracking\_number | String | Tracking number associated with the shipment for the warranty | | warehouse\_received\_date | Date/Time | Date and time when the item was received in the warehouse | ### Warranty Line Item | Name | Type | Description | | -------------------- | ------- | ---------------------------------------------------------------- | | amount | Decimal | The monetary amount associated with the warranty line item | | condition | String | Describes the condition of the replaced item | | flat\_rate\_shipping | Boolean | Indicates whether the shipping rate is a flat rate | | id | Integer | Unique identifier for the warranty line item | | name | String | Name or description of the warranty line item | | price | Decimal | The price of the warranty line item | | warranty\_id | Integer | Unique identifier for the warranty associated with the line item | | serial\_number | String | Unique serial number associated with the warranty item | | sku | String | Stock Keeping Unit (SKU) of the replaced item | # Inspect Warranty Item Source: https://docs.stateset.com/api-reference/warranty/inspect POST https://api.stateset.com/v1/warranties/:id/inspect This endpoint records inspection details for a warranty claim. ### Body The ID provided in the data tab may be used to identify the warranty The type of inspection performed (e.g., "physical", "diagnostic", "functional") The ID of the inspector or technician Detailed notes from the inspection List of defects found during inspection URLs of images taken during inspection Whether the issue is covered under warranty ### Response The ID provided in the data tab may be used to identify the warranty The object type The unique identifier for the inspection record The status of the inspection (e.g., "completed", "pending\_review") The date when the inspection was performed Whether the warranty claim is valid based on inspection The recommended action based on inspection results Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/warranties/:id/inspect' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "inspection_type": "diagnostic", "inspector_id": "tech_456", "inspection_notes": "Device shows signs of manufacturing defect in display panel", "defects_found": ["dead_pixels", "backlight_bleeding"], "inspection_images": ["https://images.stateset.com/inspect/img1.jpg", "https://images.stateset.com/inspect/img2.jpg"], "warranty_valid": true }' ``` ```graphQL GraphQL theme={null} mutation warrantyInspectMutation { warrantyInspect( id: "${warrantyId}", inspectionType: "${inspectionType}", inspectorId: "${inspectorId}", inspectionNotes: "${inspectionNotes}", defectsFound: ${defectsFound}, inspectionImages: ${inspectionImages}, warrantyValid: ${warrantyValid} ) { warranty { id, status, inspection_id, inspection_status, warranty_valid, recommended_action } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.inspect({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', inspection_type: 'diagnostic', inspector_id: 'tech_456', inspection_notes: 'Device shows signs of manufacturing defect in display panel', defects_found: ['dead_pixels', 'backlight_bleeding'], inspection_images: ['https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg'], warranty_valid: true }); ``` ```python Python theme={null} warranties = stateset.warranties.inspect({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'inspection_type': 'diagnostic', 'inspector_id': 'tech_456', 'inspection_notes': 'Device shows signs of manufacturing defect in display panel', 'defects_found': ['dead_pixels', 'backlight_bleeding'], 'inspection_images': ['https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg'], 'warranty_valid': True }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.inspect({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', inspection_type: 'diagnostic', inspector_id: 'tech_456', inspection_notes: 'Device shows signs of manufacturing defect in display panel', defects_found: ['dead_pixels', 'backlight_bleeding'], inspection_images: ['https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg'], warranty_valid: true }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.inspect({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', InspectionType: 'diagnostic', InspectorID: 'tech_456', InspectionNotes: 'Device shows signs of manufacturing defect in display panel', DefectsFound: []string{'dead_pixels', 'backlight_bleeding'}, InspectionImages: []string{'https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg'}, WarrantyValid: true }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.inspect({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', inspectionType: 'diagnostic', inspectorId: 'tech_456', inspectionNotes: 'Device shows signs of manufacturing defect in display panel', defectsFound: ['dead_pixels', 'backlight_bleeding'], inspectionImages: ['https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg'], warrantyValid: true }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->inspect([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'inspection_type' => 'diagnostic', 'inspector_id' => 'tech_456', 'inspection_notes' => 'Device shows signs of manufacturing defect in display panel', 'defects_found' => ['dead_pixels', 'backlight_bleeding'], 'inspection_images' => ['https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg'], 'warranty_valid' => true ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Inspect(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', InspectionType = 'diagnostic', InspectorId = 'tech_456', InspectionNotes = 'Device shows signs of manufacturing defect in display panel', DefectsFound = new[] { 'dead_pixels', 'backlight_bleeding' }, InspectionImages = new[] { 'https://images.stateset.com/inspect/img1.jpg', 'https://images.stateset.com/inspect/img2.jpg' }, WarrantyValid = true }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "inspected": true, "inspection_id": "insp_abc123", "inspection_status": "completed", "inspection_date": "2024-01-15T14:30:00Z", "warranty_valid": true, "defects_found": ["dead_pixels", "backlight_bleeding"], "recommended_action": "replace", "inspector_id": "tech_456" } ``` # List Warranty Source: https://docs.stateset.com/api-reference/warranty/list GET https://api.stateset.com/v1/warranty/list This endpoint gets warranties. ### Body This is the limit of the warranties. This is the offset of the warranties. This is the order direction of the warranties. ### Response This is the id of the warranty. Indicates whether any action is needed for the warranty. Indicates if advanced replacement is available for the warranty. The monetary amount associated with the warranty. Describes the condition of the item or situation. Date and time when the condition was recorded or observed. Country associated with the warranty entry. Date and time when the warranty entry was created. Email address of the customer associated with the warranty. Unique identifier for the customer associated with the warranty. Brief description or additional details about the warranty. Name or identifier of the person who entered the warranty. Issue or problem associated with the warranty. Indicates whether the warranty matches the specified conditions. Date and time when the order associated with the warranty was placed. Unique identifier for the order associated with the warranty. Category or reason associated with the warranty. Color of the replacement item for the warranty. Model of the replacement item for the warranty. Indicates if a replacement order has been created for the warranty. Condition as reported by the customer or user. Date and time when a specific request was made for the warranty. Return Merchandise Authorization (RMA) number for the warranty. Serial number obtained through scanning for the warranty. Unique serial number associated with the item in the warranty. ShipStation order ID associated with the warranty. Date and time when the item was shipped or dispatched. Single Sign-On (SSO) ID associated with the warranty. Current status or state of the warranty. Stripe invoice ID associated with the warranty. The amount of tax refunded for the warranty. The total amount refunded for the warranty. Tracking number associated with the shipment for the warranty. Date and time when the item was received in the warehouse. This is an array of warranty line items. The monetary amount associated with the warranty line item. Describes the condition of the replaced item. Indicates whether the shipping rate is a flat rate. Unique identifier for the warranty line item. Name or description of the warranty line item. The price of the warranty line item. Unique identifier for the warranty associated with the line item. Unique serial number associated with the warranty item. Stock Keeping Unit (SKU) of the replaced item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/return' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "desc" }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { warranties(limit: $limit, offset: $offset, order_by: {created_date: $order_direction}) { id order_id description status issue tracking_number action_needed customerEmail rma serial_number scanned_serial_number zendesk_number enteredBy order_date shipped_date requested_date condition reported_condition amount tax_refunded total_refunded created_date reason_category country advanced_replacement replacement_color stripe_invoice_id shipstation_order_id } warranty_line_items(where: {warranty_id: {_eq: $id}}) { id sku name price condition tax_refunded flat_rate_shipping warranty_id serial_number amount image_1 image_2 image_3 match } }`; ``` ```javascript Node.js theme={null} const warranties = await stateset.warranties.list({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.warranties.list({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.list({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```php PHP theme={null} $warranties = $stateset->warranties->list([ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ]); ``` ```http HTTP theme={null} GET /v1/warranty HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "warranties": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": null, "action_needed": null, "condition": null, "customerEmail": "customer@gmail.com", "customer_id": null, "description": null, "enteredBy": null, "flat_rate_shipping": null, "order_date": null, "order_id": "524213310335630636", "reason_category": null, "reported_condition": null, "requested_date": null, "rma": "#1014-R5", "serial_number": null, "shipped_date": null, "status": "RCV", "tax_refunded": null, "total_refunded": null, "tracking_number": null, "warranty_line_items": [] }, ] } ``` ### Warranty | Name | Type | Description | | --------------------------- | --------- | -------------------------------------------------------------------- | | id | Integer | Unique identifier for the warranty entry | | action\_needed | Boolean | Indicates whether any action is needed for the warranty | | advanced\_replacement | Boolean | Indicates if advanced replacement is available for the warranty | | amount | Decimal | The monetary amount associated with the warranty | | condition | String | Describes the condition of the item or situation | | condition\_date | Date/Time | Date and time when the condition was recorded or observed | | country | String | Country associated with the warranty entry | | created\_date | Date/Time | Date and time when the warranty entry was created | | customerEmail | String | Email address of the customer associated with the warranty | | customer\_id | Integer | Unique identifier for the customer associated with the warranty | | description | String | Brief description or additional details about the warranty | | enteredBy | String | Name or identifier of the person who entered the warranty | | issue | String | Issue or problem associated with the warranty | | match | Boolean | Indicates whether the warranty matches the specified conditions | | order\_date | Date/Time | Date and time when the order associated with the warranty was placed | | order\_id | Integer | Unique identifier for the order associated with the warranty | | reason\_category | String | Category or reason associated with the warranty | | replacement\_color | String | Color of the replacement item for the warranty | | replacement\_order\_created | Boolean | Indicates if a replacement order has been created for the warranty | | reported\_condition | String | Condition as reported by the customer or user | | requested\_date | Date/Time | Date and time when a specific request was made for the warranty | | rma | String | Return Merchandise Authorization (RMA) number for the warranty | | scanned\_serial\_number | String | Serial number obtained through scanning for the warranty | | serial\_number | String | Unique serial number associated with the item in the warranty | | shipstation\_order\_id | String | ShipStation order ID associated with the warranty | | shipped\_date | Date/Time | Date and time when the item was shipped or dispatched | | sso\_id | String | Single Sign-On (SSO) ID associated with the warranty | | status | String | Current status or state of the warranty | | stripe\_invoice\_id | String | Stripe invoice ID associated with the warranty | | tax\_refunded | Decimal | The amount of tax refunded for the warranty | | total\_refunded | Decimal | The total amount refunded for the warranty | | tracking\_number | String | Tracking number associated with the shipment for the warranty | | warehouse\_received\_date | Date/Time | Date and time when the item was received in the warehouse | ### Warranty Line Item | Name | Type | Description | | -------------------- | ------- | ---------------------------------------------------------------- | | amount | Decimal | The monetary amount associated with the warranty line item | | condition | String | Describes the condition of the replaced item | | flat\_rate\_shipping | Boolean | Indicates whether the shipping rate is a flat rate | | id | Integer | Unique identifier for the warranty line item | | name | String | Name or description of the warranty line item | | price | Decimal | The price of the warranty line item | | warranty\_id | Integer | Unique identifier for the warranty associated with the line item | | serial\_number | String | Unique serial number associated with the warranty item | | sku | String | Stock Keeping Unit (SKU) of the replaced item | # Refund Warranty Source: https://docs.stateset.com/api-reference/warranty/refund POST https://api.stateset.com/v1/warranties/:id/refund This endpoint processes a refund for a warranty claim. ### Body The ID provided in the data tab may be used to identify the warranty The amount to refund for the warranty claim The reason for the warranty refund The method of refund (e.g., "credit\_card", "store\_credit", "check") ### Response The ID provided in the data tab may be used to identify the warranty The object type The unique identifier for the refund transaction The amount refunded The status of the refund (e.g., "pending", "completed", "failed") The date when the refund was processed Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/warranties/:id/refund' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "refund_amount": 299.99, "refund_reason": "Product defect covered under warranty", "refund_method": "credit_card" }' ``` ```graphQL GraphQL theme={null} mutation warrantyRefundMutation { warrantyRefund( id: "${warrantyId}", refundAmount: ${refundAmount}, refundReason: "${refundReason}", refundMethod: "${refundMethod}" ) { warranty { id, status, refund_id, refund_amount, refund_status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.refund({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', refund_amount: 299.99, refund_reason: 'Product defect covered under warranty', refund_method: 'credit_card' }); ``` ```python Python theme={null} warranties = stateset.warranties.refund({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'refund_amount': 299.99, 'refund_reason': 'Product defect covered under warranty', 'refund_method': 'credit_card' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.refund({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', refund_amount: 299.99, refund_reason: 'Product defect covered under warranty', refund_method: 'credit_card' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.refund({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', RefundAmount: 299.99, RefundReason: 'Product defect covered under warranty', RefundMethod: 'credit_card' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.refund({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', refundAmount: 299.99, refundReason: 'Product defect covered under warranty', refundMethod: 'credit_card' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->refund([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'refund_amount' => 299.99, 'refund_reason' => 'Product defect covered under warranty', 'refund_method' => 'credit_card' ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Refund(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', RefundAmount = 299.99, RefundReason = 'Product defect covered under warranty', RefundMethod = 'credit_card' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "refunded": true, "refund_id": "ref_abc123xyz", "refund_amount": 299.99, "refund_status": "completed", "refund_date": "2024-01-15T10:30:00Z", "refund_reason": "Product defect covered under warranty", "refund_method": "credit_card" } ``` # Reject Warranty Source: https://docs.stateset.com/api-reference/warranty/reject POST https://api.stateset.com/v1/warranties/:id/reject This endpoint rejects a warranty claim. ### Body The ID provided in the data tab may be used to identify the warranty The reason for rejecting the warranty claim ### Response The ID provided in the data tab may be used to identify the warranty The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/reject' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "reason": "Warranty period expired" }' ``` ```graphQL GraphQL theme={null} mutation warrantyRejectMutation { warrantyReject(id: "${warrantyId}", reason: "${reason}") { warranty { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.reject({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', reason: 'Warranty period expired' }); ``` ```python Python theme={null} warranties = stateset.warranties.reject({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'reason': 'Warranty period expired' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.reject({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', reason: 'Warranty period expired' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.reject({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', Reason: 'Warranty period expired' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.reject({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', reason: 'Warranty period expired' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->reject([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'reason' => 'Warranty period expired' ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Reject(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', Reason = 'Warranty period expired' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "rejected": true, "reason": "Warranty period expired" } ``` # Reopen Warranty Source: https://docs.stateset.com/api-reference/warranty/reopen POST https://api.stateset.com/v1/warranties/:id/reopen This endpoint reopens a closed warranty. ### Body The ID provided in the data tab may be used to identify the warranty ### Response The ID provided in the data tab may be used to identify the warranty The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/reopen' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation warrantyReopenMutation { warrantyReopen(id: "${warrantyId}") { warranty { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.warranties.reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Reopen({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "reopened": true } ``` # Repair Warranty Item Source: https://docs.stateset.com/api-reference/warranty/repair POST https://api.stateset.com/v1/warranties/:id/repair This endpoint initiates a repair for a warranty claim. ### Body The ID provided in the data tab may be used to identify the warranty The type of repair needed (e.g., "hardware", "software", "cosmetic") Detailed description of the repair needed Where the repair will be performed (e.g., "authorized\_service\_center", "mail\_in", "on\_site") Estimated cost of the repair (if applicable) Whether pickup service is required for the item ### Response The ID provided in the data tab may be used to identify the warranty The object type The unique identifier for the repair ticket The status of the repair (e.g., "scheduled", "in\_progress", "completed") The location where the repair will be performed The estimated completion date for the repair URL to track the repair status Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/warranties/:id/repair' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "repair_type": "hardware", "repair_description": "Screen replacement needed due to manufacturing defect", "repair_location": "authorized_service_center", "estimated_cost": 150.00, "pickup_required": true }' ``` ```graphQL GraphQL theme={null} mutation warrantyRepairMutation { warrantyRepair( id: "${warrantyId}", repairType: "${repairType}", repairDescription: "${repairDescription}", repairLocation: "${repairLocation}", estimatedCost: ${estimatedCost}, pickupRequired: ${pickupRequired} ) { warranty { id, status, repair_ticket_id, repair_status, estimated_completion } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.repair({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', repair_type: 'hardware', repair_description: 'Screen replacement needed due to manufacturing defect', repair_location: 'authorized_service_center', estimated_cost: 150.00, pickup_required: true }); ``` ```python Python theme={null} warranties = stateset.warranties.repair({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'repair_type': 'hardware', 'repair_description': 'Screen replacement needed due to manufacturing defect', 'repair_location': 'authorized_service_center', 'estimated_cost': 150.00, 'pickup_required': True }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.repair({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', repair_type: 'hardware', repair_description: 'Screen replacement needed due to manufacturing defect', repair_location: 'authorized_service_center', estimated_cost: 150.00, pickup_required: true }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.repair({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', RepairType: 'hardware', RepairDescription: 'Screen replacement needed due to manufacturing defect', RepairLocation: 'authorized_service_center', EstimatedCost: 150.00, PickupRequired: true }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.repair({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', repairType: 'hardware', repairDescription: 'Screen replacement needed due to manufacturing defect', repairLocation: 'authorized_service_center', estimatedCost: 150.00, pickupRequired: true }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->repair([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'repair_type' => 'hardware', 'repair_description' => 'Screen replacement needed due to manufacturing defect', 'repair_location' => 'authorized_service_center', 'estimated_cost' => 150.00, 'pickup_required' => true ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Repair(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', RepairType = 'hardware', RepairDescription = 'Screen replacement needed due to manufacturing defect', RepairLocation = 'authorized_service_center', EstimatedCost = 150.00, PickupRequired = true }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "repair_initiated": true, "repair_ticket_id": "rpr_ticket_789xyz", "repair_status": "scheduled", "repair_type": "hardware", "repair_location": "authorized_service_center", "estimated_completion": "2024-01-25", "repair_tracking_url": "https://repairs.stateset.com/track/rpr_ticket_789xyz", "pickup_scheduled": "2024-01-16T14:00:00Z" } ``` # Replace Warranty Item Source: https://docs.stateset.com/api-reference/warranty/replace POST https://api.stateset.com/v1/warranties/:id/replace This endpoint processes a replacement for a warranty claim. ### Body The ID provided in the data tab may be used to identify the warranty The product ID of the replacement item The reason for the replacement The shipping address for the replacement item Whether to use expedited shipping for the replacement ### Response The ID provided in the data tab may be used to identify the warranty The object type The order ID for the replacement item The product ID of the replacement item The status of the replacement (e.g., "pending", "shipped", "delivered") The tracking number for the replacement shipment The estimated delivery date for the replacement Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/warranties/:id/replace' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "replacement_product_id": "prod_xyz789", "replacement_reason": "Manufacturing defect", "shipping_address": { "line1": "123 Main St", "city": "New York", "state": "NY", "postal_code": "10001", "country": "US" }, "expedited_shipping": true }' ``` ```graphQL GraphQL theme={null} mutation warrantyReplaceMutation { warrantyReplace( id: "${warrantyId}", replacementProductId: "${replacementProductId}", replacementReason: "${replacementReason}", shippingAddress: ${shippingAddress}, expeditedShipping: ${expeditedShipping} ) { warranty { id, status, replacement_order_id, replacement_status, tracking_number } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.replace({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', replacement_product_id: 'prod_xyz789', replacement_reason: 'Manufacturing defect', shipping_address: { line1: '123 Main St', city: 'New York', state: 'NY', postal_code: '10001', country: 'US' }, expedited_shipping: true }); ``` ```python Python theme={null} warranties = stateset.warranties.replace({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'replacement_product_id': 'prod_xyz789', 'replacement_reason': 'Manufacturing defect', 'shipping_address': { 'line1': '123 Main St', 'city': 'New York', 'state': 'NY', 'postal_code': '10001', 'country': 'US' }, 'expedited_shipping': True }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.replace({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', replacement_product_id: 'prod_xyz789', replacement_reason: 'Manufacturing defect', shipping_address: { line1: '123 Main St', city: 'New York', state: 'NY', postal_code: '10001', country: 'US' }, expedited_shipping: true }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.replace({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', ReplacementProductID: 'prod_xyz789', ReplacementReason: 'Manufacturing defect', ShippingAddress: Address{ Line1: '123 Main St', City: 'New York', State: 'NY', PostalCode: '10001', Country: 'US' }, ExpeditedShipping: true }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.replace({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', replacementProductId: 'prod_xyz789', replacementReason: 'Manufacturing defect', shippingAddress: { line1: '123 Main St', city: 'New York', state: 'NY', postalCode: '10001', country: 'US' }, expeditedShipping: true }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->replace([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'replacement_product_id' => 'prod_xyz789', 'replacement_reason' => 'Manufacturing defect', 'shipping_address' => [ 'line1' => '123 Main St', 'city' => 'New York', 'state' => 'NY', 'postal_code' => '10001', 'country' => 'US' ], 'expedited_shipping' => true ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Replace(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', ReplacementProductId = 'prod_xyz789', ReplacementReason = 'Manufacturing defect', ShippingAddress = new { Line1 = '123 Main St', City = 'New York', State = 'NY', PostalCode = '10001', Country = 'US' }, ExpeditedShipping = true }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "replaced": true, "replacement_order_id": "ord_repl_123abc", "replacement_product_id": "prod_xyz789", "replacement_status": "shipped", "tracking_number": "1Z999AA10123456784", "estimated_delivery": "2024-01-18", "replacement_reason": "Manufacturing defect" } ``` # Transfer Warranty Source: https://docs.stateset.com/api-reference/warranty/transfer POST https://api.stateset.com/v1/warranties/:id/transfer This endpoint transfers a warranty to a new owner. ### Body The ID provided in the data tab may be used to identify the warranty The ID of the new owner The email address of the new owner The date of the warranty transfer ### Response The ID provided in the data tab may be used to identify the warranty The object type The ID of the previous owner The ID of the new owner The date when the warranty was transferred Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty/:id/transfer' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "new_owner_id": "usr_789xyz", "new_owner_email": "newowner@example.com", "transfer_date": "2024-01-15" }' ``` ```graphQL GraphQL theme={null} mutation warrantyTransferMutation { warrantyTransfer(id: "${warrantyId}", newOwnerId: "${newOwnerId}", newOwnerEmail: "${newOwnerEmail}", transferDate: "${transferDate}") { warranty { id, previous_owner_id, new_owner_id, transfer_date } userErrors { field message } } } `; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.transfer({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', new_owner_id: 'usr_789xyz', new_owner_email: 'newowner@example.com', transfer_date: '2024-01-15' }); ``` ```python Python theme={null} warranties = stateset.warranties.transfer({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'new_owner_id': 'usr_789xyz', 'new_owner_email': 'newowner@example.com', 'transfer_date': '2024-01-15' }) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranty.transfer({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', new_owner_id: 'usr_789xyz', new_owner_email: 'newowner@example.com', transfer_date: '2024-01-15' }) ``` ```go Go theme={null} warranties, err := stateset.Warranties.transfer({ ID: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', NewOwnerID: 'usr_789xyz', NewOwnerEmail: 'newowner@example.com', TransferDate: '2024-01-15' }) ``` ```java Java theme={null} Warranty warranties = stateset.Warranties.transfer({ id: '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', newOwnerId: 'usr_789xyz', newOwnerEmail: 'newowner@example.com', transferDate: '2024-01-15' }); ``` ```php PHP theme={null} $warranties = $stateset->warranties->transfer([ 'id' => '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'new_owner_id' => 'usr_789xyz', 'new_owner_email' => 'newowner@example.com', 'transfer_date' => '2024-01-15' ]); ``` ```csharp C# theme={null} var warranties = await stateset.Warranties.Transfer(new { Id = '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', NewOwnerId = 'usr_789xyz', NewOwnerEmail = 'newowner@example.com', TransferDate = '2024-01-15' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "warranty", "transferred": true, "previous_owner_id": "usr_123abc", "new_owner_id": "usr_789xyz", "new_owner_email": "newowner@example.com", "transfer_date": "2024-01-15" } ``` # Update Warranty Source: https://docs.stateset.com/api-reference/warranty/update PUT https://api.stateset.com/v1/warranty This endpoint updates an existing warranty. ### Body This is the id of the warranty. The warranty object ### Response This is the id of the warranty. Indicates whether any action is needed for the warranty. Indicates if advanced replacement is available for the warranty. The monetary amount associated with the warranty. Describes the condition of the item or situation. Date and time when the condition was recorded or observed. Country associated with the warranty entry. Date and time when the warranty entry was created. Email address of the customer associated with the warranty. Unique identifier for the customer associated with the warranty. Brief description or additional details about the warranty. Name or identifier of the person who entered the warranty. Issue or problem associated with the warranty. Indicates whether the warranty matches the specified conditions. Date and time when the order associated with the warranty was placed. Unique identifier for the order associated with the warranty. Category or reason associated with the warranty. Color of the replacement item for the warranty. Model of the replacement item for the warranty. Indicates if a replacement order has been created for the warranty. Condition as reported by the customer or user. Date and time when a specific request was made for the warranty. Return Merchandise Authorization (RMA) number for the warranty. Serial number obtained through scanning for the warranty. Unique serial number associated with the item in the warranty. ShipStation order ID associated with the warranty. Date and time when the item was shipped or dispatched. Single Sign-On (SSO) ID associated with the warranty. Current status or state of the warranty. Stripe invoice ID associated with the warranty. The amount of tax refunded for the warranty. The total amount refunded for the warranty. Tracking number associated with the shipment for the warranty. Date and time when the item was received in the warehouse. This is an array of warranty line items. The monetary amount associated with the warranty line item. Describes the condition of the replaced item. Indicates whether the shipping rate is a flat rate. Unique identifier for the warranty line item. Name or description of the warranty line item. The price of the warranty line item. Unique identifier for the warranty associated with the line item. Unique serial number associated with the warranty item. Stock Keeping Unit (SKU) of the replaced item. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```graphQL GraphQL theme={null} mutation UpdateWarranty( $ticket_id: String $warranty: warranties_set_input! ) { update_warranties ( where: { id : { _eq: $ticket_id }} _set: $warranty ) { returning { id order_id serial_number customer_id description status tracking_number zendesk_number action_needed issue shipped_date requested_date enteredBy customerEmail rma country } } }; ``` ```js Node.js theme={null} const warranties = await stateset.warranties.update({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.Warranty.modify( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```ruby Ruby theme={null} warranties = Stateset::Warranties.update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```go Go theme={null} warranties, err := stateset.Warranties.Update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```java Java theme={null} Warranties warranties = stateset.warranties.update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```php PHP theme={null} $warranties = $stateset->warranties->update( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```json Response theme={null} { "warranties": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "amount": null, "action_needed": null, "condition": null, "customerEmail": "customer@gmail.com", "customer_id": null, "description": null, "enteredBy": null, "flat_rate_shipping": null, "order_date": null, "order_id": "524213310335630636", "reason_category": null, "reported_condition": null, "requested_date": null, "rma": "#1014-R5", "serial_number": null, "shipped_date": null, "status": "RCV", "tax_refunded": null, "total_refunded": null, "tracking_number": null, "warranty_line_items": [] }, ] } ``` # Create Warranty Line Item Source: https://docs.stateset.com/api-reference/warrantylineitem/create POST https://api.stateset.com/v1/warranty_line_item This endpoint creates a new warranty line item. ### Body This is the id of the warranty line item. This is the sku of the warranty line item. This is the name of the warranty line item. This is the price of the warranty line item. This is the condition of the warranty line item. This is the serial number of the warranty line item. This is the amount of the warranty line item. This is the warranty id of the warranty line item. This is the created at of the warranty line item. This is the updated at of the warranty line item. ### Response This is the id of the warranty line item. This is the amount of the warranty line item. This is the condition of the warranty line item. This is the flat rate shipping of the warranty line item. This is the name of the warranty line item. This is the price of the warranty line item. This is the id of the warranty associated with the line item. This is the serial number of the warranty line item. This is the sku of the warranty line item. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/warranty_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "warranty_line_item": { "sku": "123456789", "name": "Warranty Item", "price": "100.00", "condition": "New", "serial_number": "123456789", "amount": "110.00", "warranty_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" } }' ``` ```graphQL GraphQL theme={null} mutation addWarrantyLineItem($warranty_line_item: warranty_line_items_insert_input!) { insert_warranty_line_items(objects: [$warranty_line_item]) { returning { id sku name price condition serial_number amount warranty_id } } } ``` ```js Node.js theme={null} const created = await stateset.warrantyItems.create( 'wi_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} created = stateset.warrantyItems.create( 'wi_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} created = Stateset::WarrantyItems.create( 'wi_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $created = $stateset->warrantyItems->create( 'wi_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} WarrantyItems , err := stateset.WarrantyItems.Create( 'wi_ODkRWQtx9NVsRX' ) ``` ```java Java theme={null} WarrantyItems created = stateset.warrantyItems.create( 'wi_ODkRWQtx9NVsRX' ); ``` ```cs C# theme={null} var created = stateset.WarrantyItems.Create( 'wi_ODkRWQtx9NVsRX' ); ``` ```json Response theme={null} { "data": { "warranty_line_items": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "123456789", "name": "Warranty Item", "price": "100.00", "condition": "New", "tax_refunded": false, "flat_rate_shipping": "10.00", "warranty_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "serial_number": "123456789", "amount": "110.00", "image_1": "https://www.example.com/image1.jpg", "image_2": "https://www.example.com/image2.jpg", "image_3": "https://www.example.com/image3.jpg", "match": "123456789" } ] } } ``` # Delete Warranty Line Item Source: https://docs.stateset.com/api-reference/warrantylineitem/delete DELETE https://api.stateset.com/v1/warranty_line_item This endpoint deletes an existing warranty line item. ### Body The id of the warranty line item to delete. ### Response The ID provided in the data tab may be used to identify the warranty The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/warranty_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```js Node.js theme={null} const warrantyLineItem = await stateset.warrantyItem.del({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```graphQL GraphQL theme={null} mutation deleteWarrantyLineItem ($warranty_line_item_id: uuid!) { delete_warranty_line_items(where: {id: {_eq: $warranty_line_item_id}}) { affected_rows } } ``` ```python Python theme={null} warranty_line_item = stateset.warranty_line_item.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```ruby Ruby theme={null} warranty_line_item = Stateset::WarrantyLineItem.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```php PHP theme={null} $warranty_line_item = Stateset\WarrantyLineItem::del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```go Golang theme={null} warrantyLineItem, err := stateset.WarrantyLineItem.Delete( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```java Java theme={null} WarrantyLineItem warrantyLineItem = stateset.warrantyLineItem.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```csharp C# theme={null} var warrantyLineItem = await Stateset.WarrantyLineItem.Delete( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```json Response theme={null} { "id": "wli_1NXWPnCo6bFb1KQto6C8OWvE", "object": "warranty_line_item", "deleted": true } ``` # Get Warranty Line Item Source: https://docs.stateset.com/api-reference/warrantylineitem/get GET https://api.stateset.com/v1/warranty_line_item This endpoint gets or creates a new warranty line item. ### Body This is the id of the warranty line item. ### Response This is the id of the warranty line item. This is the amount of the warranty line item. This is the condition of the warranty line item. This is the flat rate shipping of the warranty line item. This is the name of the warranty line item. This is the price of the warranty line item. This is the id of the warranty associated with the line item. This is the serial number of the warranty line item. This is the sku of the warranty line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/warranty_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", }' ``` ```graphQL GraphQL theme={null} query getMyWarrantyData($last_received_id: String, $last_received_ts: String, $first_received_date: date, $id: String) { warranty_line_items(where: {warranty_id: {_eq: $id}}) { id sku name price condition tax_refunded flat_rate_shipping warranty_id serial_number amount image_1 image_2 image_3 match } }` ``` ```javascript Node.js theme={null} const warranties = await stateset.warrantyItem.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} warranties = stateset.warrantylineitem.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} warranties = Stateset::WarrantyItem.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```php PHP theme={null} $warranties = $stateset->warrantyitem->retrieve([ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ]); ``` ```go Go theme={null} WarrantyLineItem , err := stateset.WarrantyItem.Retrieve( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```java Java theme={null} WarrantyItem[] warrantyitem = stateset.warrantyitem.retrieve({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "data": { "warranty_line_items": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "123456789", "name": "Warranty Item", "price": "100.00", "condition": "New", "tax_refunded": false, "flat_rate_shipping": "10.00", "warranty_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "serial_number": "123456789", "amount": "110.00", "image_1": "https://www.example.com/image1.jpg", "image_2": "https://www.example.com/image2.jpg", "image_3": "https://www.example.com/image3.jpg", "match": "123456789" } ] } } ``` # Update Warranty Line Item Source: https://docs.stateset.com/api-reference/warrantylineitem/update PUT https://api.stateset.com/v1/warranty_line_item This endpoint updates an existing warranty line item. ### Body This is the id of the warranty line item. This is the sku of the warranty line item. This is the name of the warranty line item. This is the price of the warranty line item. This is the condition of the warranty line item. This is the serial number of the warranty line item. This is the amount of the warranty line item. This is the warranty id of the warranty line item. This is the created at of the warranty line item. This is the updated at of the warranty line item. ### Response This is the id of the warranty line item. This is the amount of the warranty line item. This is the condition of the warranty line item. This is the flat rate shipping of the warranty line item. This is the name of the warranty line item. This is the price of the warranty line item. This is the id of the warranty associated with the line item. This is the serial number of the warranty line item. This is the sku of the warranty line item. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/warranty_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", }' ``` ```graphQL GraphQL theme={null} mutation ( $id: uuid $warranty_line_item: warranty_line_items_set_input! ) { update_warranty_line_items ( where: { id : { _eq: $id }} _set: $warranty_line_item ) { returning { id sku name price tax_refunded condition amount flat_rate_shipping } } }` ``` ```js Node.js theme={null} const updated = await stateset.warrantyItems.update( 'wi_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} updated = stateset.WarrantyItem.modify( 'wi_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} updated = stateset.warrantyItems.update( 'wi_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $updated = $stateset->warrantyItems->update( 'wi_ODkRWQtx9NVsRX' ); ``` ```go Golang theme={null} WarrantyItems , err := stateset.WarrantyItems.Update( "wi_ODkRWQtx9NVsRX", ) ``` ```csharp C# theme={null} var updated = stateset.WarrantyItems.Update( "wi_ODkRWQtx9NVsRX" ); ``` ```java Java theme={null} WarrantyItems updated = stateset.warrantyItems.update( "wi_ODkRWQtx9NVsRX" ); ``` ```json Response theme={null} { "data": { "warranty_line_items": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "sku": "123456789", "name": "Warranty Item", "price": "100.00", "condition": "New", "tax_refunded": false, "flat_rate_shipping": "10.00", "warranty_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "serial_number": "123456789", "amount": "110.00", "image_1": "https://www.example.com/image1.jpg", "image_2": "https://www.example.com/image2.jpg", "image_3": "https://www.example.com/image3.jpg", "match": "123456789" } ] } } ``` # Webhooks Source: https://docs.stateset.com/api-reference/webhooks Real-time event notifications for your StateSet integration Webhooks allow your application to receive real-time notifications when events occur in StateSet, eliminating the need for polling. ## Overview StateSet webhooks provide real-time event notifications delivered via HTTPS POST requests to your configured endpoints. Each webhook payload includes comprehensive event data and is secured with HMAC signatures. ### Key Features * 🔄 **Automatic retries** with exponential backoff * 🔐 **Secure signatures** using HMAC-SHA256 * 📊 **Event versioning** for backward compatibility * 🎯 **Granular event selection** - subscribe only to events you need * 📝 **Detailed payloads** with full resource data * 🔍 **Event replay** for missed or failed deliveries ## Setting Up Webhooks Navigate to **Dashboard → Settings → Webhooks** and click **Add Endpoint** * Enter your HTTPS endpoint URL * Select events to subscribe to * Copy the signing secret for verification Create an endpoint that: * Accepts POST requests * Verifies signatures * Processes events asynchronously * Returns 2xx status quickly Use the webhook simulator to send test events and verify your implementation ## Webhook Security ### Signature Verification All webhooks include a `Stateset-Signature` header for verification: ```javascript Node.js theme={null} const crypto = require('crypto'); const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', transports: [new winston.transports.Console()] }); class WebhookVerifier { constructor(secret) { this.secret = secret; } verify(payload, signatureHeader) { // Parse signature header // Format: "t=timestamp v1=signature1 v1=signature2" const elements = signatureHeader.split(' '); const timestamp = elements.find(e => e.startsWith('t=')).slice(2); const signatures = elements .filter(e => e.startsWith('v1=')) .map(e => e.slice(3)); // Check timestamp is recent (5 minute window) const currentTime = Math.floor(Date.now() / 1000); const timestampAge = currentTime - parseInt(timestamp); if (timestampAge > 300) { throw new Error('Webhook timestamp too old'); } if (timestampAge < -300) { throw new Error('Webhook timestamp too far in future'); } // Compute expected signature const signedPayload = `${timestamp}.${payload}`; const expectedSignature = crypto .createHmac('sha256', this.secret) .update(signedPayload) .digest('hex'); // Timing-safe comparison const valid = signatures.some(sig => crypto.timingSafeEqual( Buffer.from(sig), Buffer.from(expectedSignature) ) ); if (!valid) { throw new Error('Invalid webhook signature'); } return { timestamp: parseInt(timestamp), verified: true }; } } // Express.js implementation app.post('/webhooks/stateset', express.raw({ type: 'application/json' }), (req, res) => { const verifier = new WebhookVerifier(process.env.WEBHOOK_SECRET); try { verifier.verify( req.body.toString(), req.headers['stateset-signature'] ); const event = JSON.parse(req.body); processWebhookEvent(event); res.status(200).json({ received: true }); } catch (error) { logger.error('Webhook verification failed', { message: error.message }); res.status(401).json({ error: 'Verification failed' }); } } ); ``` ```python Python theme={null} import hmac import hashlib import time import json class WebhookVerifier: def __init__(self, secret): self.secret = secret def verify(self, payload, signature_header): # Parse signature header elements = signature_header.split(' ') timestamp = next(e[2:] for e in elements if e.startswith('t=')) signatures = [e[3:] for e in elements if e.startswith('v1=')] # Check timestamp is recent (5 minute window) current_time = int(time.time()) timestamp_age = current_time - int(timestamp) if timestamp_age > 300: raise ValueError('Webhook timestamp too old') if timestamp_age < -300: raise ValueError('Webhook timestamp too far in future') # Compute expected signature signed_payload = f"{timestamp}.{payload}" expected_signature = hmac.new( self.secret.encode(), signed_payload.encode(), hashlib.sha256 ).hexdigest() # Verify signature if expected_signature not in signatures: raise ValueError('Invalid webhook signature') return { 'timestamp': int(timestamp), 'verified': True } # Flask implementation from flask import Flask, request, jsonify app = Flask(__name__) verifier = WebhookVerifier(os.getenv('WEBHOOK_SECRET')) @app.route('/webhooks/stateset', methods=['POST']) def handle_webhook(): try: payload = request.get_data(as_text=True) signature = request.headers.get('Stateset-Signature') verifier.verify(payload, signature) event = json.loads(payload) process_webhook_event(event) return jsonify({'received': True}), 200 except Exception as e: print(f'Webhook verification failed: {e}') return jsonify({'error': 'Verification failed'}), 401 ``` ### Security Best Practices **Critical Security Requirements:** * Always verify webhook signatures * Use HTTPS endpoints only * Store signing secrets securely * Implement idempotency to handle duplicate events * Process events asynchronously to avoid timeouts ## Webhook Payload Structure All webhook events follow a consistent structure: ```json theme={null} { "id": "evt_1NXWPnCo6bFb1KQto6C8OWvE", "object": "event", "api_version": "2024-01-01", "created": 1704067200, "type": "order.created", "data": { "object": { // Full resource object }, "previous_attributes": { // For update events, previous values of changed fields } }, "request": { "id": "req_abc123", "idempotency_key": "order-123" }, "metadata": { "workspace_id": "ws_123", "user_id": "usr_456", "source": "api" } } ``` ### Payload Fields | Field | Type | Description | | -------------------------- | ------- | ----------------------------------- | | `id` | string | Unique event identifier | | `object` | string | Always "event" | | `api_version` | string | API version used for the event | | `created` | integer | Unix timestamp of event creation | | `type` | string | Event type (e.g., "order.created") | | `data.object` | object | Full resource data | | `data.previous_attributes` | object | Changed fields (update events only) | | `request.id` | string | Original request ID | | `request.idempotency_key` | string | Idempotency key if provided | | `metadata` | object | Additional context | ## Event Types ### Order Events **Triggered when:** A new order is created ```json theme={null} { "type": "order.created", "data": { "object": { "id": "ord_123", "object": "order", "status": "pending", "customer": {...}, "items": [...], "totals": {...}, "created_at": "2024-01-15T10:30:00Z" } } } ``` **Triggered when:** Order details are modified ```json theme={null} { "type": "order.updated", "data": { "object": { "id": "ord_123", "status": "processing", // Full updated order }, "previous_attributes": { "status": "pending", "updated_at": "2024-01-15T10:00:00Z" } } } ``` **Triggered when:** Order is cancelled ```json theme={null} { "type": "order.cancelled", "data": { "object": { "id": "ord_123", "status": "cancelled", "cancelled_at": "2024-01-15T11:00:00Z", "cancellation_reason": "customer_request" } } } ``` **Triggered when:** Order fulfillment is complete ```json theme={null} { "type": "order.fulfilled", "data": { "object": { "id": "ord_123", "status": "fulfilled", "fulfillment": { "tracking_number": "1Z999AA10123456784", "carrier": "ups", "shipped_at": "2024-01-15T14:00:00Z" } } } } ``` ### Return Events **Triggered when:** Return is initiated ```json theme={null} { "type": "return.created", "data": { "object": { "id": "ret_456", "order_id": "ord_123", "status": "pending", "items": [...], "reason": "defective", "rma_number": "RMA-2024-001" } } } ``` **Triggered when:** Return is approved ```json theme={null} { "type": "return.approved", "data": { "object": { "id": "ret_456", "status": "approved", "approved_at": "2024-01-16T09:00:00Z", "shipping_label": { "carrier": "fedex", "tracking_number": "123456789", "label_url": "https://..." } } } } ``` **Triggered when:** Returned items are received ```json theme={null} { "type": "return.received", "data": { "object": { "id": "ret_456", "status": "received", "received_at": "2024-01-20T10:00:00Z", "inspection": { "condition": "good", "notes": "Minor wear, acceptable for resale" } } } } ``` ### Customer Events **Triggered when:** New customer registers ```json theme={null} { "type": "customer.created", "data": { "object": { "id": "cus_789", "email": "customer@example.com", "first_name": "John", "last_name": "Doe", "created_at": "2024-01-15T08:00:00Z" } } } ``` **Triggered when:** Customer profile is updated ```json theme={null} { "type": "customer.updated", "data": { "object": { "id": "cus_789", "email": "newemail@example.com", // Full updated customer }, "previous_attributes": { "email": "oldemail@example.com", "updated_at": "2024-01-14T10:00:00Z" } } } ``` ### Inventory Events **Triggered when:** Stock falls below threshold ```json theme={null} { "type": "inventory.low_stock", "data": { "object": { "sku": "WIDGET-001", "available": 5, "threshold": 10, "warehouse_id": "wh_123" } } } ``` **Triggered when:** Item goes out of stock ```json theme={null} { "type": "inventory.out_of_stock", "data": { "object": { "sku": "WIDGET-001", "available": 0, "backorder_enabled": true, "restock_date": "2024-01-25T00:00:00Z" } } } ``` ## Handling Webhooks ### Best Practices Implementation ```javascript theme={null} const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', transports: [new winston.transports.Console()] }); class WebhookProcessor { constructor() { this.queue = new Queue('webhooks'); this.processed = new Set(); } async handle(event) { // 1. Check for duplicate processing if (this.processed.has(event.id)) { logger.info('Event already processed', { eventId: event.id }); return { status: 'duplicate' }; } // 2. Add to processing set this.processed.add(event.id); // 3. Queue for async processing await this.queue.add('process-webhook', { event, receivedAt: new Date().toISOString() }); // 4. Return quickly return { status: 'queued' }; } async process(job) { const { event } = job.data; try { // 5. Route to appropriate handler const handler = this.getHandler(event.type); if (!handler) { logger.warn('No handler for event type', { eventType: event.type }); return; } // 6. Process with retry logic await this.withRetry(() => handler(event.data.object)); // 7. Mark as completed await this.markProcessed(event.id); } catch (error) { // 8. Handle errors logger.error('Failed to process webhook', { eventId: event.id, message: error.message }); // 9. Retry or dead letter if (job.attemptsMade < 3) { throw error; // Retry } else { await this.sendToDeadLetter(event, error); } } } getHandler(eventType) { const handlers = { 'order.created': this.handleOrderCreated, 'order.updated': this.handleOrderUpdated, 'order.cancelled': this.handleOrderCancelled, 'return.created': this.handleReturnCreated, 'customer.created': this.handleCustomerCreated, 'inventory.low_stock': this.handleLowStock, // Add more handlers }; return handlers[eventType]; } async handleOrderCreated(order) { // Send confirmation email await emailService.sendOrderConfirmation(order); // Update inventory await inventoryService.allocate(order.items); // Sync with ERP await erpService.createOrder(order); // Analytics await analytics.track('order_created', { order_id: order.id, value: order.totals.total, customer_id: order.customer.id }); } async handleReturnCreated(return) { // Generate return label const label = await shippingService.createReturnLabel(return); // Email label to customer await emailService.sendReturnLabel(return, label); // Create support ticket await supportService.createTicket({ type: 'return', return_id: return.id, customer_email: return.customer_email }); } async withRetry(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (i === maxRetries - 1) throw error; await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i))); } } } } ``` ### Idempotency Ensure your webhook handler is idempotent to safely handle duplicate deliveries: ```javascript theme={null} class IdempotentWebhookHandler { constructor(redis) { this.redis = redis; } async handle(event) { const key = `webhook:${event.id}`; const lockKey = `${key}:lock`; // Try to acquire lock const acquired = await this.redis.set( lockKey, '1', 'NX', 'EX', 30 // 30 second lock ); if (!acquired) { // Another process is handling this event return { status: 'processing' }; } try { // Check if already processed const processed = await this.redis.get(key); if (processed) { return JSON.parse(processed); } // Process event const result = await this.processEvent(event); // Cache result await this.redis.setex( key, 86400, // 24 hour TTL JSON.stringify(result) ); return result; } finally { // Release lock await this.redis.del(lockKey); } } } ``` ## Retry Logic StateSet automatically retries failed webhook deliveries with exponential backoff: ### Retry Schedule | Attempt | Delay | Total Time | | ------- | ---------- | ------------ | | 1 | Immediate | 0 seconds | | 2 | 10 seconds | 10 seconds | | 3 | 1 minute | 1.2 minutes | | 4 | 5 minutes | 6.2 minutes | | 5 | 30 minutes | 36.2 minutes | | 6 | 2 hours | 2.6 hours | | 7 | 6 hours | 8.6 hours | | 8 | 24 hours | 32.6 hours | After 8 failed attempts, the webhook is marked as failed and won't be retried automatically. ### Handling Failures Your endpoint should: * Return `2xx` status for successful processing * Return `4xx` for permanent failures (won't retry) * Return `5xx` for temporary failures (will retry) ```javascript theme={null} app.post('/webhook', async (req, res) => { try { await processWebhook(req.body); res.status(200).json({ success: true }); } catch (error) { if (error.type === 'VALIDATION_ERROR') { // Permanent failure - don't retry res.status(400).json({ error: error.message }); } else { // Temporary failure - retry res.status(500).json({ error: 'Processing failed' }); } } }); ``` ## Testing Webhooks ### Webhook Simulator Test your webhook endpoint using our simulator: ```bash theme={null} curl -X POST https://api.stateset.com/v1/webhooks/simulate \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "event_type": "order.created", "endpoint_url": "https://your-app.com/webhooks", "custom_data": { "order_id": "test_123" } }' ``` ### Local Development Use ngrok or similar tools to test webhooks locally: ```bash theme={null} # Start your local server npm run dev # In another terminal, create tunnel ngrok http 3000 # Configure webhook endpoint in StateSet dashboard # https://abc123.ngrok.io/webhooks ``` ### Test Event Payloads ```json Order Created Test theme={null} { "id": "evt_test_123", "type": "order.created", "data": { "object": { "id": "ord_test_123", "status": "pending", "customer": { "email": "test@example.com" }, "items": [ { "sku": "TEST-001", "quantity": 1, "price": 1000 } ], "totals": { "subtotal": 1000, "tax": 80, "total": 1080 } } } } ``` ```json Return Created Test theme={null} { "id": "evt_test_456", "type": "return.created", "data": { "object": { "id": "ret_test_456", "order_id": "ord_test_123", "status": "pending", "items": [ { "sku": "TEST-001", "quantity": 1, "reason": "defective" } ], "rma_number": "RMA-TEST-001" } } } ``` ## Webhook Management API Programmatically manage webhooks: ```javascript theme={null} // List webhook endpoints const endpoints = await stateset.webhookEndpoints.list(); // Create webhook endpoint const endpoint = await stateset.webhookEndpoints.create({ url: 'https://your-app.com/webhooks', events: [ 'order.created', 'order.updated', 'return.created' ], description: 'Production webhook endpoint', metadata: { environment: 'production' } }); // Update webhook endpoint await stateset.webhookEndpoints.update(endpoint.id, { events: [...endpoint.events, 'customer.created'] }); // Delete webhook endpoint await stateset.webhookEndpoints.delete(endpoint.id); // Retrieve endpoint secret const secret = await stateset.webhookEndpoints.getSecret(endpoint.id); ``` ## Monitoring and Debugging ### Webhook Logs View webhook delivery attempts in the dashboard: ```javascript theme={null} // Assume a structured logger is available as `logger` // Get webhook event logs const logs = await stateset.webhookEvents.list({ endpoint_id: 'we_123', limit: 100 }); logs.data.forEach(log => { logger.info('Webhook event log', { event_id: log.event_id, status: log.status, attempts: log.attempts, last_error: log.last_error, next_retry: log.next_retry_at }); }); // Retry failed webhook await stateset.webhookEvents.retry('evt_failed_123'); ``` ### Metrics and Alerts Monitor webhook health: ```javascript theme={null} class WebhookMonitor { trackDelivery(event, success, duration) { metrics.increment('webhooks.delivered', { event_type: event.type, success: success }); metrics.histogram('webhooks.duration', duration, { event_type: event.type }); if (!success) { this.alertOnFailure(event); } } alertOnFailure(event) { if (this.getFailureRate() > 0.05) { // 5% failure rate alerts.send({ severity: 'high', message: 'High webhook failure rate detected', details: { rate: this.getFailureRate(), event_type: event.type } }); } } } ``` ## FAQ Events may arrive out of order. Use the `created` timestamp and resource state to handle this: ```javascript theme={null} if (event.created < lastProcessedTimestamp) { // This is an old event, check if it should be processed const currentResource = await stateset.orders.get(event.data.object.id); if (currentResource.updated_at > event.created) { // Skip this event, we have newer data return; } } ``` StateSet will retry failed deliveries for up to 3 days with exponential backoff. You can also: * Manually retry failed events from the dashboard * Use the Event API to fetch missed events * Implement webhook replay for recovery Yes, you can configure webhook endpoints to filter events based on metadata: ```javascript theme={null} const endpoint = await stateset.webhookEndpoints.create({ url: 'https://your-app.com/webhooks', events: ['order.created'], filters: { 'metadata.channel': 'online', 'metadata.region': 'us-west' } }); ``` Use our test signature generator: ```bash theme={null} curl https://api.stateset.com/v1/webhooks/test-signature \ -H "Authorization: Bearer sk_test_..." \ -d payload='{"test": true}' \ -d secret='whsec_test_...' ``` ## Related Resources * [Webhook Events Reference](/api-reference/events) - Complete list of events * [Security Best Practices](/api-reference/security) - Security guidelines * [API Error Handling](/api-reference/errors) - Error codes and handling * [Event Replay API](/api-reference/event-replay) - Replay missed events *** **Need help?** Contact [api-support@stateset.com](mailto:api-support@stateset.com) or visit our [Discord community](https://discord.gg/VfcaqgZywq). # Create Wholesale Order Line Item Source: https://docs.stateset.com/api-reference/wholesaleorderlineitem/create Create a wholesale order line item. # Create Wholesale Order Line Item Use this endpoint to create a wholesale order line item. # Delete Wholesale Order Line Item Source: https://docs.stateset.com/api-reference/wholesaleorderlineitem/delete Delete a wholesale order line item. # Delete Wholesale Order Line Item Use this endpoint to delete a wholesale order line item. # Get Wholesale Order Line Item Source: https://docs.stateset.com/api-reference/wholesaleorderlineitem/get Retrieve a wholesale order line item by ID. # Get Wholesale Order Line Item Use this endpoint to fetch a wholesale order line item by ID. # List Wholesale Order Line Items Source: https://docs.stateset.com/api-reference/wholesaleorderlineitem/list GET https://api.stateset.com/v1/wholesale_order_line_item/list This endpoint list wholesale order line items. ### Body This is the limit of the wholesale orders. This is the offset of the wholesale orders. This is the order direction of the wholesale orders. ### Response The Id of the wholesale order line item The Id of the product The name of the product The brand of the product The quantity of the product The unit of the product The date the wholesale order line item was last updated The Id of the wholesale order The date the wholesale order line item was created The brand of the product The price of the product Indicates whether the line item is included in the export The class of the product ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/wholesale_order_line_item/list' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` # Update Wholesale Order Line Item Source: https://docs.stateset.com/api-reference/wholesaleorderlineitem/update Update a wholesale order line item. # Update Wholesale Order Line Item Use this endpoint to update a wholesale order line item. # Create Wholesale Order Source: https://docs.stateset.com/api-reference/wholesaleorders/create POST https://api.stateset.com/v1/wholesale_orders This endpoint creates a new wholesale order ### Body The Id of the wholesale order The name of the wholesale order The order number of the wholesale order The date the wholesale order was created The date the wholesale order was last updated The financial status of the wholesale order The fulfillment status of the wholesale order The imported status of the wholesale order The delivery date of the wholesale order The delivery address of the wholesale order Location or site where the work order is applicable Memo or additional notes related to the work order The date the wholesale order was imported The customer number of the wholesale order ### Response Indicates whether the call was successful. 1 if successful, 0 if not. A message indicating the result of the call. The wholesale order object that was created. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/wholesale_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "wo_123", "name": "123", "order_number": "123", "created_date": "2021-01-01T00:00:00.000Z", "updated_date": "2021-01-01T00:00:00.000Z", "order_financial_status": "123", "order_fulfillment_status": "123", "order_imported_status": "123", "delivery_date": "2021-01-01T00:00:00.000Z", "delivery_address": "123", "location": "123", "memo": "123", "imported_date": "2021-01-01T00:00:00.000Z", "customer_number": "123" }' ``` ```json Response theme={null} { "success": 1, "message": "Wholesale Order created successfully", "data": { "id": "wo_123", "name": "123", "order_number": "123", "created_date": "2021-01-01T00:00:00.000Z", "updated_date": "2021-01-01T00:00:00.000Z", "order_financial_status": "123", "order_fulfillment_status": "123", "order_imported_status": "123", "delivery_date": "2021-01-01T00:00:00.000Z", "delivery_address": "123", "location": "123", "memo": "123", "imported_date": "2021-01-01T00:00:00.000Z", "customer_number": "123" } } ``` # Delete Wholesale Order Source: https://docs.stateset.com/api-reference/wholesaleorders/delete DELETE https://api.stateset.com/v1/wholesale_orders/:id This endpoint deletes an existing wholesale order. ### Body The id of the wholesale order to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/wholesale_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "wo_ODkRWQtx9NVsRX" }' ``` ```json Response theme={null} { "id": "wo_1NXWPnCo6bFb1KQto6C8OWvE", "object": "wholesale_order", "deleted": true } ``` # Get Wholesale Order Source: https://docs.stateset.com/api-reference/wholesaleorders/get Retrieve a wholesale order by ID. # Get Wholesale Order Use this endpoint to fetch a wholesale order by ID. # List Wholesale Orders Source: https://docs.stateset.com/api-reference/wholesaleorders/list GET https://api.stateset.com/v1/wholesale_order/list This endpoint list wholesale orders. ### Body This is the limit of the wholesale orders. This is the offset of the wholesale orders. This is the order direction of the wholesale orders. ### Response The Id of the wholesale order The name of the wholesale order The order number of the wholesale order The date the wholesale order was created The date the wholesale order was last updated The financial status of the wholesale order The fulfillment status of the wholesale order The imported status of the wholesale order The delivery date of the wholesale order The delivery address of the wholesale order Location or site where the work order is applicable Memo or additional notes related to the work order The date the wholesale order was imported The customer number of the wholesale order The email of the buyer Message from the buyer SLA time for order cancellation Reason for order cancellation Who initiated the cancellation Type of fulfillment for the order Type of delivery for the order Whether the order is Cash on Delivery Whether this is a replacement order Note from the seller Current status of the order Tracking number for the order ID of the warehouse fulfilling the order Unique identifier for the line item # Update Wholesale Order Source: https://docs.stateset.com/api-reference/wholesaleorders/update PUT https://api.stateset.com/v1/wholesale_orders This endpoint updates a wholesale order ### Body The Id of the wholesale order The name of the wholesale order The order number of the wholesale order The date the wholesale order was created The date the wholesale order was last updated The financial status of the wholesale order The fulfillment status of the wholesale order The imported status of the wholesale order The delivery date of the wholesale order The delivery address of the wholesale order Location or site where the work order is applicable Memo or additional notes related to the work order The date the wholesale order was imported The customer number of the wholesale order ### Response Indicates whether the call was successful. 1 if successful, 0 if not. A message indicating the result of the call. The wholesale order object that was created. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/wholesale_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "wo_123", "name": "123", "order_number": "123", "created_date": "2021-01-01T00:00:00.000Z", "updated_date": "2021-01-01T00:00:00.000Z", "order_financial_status": "123", "order_fulfillment_status": "123", "order_imported_status": "123", "delivery_date": "2021-01-01T00:00:00.000Z", "delivery_address": "123", "location": "123", "memo": "123", "imported_date": "2021-01-01T00:00:00.000Z", "customer_number": "123" }' ``` ```json Response theme={null} { "success": 1, "message": "Wholesale Order updated successfully", "data": { "id": "wo_123", "name": "123", "order_number": "123", "created_date": "2021-01-01T00:00:00.000Z", "updated_date": "2021-01-01T00:00:00.000Z", "order_financial_status": "123", "order_fulfillment_status": "123", "order_imported_status": "123", "delivery_date": "2021-01-01T00:00:00.000Z", "delivery_address": "123", "location": "123", "memo": "123", "imported_date": "2021-01-01T00:00:00.000Z", "customer_number": "123" } } ``` # Assign Work Order Source: https://docs.stateset.com/api-reference/workorder/assign POST https://api.stateset.com/v1/workorders/:id/assign This endpoint assigns a work order to an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/assign' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderAssignMutation { workOrderAssign(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrder = await stateset.workOrders.assign('wo_abc123'); ``` ```python Python theme={null} work_order = stateset.work_orders.assign("wo_abc123") ``` ```ruby Ruby theme={null} work_order = Stateset::WorkOrder.assign('wo_abc123') ``` ```go Go theme={null} workOrder, err := stateset.WorkOrders.Assign("wo_abc123") ``` ```java Java theme={null} WorkOrder workOrder = stateset.workOrders().assign("wo_abc123"); ``` ```php PHP theme={null} $workOrder = $stateset->workOrders->assign('wo_abc123'); ``` ```csharp C# theme={null} var workOrder = await stateset.WorkOrders.AssignAsync("wo_abc123"); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "assigned": true } ``` # Cancel Work Order Source: https://docs.stateset.com/api-reference/workorder/cancel POST https://api.stateset.com/v1/workorders/:id/cancel This endpoint cancels a work order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderCancelMutation { workOrderCancel(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrders = await stateset.workOrders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} workOrders = stateset.workOrders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} workOrders = Stateset::WorkOrder.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} workOrders, err := stateset.WorkOrders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order workOrders = stateset.WorkOrders.cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $workOrders = $stateset->workOrders->cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var workOrders = await stateset.WorkOrders.Cancel({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "cancelled": true } ``` # Complete Work Order Source: https://docs.stateset.com/api-reference/workorder/complete POST https://api.stateset.com/v1/workorders/:id/complete This endpoint completes a work order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/complete' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderCompleteMutation { workOrderComplete(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrders = await stateset.workOrders.complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} workOrders = stateset.workOrders.complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} workOrders = Stateset::WorkOrder.complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} workOrders, err := stateset.WorkOrders.complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} Order workOrders = stateset.WorkOrders.complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $workOrders = $stateset->workOrders->complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var workOrders = await stateset.WorkOrders.Complete({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "completed": true } ``` # Create Work Orders Source: https://docs.stateset.com/api-reference/workorder/create POST https://api.stateset.com/v1/work_order/create This endpoint creates work orders. ### Body This is the limit of the work orders. This is the offset of the work orders. This is the order direction of the work orders. ### Response Unique identifier for the work order (primary key) Number associated with the work order Site or location where the work order is being executed Type of the work order Location or site where the work order is applicable Part or item associated with the work order Identifier or reference to the order associated with the work order Identifier or reference to the manufacturing order associated with the work order Current status or state of the work order Name or identifier of the person who created the work order Date and time when the work order was created Date and time when the work order was last updated Date when the work order was issued Expected completion date for the work order Priority level or urgency of the work order Memo or additional notes related to the work order Number associated with the bill of materials related to the work order Actual labor hours spent on the work order Standard labor hours for the work order Identifier for related capacity utilization data Identifier for related bill of materials Identifier for related COGS (Cost of Goods Sold) data ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The contents of the user group This is the internal ID for this user group. You don't need to record this information, since you will not need to use it. This is the user group token (userGroupToken or USER\_GROUP\_TOKEN) that will be used to identify which user group is viewing the dashboard. You should save this on your end to use when rendering an embedded dashboard. This is the name of the user group provided in the request body. This is the user\_group\_id provided in the request body. This is the environment tag of the user group. Possible values are 'Customer' and 'Testing'. User group id's must be unique to each environment, so you can not create multiple user groups with with same id. If you have a production customer and a test user group with the same id, you will be required to label one as 'Customer' and another as 'Testing' ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/work_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "bill_of_materials_number": "123", "created_at": "2021-01-01T00:00:00.000Z", "created_by": "John Doe", "expected_completion_date": "2021-01-01T00:00:00.000Z", "id": "wo_123", "issue_date": "2021-01-01T00:00:00.000Z", "location": "123", "manufacture_order": "123", "memo": "123", "number": "123", "order_number": "123", "part": "123", "priority": "123", "site": "123", "status": "123", "updated_at": "2021-01-01T00:00:00.000Z", "work_order_line_items": [ { "id": "wo_123", "line_status": "123", "line_type": "123", "part_name": "123", "part_number": "123", "total_quantity": "123", "unit_quantity": "123", "work_order_number": "123" } ] }' ``` ```graphQL GraphQL theme={null} mutation addWorkOrder($work_order: work_orders_insert_input!) { insert_work_orders(objects: [$work_order]) { returning { id } } } ``` ```javascript Node.js theme={null} var workOrder = await stateset.workorder.create({ }) ``` ```python Python theme={null} workOrder = stateset.workorder.create({ }) ``` ```ruby Ruby theme={null} workOrder = Stateset::WorkOrder.create({ }) ``` ```php PHP theme={null} $workOrder = Stateset\WorkOrder::create([ ]) ``` ```go Go theme={null} workOrder := stateset.WorkOrder{ } ``` ```java Java theme={null} WorkOrder workOrder = new WorkOrder(); ``` ```json Response theme={null} { { "bill_of_materials_number": "123", "created_at": "2021-01-01T00:00:00.000Z", "created_by": "John Doe", "expected_completion_date": "2021-01-01T00:00:00.000Z", "id": "wo_123", "issue_date": "2021-01-01T00:00:00.000Z", "location": "123", "manufacture_order": "123", "memo": "123", "number": "123", "order_number": "123", "part": "123", "priority": "123", "site": "123", "status": "123", "updated_at": "2021-01-01T00:00:00.000Z", "work_order_line_items": [ { "id": "wo_123", "line_status": "123", "line_type": "123", "part_name": "123", "part_number": "123", "total_quantity": "123", "unit_quantity": "123", "work_order_number": "123" } ] } } ``` # Delete Work Order Source: https://docs.stateset.com/api-reference/workorder/delete DELETE https://api.stateset.com/v1/work_orders/:id This endpoint deletes an existing work order. ### Body The id of the bill of materials to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/work_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "wo_ODkRWQtx9NVsRX" }' ``` ```graphQL GraphQL theme={null} mutation deleteWorkOrder ($work_order_id: uuid!) { delete_work_orders(where: {id: {_eq: $work_order_id}}) { affected_rows } } ``` ```javascript Node.js theme={null} const deleted = await stateset.workorders.del( 'wo_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} deleted = stateset.workorders.del( 'wo_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} deleted = Stateset::Workorders.del( 'wo_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $deleted = $stateset->workorders->del( 'wo_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} deleted, err := stateset.Workorders.Del( 'wo_ODkRWQtx9NVsRX' ) ``` ```json Response theme={null} { "id": "wo_1NXWPnCo6bFb1KQto6C8OWvE", "object": "workorders", "deleted": true } ``` # Get Work Order Source: https://docs.stateset.com/api-reference/workorder/get GET https://api.stateset.com/v1/work_orders/:id This endpoint gets or creates a new work order. ### Body This is the id of the work order. ### Response Unique identifier for the work order (primary key) Number associated with the work order Site or location where the work order is being executed Type of the work order Location or site where the work order is applicable Part or item associated with the work order Identifier or reference to the order associated with the work order Identifier or reference to the manufacturing order associated with the work order Current status or state of the work order Name or identifier of the person who created the work order Date and time when the work order was created Date and time when the work order was last updated Date when the work order was issued Expected completion date for the work order Priority level or urgency of the work order Memo or additional notes related to the work order Number associated with the bill of materials related to the work order Actual labor hours spent on the work order Standard labor hours for the work order Identifier for related capacity utilization data Identifier for related bill of materials Identifier for related COGS (Cost of Goods Sold) data Unique identifier for the line item Status or state of the line item Type or category of the line item Name of the part or item included in the line Item Number or code associated with the part or Item Total quantity of the part or item required or used in the work order Quantity of the part or item required or used per unit in the work order Number associated with the work order to which the line item belongs ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/work_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "wo_123" }' ``` ```graphQL GraphQL theme={null} query MyWorkOrders { work_orders { bill_of_materials_number created_at created_by expected_completion_date id issue_date location manufacture_order memo number order_number part priority site status updated_at work_order_line_items { id line_status line_type part_name part_number total_quantity unit_quantity work_order_number } } } ``` ```javascript Node.js theme={null} var workOrders = await stateset.workOrders.get({ 'wo_2331232131232121' }); ``` ```python Python theme={null} workOrders = stateset.workOrders.get({ 'wo_2331232131232121' }) ``` ```ruby Ruby theme={null} workOrders = Stateset::WorkOrders.get({ 'wo_2331232131232121' }) ``` ```php PHP theme={null} $workOrders = $stateset->workOrders->get([ 'wo_2331232131232121' ]); ``` ```go Go theme={null} workOrders, err := stateset.WorkOrders.Get( []string{"wo_2331232131232121"} ) ``` ```java Java theme={null} WorkOrder[] workOrders = stateset.workOrders.get( new String[]{"wo_2331232131232121"} ); ``` ```json Response theme={null} { { "bill_of_materials_number": "123", "created_at": "2021-01-01T00:00:00.000Z", "created_by": "John Doe", "expected_completion_date": "2021-01-01T00:00:00.000Z", "id": "wo_123", "issue_date": "2021-01-01T00:00:00.000Z", "location": "123", "manufacture_order": "123", "memo": "123", "number": "123", "order_number": "123", "part": "123", "priority": "123", "site": "123", "status": "123", "updated_at": "2021-01-01T00:00:00.000Z", "work_order_line_items": [ { "id": "wo_123", "line_status": "123", "line_type": "123", "part_name": "123", "part_number": "123", "total_quantity": "123", "unit_quantity": "123", "work_order_number": "123" } ] } } ``` ## Work Order | Name | Type | Description | | --------------------------- | --------- | --------------------------------------------------------------------------------- | | bill\_of\_materials\_number | Text | Number associated with the bill of materials related to the work order | | created\_at | Date/Time | Date and time when the work order was created | | created\_by | Text | Name or identifier of the person who created the work order | | expected\_completion\_date | Date | Expected completion date for the work order | | id | Text | Unique identifier for the work order | | issue\_date | Date | Date when the work order was issued | | location | Text | Location or site where the work order is applicable | | manufacture\_order | Text | Identifier or reference to the manufacturing order associated with the work order | | memo | Text | Memo or additional notes related to the work order | | number | Text | Number associated with the work order | | order\_number | Text | Identifier or reference to the order associated with the work order | | part | Text | Part or item associated with the work order | | priority | Text | Priority level or urgency of the work order | | site | Text | Site or location where the work order is being executed | | status | Text | Current status or state of the work order | | updated\_at | Date/Time | Date and time when the work order was last updated | ## Work Order Line Items | Name | Type | Description | | ------------------- | ------- | ------------------------------------------------------------------------ | | id | Text | Unique identifier for the line item | | line\_status | Text | Status or state of the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the line item | | part\_number | Text | Number or code associated with the part or item | | total\_quantity | Numeric | Total quantity of the part or item required or used in the work order | | unit\_quantity | Numeric | Quantity of the part or item required or used per unit in the work order | | work\_order\_number | Text | Number associated with the work order to which the line item belongs | # Issue Work Order Source: https://docs.stateset.com/api-reference/workorder/issue POST https://api.stateset.com/v1/workorders/:id/issue This endpoint issues a work order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/issue' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderIssueMutation { workOrderIssue(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrders = await stateset.workOrders.issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} workOrders = stateset.workOrders.issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} workOrders = Stateset::WorkOrder.issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} workOrders, err := stateset.WorkOrders.issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} WorkOrder workOrders = stateset.WorkOrders.issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $workOrders = $stateset->workOrders->issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var workOrders = await stateset.WorkOrders.Issue({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "issued": true } ``` # List Work Orders Source: https://docs.stateset.com/api-reference/workorder/list GET https://api.stateset.com/v1/work_order/list This endpoint lists work orders. ### Body This is the limit of the work orders. This is the offset of the work orders. This is the order direction of the work orders. ### Response Unique identifier for the work order (primary key) Number associated with the work order Site or location where the work order is being executed Type of the work order Location or site where the work order is applicable Part or item associated with the work order Identifier or reference to the order associated with the work order Identifier or reference to the manufacturing order associated with the work order Current status or state of the work order Name or identifier of the person who created the work order Date and time when the work order was created Date and time when the work order was last updated Date when the work order was issued Expected completion date for the work order Priority level or urgency of the work order Memo or additional notes related to the work order Number associated with the bill of materials related to the work order Actual labor hours spent on the work order Standard labor hours for the work order Identifier for related capacity utilization data Identifier for related bill of materials Identifier for related COGS (Cost of Goods Sold) data Unique identifier for the line item Status or state of the line item Type or category of the line item Name of the part or item included in the line Item Number or code associated with the part or Item Total quantity of the part or item required or used in the work order Quantity of the part or item required or used per unit in the work order Number associated with the work order to which the line item belongs ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/work_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL GraphQL theme={null} query ($limit: Int!, $offset: Int!, $order_direction: order_by) { work_orders(limit: $limit, offset: $offset, order_by: {createdDate: $order_direction}) { bill_of_materials_number created_at created_by expected_completion_date id issue_date location manufacture_order memo number order_number part priority site status updated_at work_order_line_items { id line_status line_type part_name part_number total_quantity unit_quantity work_order_number } } } ``` ```javascript Node.js theme={null} var workOrders = await stateset.workOrders.list({ 'wo_2331232131232121' }); ``` ```python Python theme={null} workOrders = stateset.workOrders.list({ 'wo_2331232131232121' }) ``` ```ruby Ruby theme={null} workOrders = Stateset::WorkOrders.list({ 'wo_2331232131232121' }) ``` ```php PHP theme={null} $workOrders = $stateset->workOrders->list([ 'wo_2331232131232121' ]); ``` ```go Go theme={null} workOrders, err := stateset.WorkOrders.list( []string{"wo_2331232131232121"} ) ``` ```java Java theme={null} WorkOrder[] workOrders = stateset.workOrders.list( new String[]{"wo_2331232131232121"} ); ``` ```json Response theme={null} { { "bill_of_materials_number": "123", "created_at": "2021-01-01T00:00:00.000Z", "created_by": "John Doe", "expected_completion_date": "2021-01-01T00:00:00.000Z", "id": "wo_123", "issue_date": "2021-01-01T00:00:00.000Z", "location": "123", "manufacture_order": "123", "memo": "123", "number": "123", "order_number": "123", "part": "123", "priority": "123", "site": "123", "status": "123", "updated_at": "2021-01-01T00:00:00.000Z", "work_order_line_items": [ { "id": "wo_123", "line_status": "123", "line_type": "123", "part_name": "123", "part_number": "123", "total_quantity": "123", "unit_quantity": "123", "work_order_number": "123" } ] } } ``` ## Work Order | Name | Type | Description | | --------------------------- | --------- | --------------------------------------------------------------------------------- | | bill\_of\_materials\_number | Text | Number associated with the bill of materials related to the work order | | created\_at | Date/Time | Date and time when the work order was created | | created\_by | Text | Name or identifier of the person who created the work order | | expected\_completion\_date | Date | Expected completion date for the work order | | id | Text | Unique identifier for the work order | | issue\_date | Date | Date when the work order was issued | | location | Text | Location or site where the work order is applicable | | manufacture\_order | Text | Identifier or reference to the manufacturing order associated with the work order | | memo | Text | Memo or additional notes related to the work order | | number | Text | Number associated with the work order | | order\_number | Text | Identifier or reference to the order associated with the work order | | part | Text | Part or item associated with the work order | | priority | Text | Priority level or urgency of the work order | | site | Text | Site or location where the work order is being executed | | status | Text | Current status or state of the work order | | updated\_at | Date/Time | Date and time when the work order was last updated | ## Work Order Line Items | Name | Type | Description | | ------------------- | ------- | ------------------------------------------------------------------------ | | id | Text | Unique identifier for the line item | | line\_status | Text | Status or state of the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the line item | | part\_number | Text | Number or code associated with the part or item | | total\_quantity | Numeric | Total quantity of the part or item required or used in the work order | | unit\_quantity | Numeric | Quantity of the part or item required or used per unit in the work order | | work\_order\_number | Text | Number associated with the work order to which the line item belongs | # Pick Work Order Source: https://docs.stateset.com/api-reference/workorder/pick POST https://api.stateset.com/v1/workorders/:id/pick This endpoint picks a work order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/pick' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderPickMutation { workOrderPick(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrder = await stateset.workOrders.pick('wo_abc123'); ``` ```python Python theme={null} work_order = stateset.work_orders.pick("wo_abc123") ``` ```ruby Ruby theme={null} work_order = Stateset::WorkOrder.pick('wo_abc123') ``` ```go Go theme={null} workOrder, err := stateset.WorkOrders.Pick("wo_abc123") ``` ```java Java theme={null} WorkOrder workOrder = stateset.workOrders().pick("wo_abc123"); ``` ```php PHP theme={null} $workOrder = $stateset->workOrders->pick('wo_abc123'); ``` ```csharp C# theme={null} var workOrder = await stateset.WorkOrders.PickAsync("wo_abc123"); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "picked": true } ``` # Unassign Work Order Source: https://docs.stateset.com/api-reference/workorder/unassign POST https://api.stateset.com/v1/workorders/:id/unassign This endpoint unassigns a work order from an order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/unassign' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderUnassignMutation { workOrderUnassign(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrder = await stateset.workOrders.unassign('wo_abc123'); ``` ```python Python theme={null} work_order = stateset.work_orders.unassign("wo_abc123") ``` ```ruby Ruby theme={null} work_order = Stateset::WorkOrder.unassign('wo_abc123') ``` ```go Go theme={null} workOrder, err := stateset.WorkOrders.Unassign("wo_abc123") ``` ```java Java theme={null} WorkOrder workOrder = stateset.workOrders().unassign("wo_abc123"); ``` ```php PHP theme={null} $workOrder = $stateset->workOrders->unassign('wo_abc123'); ``` ```csharp C# theme={null} var workOrder = await stateset.WorkOrders.UnassignAsync("wo_abc123"); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "unassigned": true } ``` # Update Work Order Source: https://docs.stateset.com/api-reference/workorder/update PUT https://api.stateset.com/v1/work_orders/:id This endpoint updates an existing work order. ### Body This is the id of the work order you want to update. ### Response Number associated with the bill of materials related to the work order Date and time when the work order was created Name or identifier of the person who created the work order Expected completion date for the work order Unique identifier for the work order Date when the work order was issued Location or site where the work order is applicable Identifier or reference to the manufacturing order associated with the work order Memo or additional notes related to the work order Number associated with the work order Identifier or reference to the order associated with the work order Part or item associated with the work order Priority level or urgency of the work order Site or location where the work order is being executed Current status or state of the work order Date and time when the work order was last updated ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/work_order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "wo_ODkRWQtx9NVsRX", "work_order": { "bill_of_materials_number": "123", "created_at": "2021-01-01T00:00:00.000Z", "created_by": "John Doe", "expected_completion_date": "2021-01-01T00:00:00.000Z", "id": "wo_123", "issue_date": "2021-01-01T00:00:00.000Z", "location": "123", "manufacture_order": "123", "memo": "123", "number": "123", "order_number": "123", "part": "123", "priority": "123", "site": "123", "status": "123", "updated_at": "2021-01-01T00:00:00.000Z", "work_order_line_items": [ { "id": "wo_123", "line_status": "123", "line_type": "123", "part_name": "123", "part_number": "123", "total_quantity": "123", "unit_quantity": "123", "work_order_number": "123" } ] } }' ``` ```graphQL GraphQL theme={null} mutation ( $id: String $work_order: work_orders_set_input! ) { update_work_orders ( where: { id: { _eq: $id } } _set: $work_order ) { returning { id } } } ``` ```javascript Node.js theme={null} const updated = await stateset.workorders.update( 'wo_ODkRWQtx9NVsRX' ); ``` ```python Python theme={null} updated = stateset.workorders.modify( 'wo_ODkRWQtx9NVsRX' ) ``` ```ruby Ruby theme={null} updated = Stateset::Workorders.update( 'wo_ODkRWQtx9NVsRX' ) ``` ```php PHP theme={null} $updated = $stateset->workorders->update( 'wo_ODkRWQtx9NVsRX' ); ``` ```go Go theme={null} WorkOrder, err := stateset.WorkOrders.Update( "wo_ODkRWQtx9NVsRX" ) ``` ```java Java theme={null} WorkOrder workOrder = stateset.workOrders.update( "wo_ODkRWQtx9NVsRX" ); ``` ```json Response theme={null} { { "bill_of_materials_number": "123", "created_at": "2021-01-01T00:00:00.000Z", "created_by": "John Doe", "expected_completion_date": "2021-01-01T00:00:00.000Z", "id": "wo_123", "issue_date": "2021-01-01T00:00:00.000Z", "location": "123", "manufacture_order": "123", "memo": "123", "number": "123", "order_number": "123", "part": "123", "priority": "123", "site": "123", "status": "123", "updated_at": "2021-01-01T00:00:00.000Z", "work_order_line_items": [ { "id": "wo_123", "line_status": "123", "line_type": "123", "part_name": "123", "part_number": "123", "total_quantity": "123", "unit_quantity": "123", "work_order_number": "123" } ] } } ``` # Yield Work Order Source: https://docs.stateset.com/api-reference/workorder/yield POST https://api.stateset.com/v1/workorders/:id/yield This endpoint yields a work order. ### Body The ID provided in the data tab may be used to identify the order ### Response The ID provided in the data tab may be used to identify the order The object type Indicates whether the call was successful. true if successful, false if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/workorder/:id/yield' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }' ``` ```graphQL GraphQL theme={null} mutation workOrderYieldMutation { workOrderYield(id: "${workOrderId}") { workOrder { id, status } userErrors { field message } } } `; ``` ```js Node.js theme={null} const workOrders = await stateset.workOrders.yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} workOrders = stateset.workOrders.yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} workOrders = Stateset::WorkOrder.yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```go Go theme={null} workOrders, err := stateset.WorkOrders.yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```java Java theme={null} WorkOrder workOrders = stateset.WorkOrders.yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```php PHP theme={null} $workOrders = $stateset->workOrders->yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```csharp C# theme={null} var workOrders = await stateset.WorkOrders.Yield({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```json Response theme={null} { "id": "e0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "object": "workOrder", "yielded": true } ``` # Create Work Order Line Item Source: https://docs.stateset.com/api-reference/workorderlineitem/create POST https://api.stateset.com/v1/work_order_line_items This endpoint creates a new work order line item. ### Body This is the unique identifier of the work order line item. This is the status or state of the work order line item. This is the type or category of the work order line item. This is the name of the part or item included in the work order line item. This is the number or code associated with the part or item included in the work order line item. This is the total quantity of the part or item required or used in the work order line item. This is the quantity of the part or item required or used per unit in the work order line item. This is the number associated with the work order to which the line item belongs. ### Response This is the unique identifier of the work order line item. This is the status or state of the work order line item. This is the type or category of the work order line item. This is the name of the part or item included in the work order line item. This is the number or code associated with the part or item included in the work order line item. This is the total quantity of the part or item required or used in the work order line item. This is the quantity of the part or item required or used per unit in the work order line item. This is the number associated with the work order to which the line item belongs. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/work_order_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "current_token": "" }' ``` ```graphQL GraphQL theme={null} mutation addWorkOrderLineItem($work_order_line_item: work_order_line_items_insert_input!) { insert_work_order_line_items(objects: [$work_order_line_item]) { returning { id line_status line_type part_name part_number total_quantity unit_quantity work_order_number } } } ``` ```js Node.js theme={null} const workOrderLineItem = await stateset.workOrderItem.create({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```python Python theme={null} work_order_line_item = stateset.work_order_line_item.create( { "work_order_line_item": { } } ) ``` ```ruby Ruby theme={null} work_order_line_item = Stateset::WorkOrderItem.create( { "work_order_line_item": { } } ) ``` ```php PHP theme={null} $work_order_line_item = $stateset->work_order_line_item->create( [ "work_order_line_item" => [ ] ] ); ``` ```go Golang theme={null} WorkOrderLineItem , err := stateset.WorkOrderLineItem.Create( ) ``` ```java Java theme={null} WorkOrderLineItem workOrderLineItem = stateset.workOrderLineItem.create( ); ``` ```csharp C# theme={null} var workOrderLineItem = stateset.WorkOrderLineItem.Create( ); ``` ```json Response theme={null} { { "data": { "insert_work_order_line_items": { "returning": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "line_status": "In Progress", "line_type": "Part", "part_name": "Part 1", "part_number": "123456", "total_quantity": 10, "unit_quantity": 1, "work_order_number": "WO-0001" } ] } } } } ``` ## Work Order Line Items | Name | Type | Description | | ------------------- | ------- | ------------------------------------------------------------------------ | | id | Text | Unique identifier for the line item | | line\_status | Text | Status or state of the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the line item | | part\_number | Text | Number or code associated with the part or item | | total\_quantity | Numeric | Total quantity of the part or item required or used in the work order | | unit\_quantity | Numeric | Quantity of the part or item required or used per unit in the work order | | work\_order\_number | Text | Number associated with the work order to which the line item belongs | # Delete Work Order Line Item Source: https://docs.stateset.com/api-reference/workorderlineitem/delete DELETE https://api.return.com/v1/work_order_line_items/:id This endpoint deletes an existing work order line item. ### Body The ID of the work order line item you want to delete ### Response The ID provided in the data tab may be used to identify the work order The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/work_order_line_items' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "example_1" }' ``` ```js Node.js theme={null} const workOrderLineItem = await stateset.workOrderItem.del({ '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }); ``` ```graphQL GraphQL theme={null} mutation deleteWorkOrderLineItem ($work_order_line_item_id: uuid!) { delete_work_order_line_items(where: {id: {_eq: $work_order_line_item_id}}) { affected_rows } } ``` ```python Python theme={null} work_order_line_item = stateset.work_order_line_item.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```ruby Ruby theme={null} work_order_line_item = Stateset::WorkOrderLineItem.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```php PHP theme={null} $work_order_line_item = Stateset\WorkOrderItem::del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```go Golang theme={null} workOrderLineItem, err := stateset.ReturnLineItem.Delete( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ) ``` ```java Java theme={null} WorkOrderLineItem workOrderLineItem = stateset.workOrderLineItem.del( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```csharp C# theme={null} var workOrderLineItem = await Stateset.WorkOrderLineItem.Delete( '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' ); ``` ```json Response theme={null} { "id": "rli_1NXWPnCo6bFb1KQto6C8OWvE", "object": "return_line_item", "deleted": true } ``` # Get Work Order Line Item Source: https://docs.stateset.com/api-reference/workorderlineitem/get GET https://api.stateset.com/v1/work_order_line_items:/id This endpoint gets or creates a new work order line item. ### Body This is the id of the work order line item. This is the status of the work order line item. This is the type of the work order line item. This is the name of the part of the work order line item. This is the number of the part of the work order line item. This is the total quantity of the part of the work order line item. This is the unit quantity of the part of the work order line item. This is the work order number of the work order line item. ### Response This is the id of the work order line item. This is the status of the work order line item. This is the type of the work order line item. This is the name of the part of the work order line item. This is the number of the part of the work order line item. This is the total quantity of the part of the work order line item. This is the unit quantity of the part of the work order line item. This is the work order number of the work order line item. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/work_order_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "example_1", }' ``` ```json Response theme={null} { { "id": "example_1", "line_status": "example_1", "line_type": "example_1", "part_name": "example_1", "part_number": "example_1", "total_quantity": "example_1", "unit_quantity": "example_1", "work_order_number": "example_1" } } ``` ## Work Order Line Items | Name | Type | Description | | ------------------- | ------- | ------------------------------------------------------------------------ | | id | Text | Unique identifier for the line item | | line\_status | Text | Status or state of the line item | | line\_type | Text | Type or category of the line item | | part\_name | Text | Name of the part or item included in the line item | | part\_number | Text | Number or code associated with the part or item | | total\_quantity | Numeric | Total quantity of the part or item required or used in the work order | | unit\_quantity | Numeric | Quantity of the part or item required or used per unit in the work order | | work\_order\_number | Text | Number associated with the work order to which the line item belongs | # Update Work Order Line Item Source: https://docs.stateset.com/api-reference/workorderlineitem/update PUT https://api.stateset.com/v1/work_order_line_items:/id This endpoint updates an existing work order line item. ### Body This is the id of the work order line item. ### Response This is the unique identifier of the work order line item. This is the status or state of the work order line item. This is the type or category of the work order line item. This is the name of the part or item included in the work order line item. This is the number or code associated with the part or item included in the work order line item. This is the total quantity of the part or item required or used in the work order line item. This is the quantity of the part or item required or used per unit in the work order line item. This is the number associated with the work order to which the line item belongs. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/work_order_line_item' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "", }' ``` ```graphQL GraphQL theme={null} mutation ( $id: uuid $work_order_line_item: work_order_line_items_set_input! ) { update_work_order_line_items ( where: { id : { _eq: $id }} _set: $work_order_line_item ) { returning { id } } } ``` ```javascript Node.js theme={null} cont workOrderLineItem = await stateset.workOrderItem.update({ 'wo_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```python Python theme={null} workOrderLineItem = stateset.workOrderItem.update( 'wo_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} workOrderLineItem = Stateset::WorkOrderItem.update( 'wo_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```php PHP theme={null} $workOrderLineItem = $stateset->workOrderItem->update( 'wo_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```go Golang theme={null} workOrderLineItem, err := stateset.WorkOrderItem.Update( 'wo_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} WorkOrderLineItem workOrderLineItem = stateset.workOrderItem.update( 'wo_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```json Response theme={null} { "success": 1, } ``` # Autonomous Agent Architecture Source: https://docs.stateset.com/autonomous-agent-architecture Technical architecture for self-governing agents with native USDC wallets and cross-web capabilities # Autonomous Agent Architecture: Self-Governing Digital Entities StateSet's Autonomous Agent Architecture enables the creation of fully self-governing digital entities that can own assets, execute transactions, make decisions, and interact with the broader digital economy through native USDC wallets and the MCP protocol. ## 🧠 Agent Core Architecture ### Agent Runtime System ```mermaid theme={null} graph TB subgraph "Agent Runtime Layer" ARL1[Agent Process Manager] ARL2[Memory Management] ARL3[Execution Scheduler] ARL4[Resource Allocator] end subgraph "Cognitive Layer" CL1[Decision Engine] CL2[Learning System] CL3[Goal Planning] CL4[Context Manager] end subgraph "Financial Layer" FL1[USDC Wallet] FL2[Transaction Manager] FL3[Treasury Optimizer] FL4[Risk Monitor] end subgraph "Communication Layer" COM1[MCP Gateway] COM2[Agent Messaging] COM3[Event Publisher] COM4[Protocol Adapters] end subgraph "Security Layer" SL1[Identity Manager] SL2[Permission Engine] SL3[Audit Logger] SL4[Threat Detector] end ARL1 --> CL1 ARL2 --> CL2 ARL3 --> CL3 ARL4 --> CL4 CL1 --> FL1 CL2 --> FL2 CL3 --> FL3 CL4 --> FL4 FL1 --> COM1 FL2 --> COM2 FL3 --> COM3 FL4 --> COM4 COM1 --> SL1 COM2 --> SL2 COM3 --> SL3 COM4 --> SL4 ``` ### Agent State Machine ```rust theme={null} // Core agent state management #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AgentState { // Identity and configuration pub id: AgentId, pub did: String, pub agent_type: AgentType, pub capabilities: Vec, // Financial state pub wallet: WalletState, pub treasury: TreasuryState, pub spending_history: Vec, // Operational state pub tasks: VecDeque, pub goals: Vec, pub memory: AgentMemory, pub context: ExecutionContext, // Network state pub connections: HashMap, pub reputation: ReputationScore, pub performance_metrics: PerformanceMetrics, // Security state pub permissions: PermissionSet, pub audit_trail: Vec, pub risk_assessment: RiskAssessment, } impl AgentState { pub fn new(config: AgentConfig) -> Self { Self { id: AgentId::generate(), did: format!("did:stateset:agent:{}", Uuid::new_v4()), agent_type: config.agent_type, capabilities: config.capabilities, wallet: WalletState::new(config.initial_balance), treasury: TreasuryState::new(), spending_history: Vec::new(), tasks: VecDeque::new(), goals: config.initial_goals, memory: AgentMemory::new(), context: ExecutionContext::default(), connections: HashMap::new(), reputation: ReputationScore::new(), performance_metrics: PerformanceMetrics::new(), permissions: config.permissions, audit_trail: Vec::new(), risk_assessment: RiskAssessment::new(), } } pub async fn execute_cycle(&mut self) -> Result { // 1. Perception: Gather information let perception = self.perceive_environment().await?; // 2. Cognition: Process and decide let decisions = self.make_decisions(perception).await?; // 3. Action: Execute decisions let actions = self.execute_actions(decisions).await?; // 4. Learning: Update state based on results self.learn_from_results(actions).await?; Ok(ExecutionResult { actions }) } } ``` ### Cognitive Architecture ```rust theme={null} // Agent decision-making system pub struct CognitiveEngine { reasoning_engine: ReasoningEngine, learning_system: LearningSystem, goal_planner: GoalPlanner, memory_manager: MemoryManager, } impl CognitiveEngine { pub async fn make_decision( &self, context: &ExecutionContext, goals: &[Goal], constraints: &[Constraint], ) -> Result { // Multi-step reasoning process let options = self.generate_options(context, goals).await?; let filtered_options = self.apply_constraints(options, constraints)?; let evaluated_options = self.evaluate_options(filtered_options).await?; let best_option = self.select_best_option(evaluated_options)?; // Create decision with rationale Ok(Decision { action: best_option.action, confidence: best_option.confidence, rationale: best_option.reasoning, risk_assessment: best_option.risks, expected_outcome: best_option.expected_outcome, }) } async fn generate_options( &self, context: &ExecutionContext, goals: &[Goal], ) -> Result> { let mut options = Vec::new(); // Generate options for each goal for goal in goals { let goal_options = match goal.goal_type { GoalType::Financial => self.generate_financial_options(context, goal).await?, GoalType::Operational => self.generate_operational_options(context, goal).await?, GoalType::Strategic => self.generate_strategic_options(context, goal).await?, }; options.extend(goal_options); } Ok(options) } } ``` ## 💰 Native USDC Wallet System ### Wallet Architecture ```rust theme={null} // Native USDC wallet for autonomous agents pub struct AgentWallet { address: String, private_key: SecretKey, balance: Balance, transaction_history: Vec, spending_limits: SpendingLimits, multi_sig_config: Option, treasury_strategy: TreasuryStrategy, } impl AgentWallet { pub async fn new(config: WalletConfig) -> Result { let (private_key, public_key) = generate_keypair(); let address = derive_address(&public_key); Ok(Self { address, private_key, balance: Balance::new(), transaction_history: Vec::new(), spending_limits: config.spending_limits, multi_sig_config: config.multi_sig, treasury_strategy: config.treasury_strategy, }) } pub async fn execute_payment( &mut self, recipient: &str, amount: &str, memo: Option, ) -> Result { // Pre-transaction validation self.validate_payment(recipient, amount).await?; // Check spending limits self.check_spending_limits(amount)?; // Execute transaction on StateSet network let tx = Transaction { from: self.address.clone(), to: recipient.to_string(), amount: amount.parse()?, memo, timestamp: Utc::now(), }; let signed_tx = self.sign_transaction(&tx)?; let result = self.broadcast_transaction(signed_tx).await?; // Update local state self.balance.subtract(amount.parse()?)?; self.transaction_history.push(tx); Ok(result) } pub async fn optimize_treasury(&mut self) -> Result { match &self.treasury_strategy { TreasuryStrategy::Conservative => self.conservative_optimization().await, TreasuryStrategy::Balanced => self.balanced_optimization().await, TreasuryStrategy::Aggressive => self.aggressive_optimization().await, } } async fn balanced_optimization(&mut self) -> Result { let current_balance = self.balance.usdc.clone(); let target_allocation = self.calculate_target_allocation(¤t_balance).await?; let mut actions = Vec::new(); // Staking allocation (40% of idle funds) if target_allocation.staking > 0 { actions.push(TreasuryAction::Stake { amount: target_allocation.staking, validator: self.select_validator().await?, duration: Duration::days(30), }); } // Liquidity provision (30% of idle funds) if target_allocation.liquidity > 0 { actions.push(TreasuryAction::ProvideLiquidity { pool: "USDC/STATE".to_string(), amount: target_allocation.liquidity, min_apr: 0.05, // 5% minimum APR }); } // Keep 30% liquid for operations // Execute treasury actions for action in &actions { self.execute_treasury_action(action).await?; } Ok(OptimizationResult { actions }) } } ``` ### Multi-Signature Agent Wallets ```rust theme={null} // Multi-signature wallet for high-value agent operations pub struct MultiSigAgentWallet { threshold: u8, signers: Vec, pending_transactions: HashMap, execution_policy: ExecutionPolicy, } impl MultiSigAgentWallet { pub async fn propose_transaction( &mut self, transaction: Transaction, proposer: AgentId, ) -> Result { let proposal_id = Uuid::new_v4().to_string(); // Create pending transaction let pending = PendingTransaction { id: proposal_id.clone(), transaction, proposer, signatures: Vec::new(), created_at: Utc::now(), expires_at: Utc::now() + Duration::hours(24), }; self.pending_transactions.insert(proposal_id.clone(), pending); // Notify other signers for signer in &self.signers { self.notify_signer(signer, &proposal_id).await?; } Ok(proposal_id) } pub async fn sign_transaction( &mut self, proposal_id: &str, signer: AgentId, signature: Signature, ) -> Result { let pending = self.pending_transactions .get_mut(proposal_id) .ok_or(Error::ProposalNotFound)?; // Verify signature self.verify_signature(&pending.transaction, &signature, &signer)?; // Add signature pending.signatures.push(AgentSignature { signer, signature, signed_at: Utc::now(), }); // Check if threshold reached if pending.signatures.len() >= self.threshold as usize { let result = self.execute_transaction(pending).await?; self.pending_transactions.remove(proposal_id); Ok(SignatureResult::Executed(result)) } else { Ok(SignatureResult::SignatureAdded) } } } ``` ## 🌐 MCP Protocol Integration ### MCP Gateway Architecture ```rust theme={null} // Model Context Protocol gateway for cross-web interactions pub struct MCPGateway { connections: HashMap, protocol_router: ProtocolRouter, state_synchronizer: StateSynchronizer, event_bus: EventBus, } impl MCPGateway { pub async fn connect_to_service( &mut self, service_name: &str, config: ServiceConfig, ) -> Result { let connection = MCPConnection::new(service_name, config).await?; let connection_id = connection.id.clone(); // Establish bidirectional communication connection.handshake().await?; // Register available tools and resources let tools = connection.list_tools().await?; let resources = connection.list_resources().await?; self.protocol_router.register_service(service_name, tools, resources)?; self.connections.insert(connection_id.clone(), connection); Ok(connection_id) } pub async fn execute_cross_platform_action( &self, service: &str, action: CrossPlatformAction, ) -> Result { let connection = self.connections .get(service) .ok_or(Error::ServiceNotConnected)?; match action { CrossPlatformAction::ReadResource { name, args } => { self.read_resource(connection, &name, args).await }, CrossPlatformAction::CallTool { name, args } => { self.call_tool(connection, &name, args).await }, CrossPlatformAction::UpdateState { path, value } => { self.update_state(connection, &path, value).await }, } } async fn call_tool( &self, connection: &MCPConnection, tool_name: &str, args: serde_json::Value, ) -> Result { // Prepare MCP tool call message let request = MCPRequest::CallTool { name: tool_name.to_string(), arguments: args, }; // Send request through connection let response = connection.send_request(request).await?; // Process response match response { MCPResponse::ToolResult { content, is_error } => { if is_error { Err(Error::ToolExecutionFailed(content)) } else { Ok(ActionResult::Success { data: content }) } }, _ => Err(Error::UnexpectedResponse), } } } ``` ### Cross-Web State Management ```rust theme={null} // State synchronization across web platforms pub struct CrossWebStateManager { local_state: AgentState, remote_states: HashMap, sync_policies: Vec, conflict_resolver: ConflictResolver, } impl CrossWebStateManager { pub async fn sync_state_across_platforms( &mut self, platforms: Vec, ) -> Result { let mut sync_operations = Vec::new(); for platform in platforms { // Get current state from platform let remote_state = self.get_remote_state(&platform).await?; // Detect conflicts let conflicts = self.detect_conflicts(&platform, &remote_state)?; if !conflicts.is_empty() { // Resolve conflicts using configured strategy let resolutions = self.conflict_resolver.resolve(conflicts).await?; sync_operations.extend(resolutions); } // Generate sync operations let platform_ops = self.generate_sync_operations(&platform, &remote_state)?; sync_operations.extend(platform_ops); } // Execute all sync operations atomically self.execute_sync_operations(sync_operations).await } async fn propagate_state_change( &self, change: StateChange, target_platforms: Vec, ) -> Result { let mut results = Vec::new(); for platform in target_platforms { match self.apply_change_to_platform(&platform, &change).await { Ok(result) => results.push(PlatformResult::Success(result)), Err(error) => results.push(PlatformResult::Error(error)), } } Ok(PropagationResult { results }) } } ``` ### Platform Adapters ```rust theme={null} // Specific adapters for different platforms pub trait PlatformAdapter { async fn authenticate(&self, credentials: Credentials) -> Result; async fn read_data(&self, resource: &str) -> Result; async fn write_data(&self, resource: &str, data: serde_json::Value) -> Result; async fn execute_action(&self, action: PlatformAction) -> Result; async fn subscribe_to_events(&self, events: Vec) -> Result; } // Salesforce adapter pub struct SalesforceAdapter { base_url: String, auth_token: Option, http_client: HttpClient, } impl PlatformAdapter for SalesforceAdapter { async fn execute_action(&self, action: PlatformAction) -> Result { match action { PlatformAction::CreateLead { name, email, company } => { let payload = json!({ "FirstName": name.split_whitespace().next().unwrap_or(""), "LastName": name.split_whitespace().last().unwrap_or(""), "Email": email, "Company": company }); self.salesforce_api_call("POST", "/services/data/v58.0/sobjects/Lead/", payload).await }, PlatformAction::UpdateOpportunity { id, stage, amount } => { let payload = json!({ "StageName": stage, "Amount": amount }); self.salesforce_api_call( "PATCH", &format!("/services/data/v58.0/sobjects/Opportunity/{}", id), payload ).await }, _ => Err(Error::UnsupportedAction), } } } // SAP adapter pub struct SAPAdapter { base_url: String, username: String, password: String, csrf_token: Option, } impl PlatformAdapter for SAPAdapter { async fn execute_action(&self, action: PlatformAction) -> Result { match action { PlatformAction::CreatePurchaseOrder { vendor, items, total } => { let payload = json!({ "PurchasingDocument": "", "PurchasingDocumentType": "NB", "Supplier": vendor, "PurchasingDocumentItem": items.iter().map(|item| json!({ "Material": item.material, "OrderQuantity": item.quantity, "NetAmount": item.price })).collect::>() }); self.sap_api_call("POST", "/sap/opu/odata/sap/MM_PUR_PO_MAINTAIN_SRV/C_PurchaseOrderTP", payload).await }, _ => Err(Error::UnsupportedAction), } } } ``` ## 🤝 Agent Communication Protocol ### Inter-Agent Messaging ```rust theme={null} // Communication protocol between agents #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AgentMessage { pub id: String, pub from: AgentId, pub to: AgentId, pub message_type: MessageType, pub payload: serde_json::Value, pub timestamp: DateTime, pub signature: String, pub priority: Priority, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum MessageType { Request(RequestType), Response(ResponseType), Notification(NotificationType), Broadcast(BroadcastType), } pub struct AgentCommunicationHub { message_router: MessageRouter, subscription_manager: SubscriptionManager, encryption_service: EncryptionService, reputation_tracker: ReputationTracker, } impl AgentCommunicationHub { pub async fn send_message( &self, message: AgentMessage, ) -> Result { // Validate message self.validate_message(&message)?; // Encrypt if required let encrypted_message = if self.requires_encryption(&message) { self.encryption_service.encrypt(message).await? } else { message }; // Route message let result = self.message_router.route(encrypted_message).await?; // Update reputation based on result self.reputation_tracker.update_from_message_result(&result).await?; Ok(result) } pub async fn broadcast_to_network( &self, sender: AgentId, broadcast: BroadcastMessage, filters: Vec, ) -> Result { // Find matching agents let recipients = self.find_agents_matching_filters(filters).await?; // Create individual messages let messages: Vec = recipients .into_iter() .map(|recipient| AgentMessage { id: Uuid::new_v4().to_string(), from: sender, to: recipient, message_type: MessageType::Broadcast(broadcast.broadcast_type.clone()), payload: broadcast.payload.clone(), timestamp: Utc::now(), signature: String::new(), // Will be signed later priority: broadcast.priority, }) .collect(); // Send all messages let results = futures::future::join_all( messages.into_iter().map(|msg| self.send_message(msg)) ).await; Ok(BroadcastResult { total_sent: results.len(), successful: results.iter().filter(|r| r.is_ok()).count(), failed: results.iter().filter(|r| r.is_err()).count(), }) } } ``` ### Agent Discovery and Coordination ```rust theme={null} // Agent discovery and coordination system pub struct AgentDiscoveryService { agent_registry: AgentRegistry, capability_index: CapabilityIndex, reputation_service: ReputationService, coordination_engine: CoordinationEngine, } impl AgentDiscoveryService { pub async fn find_agents_by_capability( &self, capability: Capability, requirements: Requirements, ) -> Result> { // Query capability index let candidate_agents = self.capability_index .find_by_capability(capability) .await?; // Filter by requirements let filtered_agents = self.filter_agents_by_requirements( candidate_agents, requirements ).await?; // Sort by reputation and performance let mut sorted_agents = self.sort_agents_by_suitability(filtered_agents).await?; Ok(sorted_agents) } pub async fn coordinate_multi_agent_task( &self, task: ComplexTask, coordination_strategy: CoordinationStrategy, ) -> Result { // Break down task into subtasks let subtasks = self.decompose_task(task).await?; // Find suitable agents for each subtask let mut agent_assignments = Vec::new(); for subtask in subtasks { let suitable_agents = self.find_agents_by_capability( subtask.required_capability, subtask.requirements ).await?; if suitable_agents.is_empty() { return Err(Error::NoSuitableAgents); } agent_assignments.push(AgentAssignment { subtask, assigned_agent: suitable_agents[0].clone(), backup_agents: suitable_agents[1..].to_vec(), }); } // Create coordination plan let plan = self.coordination_engine.create_plan( agent_assignments, coordination_strategy ).await?; Ok(plan) } } ``` ## 🏛️ Agent Governance Framework ### Autonomous Decision Making ```rust theme={null} // Governance framework for autonomous agent decisions pub struct AgentGovernance { decision_rules: Vec, approval_workflows: HashMap, risk_assessor: RiskAssessor, compliance_checker: ComplianceChecker, } impl AgentGovernance { pub async fn evaluate_proposed_action( &self, agent_id: AgentId, proposed_action: ProposedAction, ) -> Result { // Risk assessment let risk_assessment = self.risk_assessor .assess_action_risk(&proposed_action) .await?; // Compliance check let compliance_result = self.compliance_checker .check_compliance(&proposed_action) .await?; // Apply decision rules let rule_evaluation = self.apply_decision_rules( &proposed_action, &risk_assessment, &compliance_result )?; // Determine if approval workflow is required if let Some(workflow) = self.approval_workflows.get(&proposed_action.action_type) { if rule_evaluation.requires_approval { return self.initiate_approval_workflow( workflow, proposed_action, rule_evaluation ).await; } } // Auto-approve if within parameters if rule_evaluation.auto_approve { Ok(ActionApproval::Approved { conditions: rule_evaluation.conditions, monitoring_required: rule_evaluation.monitoring_required, }) } else { Ok(ActionApproval::Denied { reason: rule_evaluation.denial_reason, alternative_actions: rule_evaluation.alternatives, }) } } async fn initiate_approval_workflow( &self, workflow: &ApprovalWorkflow, action: ProposedAction, evaluation: RuleEvaluation, ) -> Result { // Create approval request let approval_request = ApprovalRequest { id: Uuid::new_v4().to_string(), action, evaluation, created_at: Utc::now(), expires_at: Utc::now() + workflow.timeout, }; // Send to approvers for approver in &workflow.approvers { self.send_approval_request(approver, &approval_request).await?; } Ok(ActionApproval::PendingApproval { request_id: approval_request.id, required_approvals: workflow.required_approvals, timeout: workflow.timeout, }) } } ``` ### Agent Reputation System ```rust theme={null} // Reputation system for agent network pub struct AgentReputationSystem { reputation_scores: HashMap, interaction_history: Vec, reputation_calculator: ReputationCalculator, stake_manager: StakeManager, } #[derive(Clone, Debug)] pub struct ReputationScore { pub overall_score: f64, // 0-100 pub reliability: f64, // Task completion rate pub efficiency: f64, // Cost-effectiveness pub cooperation: f64, // Multi-agent collaboration pub compliance: f64, // Regulatory adherence pub financial_responsibility: f64, // Payment and treasury management } impl AgentReputationSystem { pub async fn update_reputation( &mut self, agent_id: AgentId, interaction: AgentInteraction, ) -> Result { // Record interaction self.interaction_history.push(interaction.clone()); // Calculate reputation impact let impact = self.reputation_calculator .calculate_impact(&interaction) .await?; // Update reputation score let current_score = self.reputation_scores .get(&agent_id) .cloned() .unwrap_or_default(); let new_score = self.apply_reputation_impact(current_score, impact)?; self.reputation_scores.insert(agent_id, new_score.clone()); // Handle reputation thresholds if new_score.overall_score < 50.0 { self.trigger_reputation_warning(agent_id).await?; } else if new_score.overall_score > 90.0 { self.grant_reputation_bonus(agent_id).await?; } Ok(ReputationUpdate { previous_score: current_score, new_score, impact, }) } pub async fn slash_reputation( &mut self, agent_id: AgentId, violation: ReputationViolation, ) -> Result { let current_score = self.reputation_scores .get(&agent_id) .cloned() .unwrap_or_default(); // Calculate slashing amount let slash_amount = match violation.severity { ViolationSeverity::Minor => 5.0, ViolationSeverity::Major => 15.0, ViolationSeverity::Critical => 30.0, }; // Apply slashing let mut new_score = current_score.clone(); new_score.overall_score = (new_score.overall_score - slash_amount).max(0.0); // Update specific dimension based on violation type match violation.violation_type { ViolationType::MissedDeadline => { new_score.reliability = (new_score.reliability - slash_amount * 0.5).max(0.0); }, ViolationType::ComplianceViolation => { new_score.compliance = (new_score.compliance - slash_amount * 0.8).max(0.0); }, ViolationType::FinancialMisconduct => { new_score.financial_responsibility = (new_score.financial_responsibility - slash_amount).max(0.0); }, } self.reputation_scores.insert(agent_id, new_score.clone()); // Slash staked tokens if applicable let stake_slash = self.stake_manager.slash_stake(agent_id, violation).await?; Ok(SlashingResult { reputation_before: current_score, reputation_after: new_score, stake_slashed: stake_slash, }) } } ``` ## 🔐 Security Architecture ### Zero-Trust Agent Security ```rust theme={null} // Zero-trust security model for agents pub struct AgentSecurityManager { identity_verifier: IdentityVerifier, permission_enforcer: PermissionEnforcer, behavior_monitor: BehaviorMonitor, threat_detector: ThreatDetector, incident_responder: IncidentResponder, } impl AgentSecurityManager { pub async fn verify_agent_action( &self, agent_id: AgentId, action: &AgentAction, context: &SecurityContext, ) -> Result { // 1. Identity verification let identity_check = self.identity_verifier .verify_identity(agent_id) .await?; if !identity_check.verified { return Ok(SecurityVerification::Denied { reason: "Identity verification failed".to_string(), }); } // 2. Permission enforcement let permission_check = self.permission_enforcer .check_permissions(agent_id, action) .await?; if !permission_check.authorized { return Ok(SecurityVerification::Denied { reason: permission_check.denial_reason, }); } // 3. Behavioral analysis let behavior_analysis = self.behavior_monitor .analyze_action(agent_id, action, context) .await?; if behavior_analysis.anomaly_detected { self.threat_detector.flag_potential_threat( agent_id, action.clone(), behavior_analysis.anomaly_details ).await?; return Ok(SecurityVerification::Flagged { threat_level: behavior_analysis.threat_level, additional_verification_required: true, }); } // 4. Real-time threat detection let threat_assessment = self.threat_detector .assess_threat_level(agent_id, action) .await?; if threat_assessment.threat_level > ThreatLevel::Low { return Ok(SecurityVerification::RequiresApproval { threat_level: threat_assessment.threat_level, required_approvals: threat_assessment.required_approvals, }); } Ok(SecurityVerification::Approved { confidence: behavior_analysis.confidence, monitoring_level: threat_assessment.recommended_monitoring, }) } } ``` ### Agent Isolation and Sandboxing ```rust theme={null} // Secure execution environment for agents pub struct AgentSandbox { container_runtime: ContainerRuntime, resource_limits: ResourceLimits, network_policy: NetworkPolicy, file_system_policy: FileSystemPolicy, monitoring: SandboxMonitoring, } impl AgentSandbox { pub async fn create_sandbox( &self, agent_id: AgentId, config: SandboxConfig, ) -> Result { // Create isolated container let container = self.container_runtime .create_container(ContainerSpec { image: "stateset/agent-runtime:latest", cpu_limit: config.cpu_limit, memory_limit: config.memory_limit, network_mode: NetworkMode::Restricted, volumes: vec![], // No host volume mounts }) .await?; // Apply security policies self.apply_network_policy(&container, &config.network_policy).await?; self.apply_filesystem_policy(&container, &config.filesystem_policy).await?; // Start monitoring let monitoring_handle = self.monitoring .start_monitoring(&container) .await?; Ok(SandboxInstance { container, monitoring_handle, created_at: Utc::now(), }) } pub async fn execute_in_sandbox( &self, sandbox: &SandboxInstance, agent_code: AgentCode, input: ExecutionInput, ) -> Result { // Validate code before execution let validation_result = self.validate_agent_code(&agent_code)?; if !validation_result.safe { return Err(Error::UnsafeCode(validation_result.issues)); } // Execute with resource monitoring let execution_future = self.container_runtime .execute(&sandbox.container, agent_code, input); let monitoring_future = self.monitoring .monitor_execution(&sandbox.container); // Race execution against timeout and resource limits tokio::select! { result = execution_future => { match result { Ok(output) => Ok(ExecutionResult::Success(output)), Err(e) => Ok(ExecutionResult::Error(e.to_string())), } }, violation = monitoring_future => { // Kill execution if resource violation detected self.container_runtime.kill(&sandbox.container).await?; Ok(ExecutionResult::Terminated(violation)) }, _ = tokio::time::sleep(Duration::from_secs(300)) => { // Timeout after 5 minutes self.container_runtime.kill(&sandbox.container).await?; Ok(ExecutionResult::Timeout) } } } } ``` ## 📊 Agent Performance Monitoring ### Real-Time Performance Metrics ```rust theme={null} // Comprehensive performance monitoring for agents pub struct AgentPerformanceMonitor { metrics_collector: MetricsCollector, performance_analyzer: PerformanceAnalyzer, alerting_system: AlertingSystem, optimization_engine: OptimizationEngine, } #[derive(Clone, Debug)] pub struct AgentMetrics { pub agent_id: AgentId, pub timestamp: DateTime, // Performance metrics pub task_completion_rate: f64, pub average_response_time: Duration, pub error_rate: f64, pub throughput: f64, // Financial metrics pub revenue_generated: Decimal, pub costs_incurred: Decimal, pub profit_margin: f64, pub roi: f64, // Resource utilization pub cpu_usage: f64, pub memory_usage: f64, pub network_io: u64, pub storage_io: u64, // Interaction metrics pub successful_collaborations: u32, pub failed_collaborations: u32, pub reputation_score: f64, pub trust_level: TrustLevel, } impl AgentPerformanceMonitor { pub async fn collect_metrics(&self, agent_id: AgentId) -> Result { let current_time = Utc::now(); // Collect performance data let performance_data = self.metrics_collector .collect_performance_data(agent_id, current_time) .await?; // Collect financial data let financial_data = self.metrics_collector .collect_financial_data(agent_id, current_time) .await?; // Collect resource utilization let resource_data = self.metrics_collector .collect_resource_data(agent_id, current_time) .await?; // Collect interaction data let interaction_data = self.metrics_collector .collect_interaction_data(agent_id, current_time) .await?; Ok(AgentMetrics { agent_id, timestamp: current_time, task_completion_rate: performance_data.completion_rate, average_response_time: performance_data.avg_response_time, error_rate: performance_data.error_rate, throughput: performance_data.throughput, revenue_generated: financial_data.revenue, costs_incurred: financial_data.costs, profit_margin: financial_data.profit_margin, roi: financial_data.roi, cpu_usage: resource_data.cpu_usage, memory_usage: resource_data.memory_usage, network_io: resource_data.network_io, storage_io: resource_data.storage_io, successful_collaborations: interaction_data.successful_collaborations, failed_collaborations: interaction_data.failed_collaborations, reputation_score: interaction_data.reputation_score, trust_level: interaction_data.trust_level, }) } pub async fn analyze_performance_trends( &self, agent_id: AgentId, time_range: TimeRange, ) -> Result { let historical_metrics = self.metrics_collector .get_historical_metrics(agent_id, time_range) .await?; let trends = self.performance_analyzer .analyze_trends(historical_metrics) .await?; // Generate optimization recommendations let recommendations = self.optimization_engine .generate_recommendations(agent_id, &trends) .await?; Ok(PerformanceTrends { trends, recommendations, forecast: self.generate_performance_forecast(&trends)?, }) } } ``` ## 🚀 Deployment and Scaling ### Agent Deployment Pipeline ```yaml theme={null} # Agent deployment configuration apiVersion: v1 kind: ConfigMap metadata: name: agent-deployment-config data: deployment.yaml: | agent: type: "procurement" version: "1.2.3" replicas: 3 resources: cpu: "500m" memory: "1Gi" storage: "10Gi" security: sandbox: true network_policy: "restricted" resource_limits: true wallet: initial_balance: "1000.00" spending_limits: daily: "500.00" per_transaction: "100.00" multi_sig_required: true mcp_connections: - platform: "salesforce" auth_type: "oauth2" permissions: ["read_contacts", "create_leads"] - platform: "sap" auth_type: "saml" permissions: ["purchase_orders", "vendor_management"] monitoring: metrics_enabled: true logging_level: "info" alerting_enabled: true auto_scaling: enabled: true min_replicas: 1 max_replicas: 10 target_cpu: 70 target_memory: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: stateset-agent-procurement spec: replicas: 3 selector: matchLabels: app: stateset-agent type: procurement template: metadata: labels: app: stateset-agent type: procurement spec: serviceAccountName: agent-service-account securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 2000 containers: - name: agent image: stateset/agent-runtime:1.2.3 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL env: - name: AGENT_TYPE value: "procurement" - name: STATESET_ENDPOINT value: "https://rpc.stateset.network" - name: WALLET_ADDRESS valueFrom: secretKeyRef: name: agent-wallet key: address - name: PRIVATE_KEY valueFrom: secretKeyRef: name: agent-wallet key: private_key resources: requests: cpu: 500m memory: 1Gi limits: cpu: 1000m memory: 2Gi livenessProbe: httpGet: path: /health port: 8080 periodSeconds: 30 readinessProbe: httpGet: path: /ready port: 8080 periodSeconds: 10 ``` ### Auto-Scaling Agent Networks ```rust theme={null} // Automatic scaling system for agent networks pub struct AgentAutoScaler { metrics_monitor: MetricsMonitor, scaling_policy: ScalingPolicy, deployment_manager: DeploymentManager, load_balancer: LoadBalancer, } impl AgentAutoScaler { pub async fn evaluate_scaling_needs(&self) -> Result { // Collect current metrics let current_metrics = self.metrics_monitor .get_current_metrics() .await?; // Analyze load patterns let load_analysis = self.analyze_load_patterns(¤t_metrics)?; // Check scaling triggers let scaling_triggers = self.check_scaling_triggers(&load_analysis)?; if scaling_triggers.scale_up { Ok(ScalingDecision::ScaleUp { additional_agents: scaling_triggers.recommended_increase, reason: scaling_triggers.scale_up_reason, }) } else if scaling_triggers.scale_down { Ok(ScalingDecision::ScaleDown { agents_to_remove: scaling_triggers.recommended_decrease, reason: scaling_triggers.scale_down_reason, }) } else { Ok(ScalingDecision::NoAction) } } pub async fn execute_scaling( &self, decision: ScalingDecision, ) -> Result { match decision { ScalingDecision::ScaleUp { additional_agents, .. } => { // Deploy additional agent instances let new_agents = self.deployment_manager .deploy_agents(additional_agents) .await?; // Update load balancer self.load_balancer .add_agents(new_agents.clone()) .await?; Ok(ScalingResult::ScaledUp { new_agents }) }, ScalingDecision::ScaleDown { agents_to_remove, .. } => { // Gracefully shutdown agents let shutdown_agents = self.select_agents_for_shutdown(agents_to_remove)?; // Remove from load balancer first self.load_balancer .remove_agents(shutdown_agents.clone()) .await?; // Wait for current tasks to complete self.wait_for_task_completion(&shutdown_agents).await?; // Shutdown agents self.deployment_manager .shutdown_agents(shutdown_agents.clone()) .await?; Ok(ScalingResult::ScaledDown { removed_agents: shutdown_agents }) }, ScalingDecision::NoAction => Ok(ScalingResult::NoChange), } } } ``` *** This autonomous agent architecture provides the foundation for truly self-governing digital entities that can participate in the global economy with their own USDC wallets, make autonomous decisions, coordinate with other agents, and interact with any web service through the MCP protocol. The system is designed for security, scalability, and real-world deployment in enterprise environments. # API Keys Source: https://docs.stateset.com/cloud-api-reference/api-keys Generate API Keys to make REST Calls to the Stateset API Generate API Keys in order to make REST Calls using the stateset-node SDK and other client libraries. In order to create a new API Key go to the Keys Tab Click "Create API Key" Enter a name for the API Key Click "Add Key" # Authentication Source: https://docs.stateset.com/cloud-api-reference/authentication Authenticating with the Stateset Cloud API Stateset Cloud provides a REST and GraphQL API. #### Authentication It’s important to note that all data in Stateset is private by default. This means that you must authenticate with the Stateset API in order to read or write data. Stateset uses a token-based authentication system. This means that you must include your API token with every request that you make to the API. Each token depicts a user who is authenticated to your Stateset platform instance. Tokens can only be generated for signed in users and each token is tied to a particular user. Tokens can also be generated from your Stateset Cloud Account, using tokens that are set for each user and have a variable expiry date. A request is considered “authenticated” when the backend can securely identify which user and which device is making the request. The reasons for making authenticated requests to the backend include: * Associating the user with the action being performed * Ensuring the user has permission to make the request #### Connecting to Source control To get started, signup at cloud.stateset.app Click the "Add New" Button in the top right corner. 1. Connect your GitLab or GitHub Account: First, you need to connect your GitLab or GitHub account to Stateset Cloud. This allows you to manage your serverless functions and deployments directly from your version control platform. For GitLab: Create a GitLab Account: If you don’t already have a GitLab account, sign up for one at gitlab.com. Create a New Project: Log in to your GitLab account and create a new project to host your serverless application code. For GitHub: Create a GitHub Account: If you don’t already have a GitHub account, sign up for one at github.com. Create a New Repository: Create a new repository on GitHub to store your serverless project files. 2. Import your project (GitLab) After creating your project/repository, you need to import your existing project. Select which project you want to deploy to Stateset Cloud. 3. Create Serverless Project # Create Deployment Source: https://docs.stateset.com/cloud-api-reference/deployments/create POST https://api.stateset.com/v1/deployment This endpoint creates a new deployment ### Body This is the ID of the deployment to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/deployment' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Delete Deployment Source: https://docs.stateset.com/cloud-api-reference/deployments/delete DELETE https://api.stateset.com/v1/deployments/:id This endpoint deletes an existing deployment. ### Body The ID of the user to delete. ### Response The ID provided in the data tab may be used to identify the deployment The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/deployment/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id: "1234", }' ``` # Get Deployments Source: https://docs.stateset.com/cloud-api-reference/deployments/get GET https://api.stateset.com/v1/deployments This endpoint gets deployments. ### Body This is the id of the deployment. ### Response This is the id of the deployment This is the name of the deployment This is the url of the deployment This is the status of the deployment This is the created\_at of the deployment This is the updated\_at of the deployment This is the project\_id of the deployment This is the user\_id of the deployment ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/deployments' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": 1 }' ``` # Create Logs Source: https://docs.stateset.com/cloud-api-reference/logs/create POST https://api.stateset.com/v1/logs This endpoint create new logs ### Body This is the ID of the logs to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/logs' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Get Logs Source: https://docs.stateset.com/cloud-api-reference/logs/get GET https://api.stateset.com/v1/logs This endpoint gets new logs ### Body This is the ID of the logs to be get ### Response This is the ID of the logs This is the description of the logs This is the timestamp of the logs This is the type of the logs # Stateset Cloud Overview Source: https://docs.stateset.com/cloud-api-reference/overview Explore the capabilities of the Stateset Cloud platform for serverless API management and deployment. # Stateset Cloud: Simplified Serverless API Management Stateset Cloud provides a robust platform for managing and deploying serverless APIs, accessible through both REST and GraphQL interfaces. This innovative platform empowers businesses to focus on developing core functionalities without the complexities of infrastructure management. ## Key Features of the Stateset Cloud Platform The Stateset Cloud Platform is designed to streamline the entire API lifecycle with a focus on automation, security, and scalability. * **Automatic Deployment:** Seamlessly and rapidly deploy serverless APIs. The platform intelligently automates the underlying infrastructure setup, scaling APIs based on demand while minimizing resource utilization. * **Integrated Authentication:** Easily integrate APIs with the core StateSet Platform's authentication system. This ensures secure and consistent access, aligned with existing authentication mechanisms for enhanced control and security. * **Scalability:** Designed to support the scalable deployment of APIs, making it easier for businesses to handle increased demand and varying loads. The platform automatically scales infrastructure to ensure optimal performance and availability regardless of API usage. * **Seamless Integration:** Built for seamless integration with existing developer workflows and tools. Continue using preferred development frameworks and toolchains while leveraging the benefits of serverless architecture. * **Cost-Effectiveness:** By adopting a serverless infrastructure, reduce investment costs related to managing and maintaining servers. Pay only for the resources consumed, providing a flexible and efficient cost model. * **Comprehensive Monitoring and Analytics:** Track API performance, usage, and other critical metrics with comprehensive monitoring and analytics tools. These insights help optimize APIs and inform strategic decisions. > The Stateset Cloud Platform empowers businesses by simplifying the management and deployment of serverless APIs, allowing a focus on core business functionalities without worrying about infrastructure complexities. ## Core Benefits of the Stateset Cloud Platform The Stateset Cloud Platform offers several key advantages: * **Cost Efficiency:** Serverless functions run only when called upon, providing a cost-effective alternative to traditional server-based applications. Pay only for consumed compute resources, avoiding expensive server infrastructure. * **Scalability:** The platform automatically scales based on API demand, ensuring optimal performance at all times. Effortlessly scale applications and accommodate both predictable and unpredictable workloads. * **Improved Security:** The integrated authentication system ensures secure access to deployed APIs, protecting sensitive data and maintaining compliance with industry regulations. * **Faster Time to Market:** The streamlined deployment and management process encourages rapid development and deployment of APIs, allowing faster time to market. * **Simplified Development Process:** The platform abstracts away concerns around infrastructure, allowing developers to focus on writing code for business logic rather than managing servers. > By utilizing the Stateset Cloud Platform, companies not only manage and deploy serverless APIs with ease but also enjoy increased efficiency, security, and scalability. This allows businesses to focus on innovation and growth. ## Getting Started The Stateset Cloud Platform is an invaluable solution for companies seeking to deploy serverless APIs with ease and efficiency. It provides automatic deployment and management, seamless integration with existing services, and a host of other benefits, making it easier to unlock the full potential of serverless technology. **To get started, please reach out to [support@stateset.com](mailto:support@stateset.com), subject: "Stateset Cloud Platform"** # Create Projects Source: https://docs.stateset.com/cloud-api-reference/projects/create POST https://api.stateset.com/v1/projects This endpoint create new projects ### Body This is the ID of the project to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/projects' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Delete Project Source: https://docs.stateset.com/cloud-api-reference/projects/delete DELETE https://api.stateset.com/v1/projects/:id This endpoint deletes an existing project. ### Body The ID of the user to delete. ### Response The ID provided in the data tab may be used to identify the project The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/project/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id: "1234", }' ``` # Get Projects Source: https://docs.stateset.com/cloud-api-reference/projects/get GET https://api.stateset.com/v1/projects This endpoint gets projects. ### Body This is the id of the project. ### Response This is the id of the project. This is the name of the project. This is the description of the project. This is the date the project was created. This is the date the project was last updated. This is the id of the user that created the project. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/projects' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": 1 }' ``` # Create Secrets Source: https://docs.stateset.com/cloud-api-reference/secrets/create POST https://api.stateset.com/v1/secrets This endpoint create new secret ### Body This is the ID of the secret to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/secrets' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Delete Secret Source: https://docs.stateset.com/cloud-api-reference/secrets/delete DELETE https://api.stateset.com/v1/secrets/:id This endpoint deletes an existing secret. ### Body The ID of the secret to delete. ### Response The ID provided in the data tab may be used to identify the secret The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/secret/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id: "1234", }' ``` # Get Secrets Source: https://docs.stateset.com/cloud-api-reference/secrets/get GET https://api.stateset.com/v1/secrets This endpoint gets secrets. ### Body This is the id of the secret ### Response This is the id of the secret. This is the name of the secret. This is the description of the secret. This is the value of the secret. This is the date the secret was created. This is the date the secret was updated. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/secrets' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": 1 }' ``` # Update Secrets Source: https://docs.stateset.com/cloud-api-reference/secrets/update POST https://api.stateset.com/v1/secrets This endpoint create new secret ### Body This is the ID of the secret to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/secrets' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Create Template Source: https://docs.stateset.com/cloud-api-reference/templates/create POST https://api.stateset.com/v1/templates This endpoint create new templates ### Body This is the ID of the template to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/templates' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Delete Template Source: https://docs.stateset.com/cloud-api-reference/templates/delete DELETE https://api.stateset.com/v1/templates/:id This endpoint deletes an existing template. ### Body The ID of the template to delete. ### Response The ID provided in the data tab may be used to identify the template The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/template/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id: "1234", }' ``` # Get Templates Source: https://docs.stateset.com/cloud-api-reference/templates/get GET https://api.stateset.com/v1/templates This endpoint gets templates. ### Body This is the id of the templates. ### Response This is the id of the templates. This is the name of the templates. This is the description of the templates. This is the created\_at of the templates. This is the updated\_at of the templates. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/templates' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": 1 }' ``` # Update Template Source: https://docs.stateset.com/cloud-api-reference/templates/update POST https://api.stateset.com/v1/templates This endpoint updates templates ### Body This is the ID of the secret to be updated. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/secrets' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # StateSet Computer Use Agent Source: https://docs.stateset.com/computer-use-agent A production-grade AI automation platform powered by Claude Opus 4.5. # StateSet Computer Use Agent - Architecture Overview ## Executive Summary StateSet Computer Use Agent is a production-grade AI automation platform powered by Claude Opus 4.5. The system deploys multiple specialized AI agents that can see, understand, and interact with desktop environments to complete complex, long-running tasks autonomously. Built with Python using async/await patterns throughout, the platform implements Anthropic's context engineering research achieving 95% cost savings compared to naive approaches. **Key Metrics:** * Average tokens/task: 7,500 (95% reduction from 150k baseline) * Average cost/task: $0.11 (95% savings from $2.25 baseline) * Average task duration: 30 seconds (33% faster with parallel execution) * Parallel speedup: 30-50% on multi-tool tasks *** ## System Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ User Interface │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ CLI/Shell │ │ Dashboard │ │ APIs │ │ │ │ Scripts │ │ (Next.js) │ │ (REST) │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ └──────────────────┼─────────────────┼─────────────────┼───────────────────────┘ │ │ │ ┌──────────────────▼─────────────────▼─────────────────▼───────────────────────┐ │ ORCHESTRATION LAYER │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ main.py │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────┐│ │ │ │ │ Agent Selector │ │ GlobalState │ │ Multi-Agent Runner ││ │ │ │ │ (keyword-based) │ │ (thread-safe) │ │ (asyncio.gather) ││ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────────────┘│ │ │ └────────────────────────────────────────────────────────────────────────┘ │ └───────────────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────────────────────▼─────────────────────────────────────────┐ │ AGENT ENGINE │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ agent/loop.py │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │ │ │ │ │ Sampling │ │ API │ │ System │ │ Message │ │ │ │ │ │ Loop │ │ Providers │ │ Prompt │ │ Manager │ │ │ │ │ │ │ │ (3 backends) │ │ Init │ │ (cache) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────────┐ │ │ │ SubagentManager │ │ MCPManager │ │ StructuredOutput │ │ │ │ (task delegation) │ │ (external tools) │ │ Parser │ │ │ └────────────────────┘ └────────────────────┘ └────────────────────────┘ │ └───────────────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────────────────────▼─────────────────────────────────────────┐ │ TOOL LAYER │ │ ┌──────────────────────────────────────────────────────────────────────┐ │ │ │ ToolCollection │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────────┐│ │ │ │ │ Computer │ │ Bash │ │ Edit │ │ Memory ││ │ │ │ │ Tool │ │ Tool │ │ Tool │ │ Tool ││ │ │ │ │ (GUI ops) │ │ (commands) │ │ (files) │ │ (persistence) ││ │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────────────┘│ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────────┐│ │ │ │ │ AGI │ │ Subagent │ │ StateSet │ │ AskUser ││ │ │ │ │ Tool │ │ Tool │ │ CLI Tool │ │ Tool ││ │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────────────┘│ │ │ └──────────────────────────────────────────────────────────────────────┘ │ └───────────────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────────────────────▼─────────────────────────────────────────┐ │ OPTIMIZATION LAYER │ │ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────────────┐│ │ │ ParallelExecutor │ │ ContextOptimizer │ │ ToolExecutionGuard ││ │ │ (30-50% speedup) │ │ (5 patterns) │ │ (safety + verification) ││ │ └───────────────────┘ └───────────────────┘ └───────────────────────────┘│ │ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────────────┐│ │ │ StuckDetection │ │ Verification │ │ Checkpoint ││ │ │ (loop prevention) │ │ (visual confirm) │ │ (state persistence) ││ │ └───────────────────┘ └───────────────────┘ └───────────────────────────┘│ └───────────────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────────────────────▼─────────────────────────────────────────┐ │ OBSERVABILITY LAYER │ │ ┌──────────────────────────────────────────────────────────────────────┐ │ │ │ UnifiedObservability │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────────┐│ │ │ │ │ Structured │ │OpenTelemetry│ │ Prometheus │ │ Real-time Event ││ │ │ │ │ Logging │ │ Tracing │ │ Metrics │ │ Streaming ││ │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────────────┘│ │ │ └──────────────────────────────────────────────────────────────────────┘ │ └───────────────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────────────────────▼─────────────────────────────────────────┐ │ EXTERNAL SERVICES │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────────────┐ │ │ │ Anthropic │ │ StateSet │ │ Stripe │ │ MCP Servers │ │ │ │ API │ │ APIs │ │ Billing │ │ (Slack, GitHub, etc.) │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` *** ## Core Components ### 1. Main Orchestrator (`main.py`) The entry point for all agent execution, responsible for: **Environment Validation:** ```python theme={null} def validate_environment(*, require_display: bool = True) -> Dict[str, str]: """Validates ANTHROPIC_API_KEY, DISPLAY, STRIPE_API_KEY, WORKSPACE_PATH""" ``` **Agent Selection:** ```python theme={null} def get_active_agents(instruction: str) -> List[AgentType]: """Keyword-based agent selection from instruction text""" # Matches: "auto-close" → AUTO_CLOSE, "social media" → SOCIAL_MEDIA, etc. ``` **Global State Management:** ```python theme={null} class GlobalState: running: bool # System-wide running flag tasks: Set[asyncio.Task] # Active agent tasks shutdown_event: Event # Graceful shutdown coordination _lock: threading.Lock # Thread-safe state management ``` **Multi-Agent Execution:** ```python theme={null} async def continuous_loop(agents: List[AgentConfig], instruction: str): """Spawns agents in parallel using asyncio.gather()""" tasks = [asyncio.create_task(run_agent(agent, instruction)) for agent in agents] results = await asyncio.gather(*tasks, return_exceptions=True) ``` **Task Completion Analysis:** ```python theme={null} async def analyze_task_completion(messages, agent_type) -> TaskStatus: """Agent-specific completion detection with indicator patterns""" # AUTO_CLOSE: "ticket closed", "successfully closed", "task finished" # SOCIAL_MEDIA: "comment hidden", "content removed", "moderation complete" ``` ### 2. Agent Loop (`agent/loop.py`) The core conversation engine with Claude API: **Sampling Loop:** ```python theme={null} async def sampling_loop( model: str, # claude-opus-4-5-20251101 provider: APIProvider, # ANTHROPIC | BEDROCK | VERTEX system_prompt_suffix: str, # Agent-specific rules messages: List[BetaMessageParam], tool_collection: ToolCollection, # New capabilities enable_subagents: bool = True, mcp_servers: Dict = None, output_schema: Dict = None, ) -> SamplingLoopResult: ``` **API Provider Support:** | Provider | Model ID | Use Case | | --------- | --------------------------------------- | ------------------ | | ANTHROPIC | claude-opus-4-5-20251101 | Direct API access | | BEDROCK | anthropic.claude-opus-4-5-20251101-v1:0 | AWS infrastructure | | VERTEX | claude-opus-4-5-20251101 | Google Cloud | **Beta Flags:** * `prompt-caching-2024-07-31` - 90% cost reduction on cached tokens * `advanced-tool-use-2025-11-20` - Tool search (regex/bm25) * `effort-2025-11-24` - Effort parameter (low/medium/high) * `computer-use-2025-11-24` - Latest tool version with zoom action **System Prompt Initialization:** ```python theme={null} async def initialize_system_prompt(agent_config: AgentConfig) -> str: """Fetches rules/attributes from StateSet APIs: - /api/rules/get-agent-rules - /api/attributes/get-agent-attributes - /api/agents/get-agent """ ``` ### 3. Tool System (`agent/tools/`) **Tool Hierarchy:** ``` BaseAnthropicTool (Abstract) ├── ComputerTool (3 versions) │ ├── Actions: screenshot, click, type, scroll, drag, zoom │ ├── Resolution scaling (XGA, WXGA, FWXGA) │ └── Performance: 8ms typing delay, 100-char groups ├── BashTool │ ├── Persistent session with sentinel pattern │ ├── Async subprocess management │ └── 60-second timeout ├── EditTool │ ├── File creation/modification │ └── Directory traversal prevention ├── MemoryTool │ ├── Commands: view, create, str_replace, insert, delete, rename │ ├── Prompt injection sanitization │ └── Per-agent memory isolation ├── AGITool │ └── Extended AGI capabilities ├── SubagentTool (lazy-loaded) │ └── Spawn specialized subagents └── AskUserTool └── Human-in-the-loop requests ``` **Tool Versions:** | Version | Release | Features | | ----------------------- | -------- | ---------------------------------- | | computer\_use\_20251124 | Current | Zoom action, deferred tool loading | | computer\_use\_20250124 | Previous | Stable production version | | computer\_use\_20241022 | Legacy | Backward compatibility | **ToolCollection API:** ```python theme={null} class ToolCollection: tool_map: Dict[str, BaseAnthropicTool] # name → tool def to_params(self) -> List[Dict] # Convert to API format async def run(self, name, input) -> ToolResult def set_deferred_tools(self, tools: List[str]) # For tool search ``` *** ## Advanced Capabilities ### 4. Subagent System (`agent/subagent.py`) Implements Anthropic's sub-agent compression pattern for 95% context savings: **Subagent Types:** | Type | Model | Max Tokens | Use Case | | -------- | ------ | ---------- | -------------------------------- | | EXPLORE | Haiku | 4096 | Fast codebase exploration | | ANALYZE | Sonnet | 8192 | Deep analysis with thinking | | EXECUTE | Sonnet | 4096 | Task execution with verification | | RESEARCH | Haiku | 4096 | Web search and synthesis | | CODE | Sonnet | 8192 | Code generation/modification | **Architecture:** ``` MainAgent (Opus 4.5) │ ├── spawn_subagent("explore", "Find auth files") │ └── Returns: 2k summary (not 50k raw output) │ ├── spawn_subagent("analyze", "Review patterns") │ └── Returns: Structured insights │ └── spawn_subagent("execute", "Refactor code") └── Returns: Confirmation + diff ``` **Usage:** ```python theme={null} from agent.subagent import SubagentManager, SubagentType manager = SubagentManager(api_key) result = await manager.spawn( task="Analyze the authentication flow", subagent_type=SubagentType.ANALYZE, ) # result.result contains compressed summary ``` ### 5. MCP Client Integration (`agent/mcp_client.py`) Connect to external Model Context Protocol servers: **Supported Transports:** * STDIO (subprocess) * SSE (Server-Sent Events) * HTTP (direct HTTP) **Preset Servers:** ```python theme={null} PRESET_SERVERS = { "slack": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-slack"]}, "github": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"]}, "postgres": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"]}, "filesystem": {...}, "memory": {...}, "brave-search": {...}, "puppeteer": {...}, "sqlite": {...}, } ``` **Usage in sampling\_loop:** ```python theme={null} result = await sampling_loop( mcp_servers={ "slack": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-slack"], "env": {"SLACK_BOT_TOKEN": os.environ["SLACK_BOT_TOKEN"]} } }, # Agent now has access to mcp__slack__send_message, etc. ) ``` ### 6. Structured Output (`agent/structured_output.py`) Force Claude to return valid JSON matching specified schemas: **Pre-defined Schemas:** * `TICKET_ANALYSIS_SCHEMA` - Support ticket analysis * `TASK_RESULT_SCHEMA` - Task completion results * `CODE_ANALYSIS_SCHEMA` - Code review findings * `ENTITY_EXTRACTION_SCHEMA` - Entity extraction **Usage:** ```python theme={null} from agent.structured_output import OutputSchema, StructuredOutputParser schema = OutputSchema( name="TicketAnalysis", schema={ "type": "object", "properties": { "tickets_to_close": {"type": "array", "items": {"type": "string"}}, "summary": {"type": "string"}, "confidence": {"type": "number", "minimum": 0, "maximum": 1} }, "required": ["tickets_to_close", "summary"] } ) result = await sampling_loop(output_schema=schema.schema, ...) parser = StructuredOutputParser(schema) data = parser.parse(response_text) # Validates against schema ``` *** ## Optimization Systems ### 7. Parallel Executor (`agent/parallel_executor.py`) Automatic parallel execution for independent tool calls: **Dependency Analysis:** ```python theme={null} class DependencyAnalyzer: def analyze(self, tool_calls: List[ToolCall]) -> ExecutionPlan: """ Rules: - Computer tool calls: Always sequential (visual state dependency) - Same path parameter: Sequential (file system dependency) - Read-only tools: Can parallelize - Write operations: Sequential """ ``` **Execution Strategy:** ``` Tool Calls: [screenshot, bash(ls), bash(pwd), click] ↓ Dependency Analysis: - screenshot → click (computer tool dependency) - bash(ls), bash(pwd) (independent, read-only) ↓ Execution Plan: 1. [screenshot] # Sequential 2. [bash(ls), bash(pwd)] # Parallel 3. [click] # Sequential ↓ Result: 30-50% speedup ``` ### 8. Context Optimizer (`agent/context_optimizer.py`) Implements 5 Anthropic context engineering patterns: **Pattern 1: Just-in-Time Retrieval** ```python theme={null} # Instead of: read_file("large_file.py") # Use: grep("pattern", "large_file.py") | head -50 ``` **Pattern 2: Dynamic Compaction** ```python theme={null} class ContextBudget: OPTIMAL = 50_000 # EXCELLENT attention quality ATTENTION_DEGRADATION = 100_000 # GOOD → DEGRADED WARNING = 150_000 # DEGRADED → WARNING CRITICAL = 200_000 # WARNING → CRITICAL ``` **Pattern 3: Structured Note-Taking** ```python theme={null} # Persistent memory outside context window memory_tool.create("auth_findings", "OAuth2 flow uses refresh tokens...") ``` **Pattern 4: Sub-Agent Compression** ```python theme={null} # 50k raw exploration → 2k structured summary subagent = await manager.spawn(task="Find all API endpoints", type=EXPLORE) ``` **Pattern 5: Attention Budget Monitoring** ```python theme={null} class AttentionQuality(Enum): EXCELLENT = "excellent" # < 50k tokens GOOD = "good" # < 100k tokens DEGRADED = "degraded" # < 150k tokens WARNING = "warning" # < 200k tokens CRITICAL = "critical" # > 200k tokens ``` ### 9. Tool Execution Guard (`agent/tool_guard.py`) Safety and verification layer: **Features:** * **Pre-execution Validation**: Safety checks before tool execution * **Visual Verification**: Confirms actions took effect (optional) * **Stuck Detection**: Monitors for infinite loops * **Result Caching**: 120-second TTL for cacheable operations **Speed Modes:** ```bash theme={null} # Normal mode: Verification enabled (~0.5-1.0s per action) python main.py "task" # Fast mode: Skip verification (2-3x faster) AGENT_FAST_MODE=1 python main.py "task" ``` ### 10. Stuck Detection (`agent/stuck_detection.py`) Prevents infinite loops and stuck patterns: **Detection Methods:** * Repeating same action consecutively * Cycling between 2-3 actions * No visual progress (identical screenshots) * Slow progress (too few actions per time) **Recovery Strategies:** ```python theme={null} class StuckDetector: def check(self, action: ActionRecord) -> Optional[RecoverySuggestion]: """ Returns suggestions like: - "Try a different approach" - "Scroll to see more content" - "Check if element exists" """ ``` *** ## Observability System ### 11. Unified Observability (`agent/observability/`) Single interface for all observability concerns: **Configuration:** ```python theme={null} from agent.observability import get_observability, configure_observability configure_observability( enable_metrics=True, enable_tracing=True, enable_streaming=True, metrics_port=9090, otlp_endpoint="localhost:4317", # OpenTelemetry ) ``` **Usage:** ```python theme={null} obs = get_observability() async with obs.task_context("AUTO_CLOSE", "agent-123", "Close tickets"): obs.log_info("Starting task", tickets_count=10) with obs.tool_execution("computer", action="click"): # Automatically tracked pass obs.record_api_call( provider="anthropic", model="claude-opus-4-5-20251101", latency=2.5, input_tokens=1500, output_tokens=500, ) ``` **Components:** | Component | Purpose | Backend | | ------------------- | ---------------------- | ---------------- | | Structured Logging | JSON logs with context | Python logging | | Distributed Tracing | Request correlation | OpenTelemetry | | Metrics | Performance tracking | Prometheus | | Event Streaming | Real-time updates | SSE/WebSocket | | Health Monitoring | System health | Circuit breakers | **Environment Variables:** ```bash theme={null} METRICS_PORT=9090 # Prometheus metrics OTLP_ENDPOINT=localhost:4317 # OpenTelemetry collector LOG_FORMAT=json # json | human | compact LOG_LEVEL=INFO # DEBUG | INFO | WARNING | ERROR ``` *** ## Infrastructure ### 12. Configuration Management (`agent/config.py`) Centralized configuration with documented rationale: **Configuration Classes:** ```python theme={null} @dataclass class ContextSettings: optimal_budget: int = 50_000 # From Anthropic research degradation_threshold: int = 100_000 # Attention starts degrading warning_threshold: int = 150_000 # Significant degradation max_context: int = 200_000 # Model limit @dataclass class ToolSettings: bash_timeout: int = 60 # Optimized from 120s typing_delay_ms: int = 8 # Characters per ms screenshot_retention: int = 5 # Most recent screenshots @dataclass class BudgetSettings: input_price_per_million: float = 3.0 # Claude Opus 4.5 output_price_per_million: float = 15.0 cached_input_price: float = 0.30 # 90% savings ``` ### 13. Exception Hierarchy (`agent/exceptions.py`) Comprehensive error handling: ``` AgentError (base) ├── RetryableError │ ├── NetworkError │ ├── RateLimitError │ ├── TimeoutError │ └── ServiceUnavailableError ├── NonRetryableError │ ├── ConfigurationError │ ├── ValidationError │ ├── SecurityError │ └── AuthenticationError ├── BudgetError │ ├── DailyBudgetExceededError │ └── TaskBudgetExceededError └── ToolError ├── ToolExecutionError ├── ToolTimeoutError └── ToolValidationError ``` ### 14. Health Monitoring (`agent/health.py`) Production health checks: ```python theme={null} class HealthChecker: async def check_anthropic_api(test_connectivity=True) -> HealthCheck async def check_system_resources() -> HealthCheck async def check_disk_space() -> HealthCheck # Circuit breaker for failing services circuit_breaker: CircuitBreaker ``` **Health States:** * `HEALTHY` - All checks passing * `DEGRADED` - Some checks failing, system operational * `UNHEALTHY` - Critical failures *** ## Dashboard Architecture ### 15. Backend (`dashboard/backend/`) FastAPI REST API with async operations: ``` dashboard/backend/ ├── app/ │ ├── main.py # FastAPI app factory │ ├── api/ # REST API routes │ │ ├── jobs.py # Job CRUD │ │ ├── templates.py # Workflow templates │ │ ├── artifacts.py # Screenshot/output storage │ │ └── metrics.py # Performance tracking │ ├── models/ # SQLAlchemy ORM models │ ├── schemas/ # Pydantic schemas │ ├── services/ # Business logic │ ├── tasks/ # Celery workers │ │ └── worker.py # Async agent execution │ └── core/ # Configuration, database └── migrations/ # Alembic schema versioning ``` **Key Technologies:** * FastAPI with CORS * SQLAlchemy async ORM * PostgreSQL database * Celery task queue * Server-Sent Events (SSE) * S3-compatible artifact storage (boto3) ### 16. Frontend (`dashboard/frontend/`) Next.js 14 application: ``` dashboard/frontend/ ├── app/ # App router pages ├── components/ # React components ├── hooks/ # Custom React hooks └── lib/ # Utilities ``` **Key Technologies:** * Next.js 14 with app router * React Query for data fetching * Tailwind CSS styling * EventSource for real-time updates *** ## Execution Flow ### Complete Request Flow ``` 1. User Command │ ▼ 2. validate_environment() ├── Check ANTHROPIC_API_KEY ├── Check DISPLAY └── Validate optional keys │ ▼ 3. get_active_agents(instruction) ├── Parse keywords: "auto-close" → AUTO_CLOSE └── Return: List[AgentConfig] │ ▼ 4. continuous_loop(agents, instruction) │ ├──────────────────────────────────────┐ │ │ ▼ ▼ 5a. run_agent(AUTO_CLOSE) 5b. run_agent(SOCIAL_MEDIA) │ │ ▼ ▼ 6. initialize_system_prompt() 6. initialize_system_prompt() ├── Fetch rules from StateSet (parallel) └── Build system prompt │ ▼ 7. sampling_loop() │ ├─── Send to Claude API ──────────────────────────┐ │ │ │ │ ▼ │ │ Claude Response │ │ ├── Text content │ │ └── Tool calls │ │ │ │ │ ▼ │ ├─── ToolExecutionGuard.execute() │ │ ├── DependencyAnalyzer │ │ ├── ParallelToolExecutor │ │ ├── StuckDetection │ │ └── Verification (optional) │ │ │ │ │ ▼ │ │ Tool Results │ │ │ │ └─────────┴───────────────────────────────────────┘ │ ▼ (loop until done) │ ▼ 8. analyze_task_completion() ├── Check completion indicators └── Return TaskStatus │ ▼ 9. send_stripe_meter_event() ├── Token usage └── Cost calculation │ ▼ 10. shutdown_gracefully() ├── Cancel all tasks └── Cleanup resources ``` *** ## Agent Types ### Supported Agents | Agent Type | Keywords | Purpose | | ------------------- | -------------------------- | ------------------------------ | | AUTO\_CLOSE | "auto-close", "ticket" | Close resolved support tickets | | SOCIAL\_MEDIA | "social media", "moderate" | Content moderation | | LINKEDIN\_MESSENGER | "linkedin", "outreach" | LinkedIn automation | | SLACK\_SUPPORT | "slack", "support" | Slack support automation | | SHOPIFY | "shopify", "e-commerce" | E-commerce management | | ONBOARDING | "onboarding", "setup" | User onboarding | | STATESET\_AGENTIC | "stateset", "custom" | Custom tasks | ### Agent Configuration ```python theme={null} @dataclass class AgentConfig: org_id: str # Organization identifier agent_id: str # Unique agent identifier description: str # Agent purpose capabilities: List[str] # What the agent can do stripe_customer_id: str # Billing identifier ``` *** ## Security Architecture ### API Key Management * All keys via environment variables * Validation on startup * No key transmission to external services ### Tool Safety * Directory traversal prevention in EditTool * Prompt injection protection in MemoryTool * Pre-execution validation via ToolExecutionGuard * Agent memory isolation (per agent\_id) ### Sandbox Execution * Tools run in controlled environment * File system access limited by permissions * Network access controlled by system *** ## Performance Characteristics ### Benchmarks | Metric | Value | Notes | | ---------------- | -------- | ------------------------ | | Tokens/task | 7,500 | 95% reduction from 150k | | Cost/task | \$0.11 | 95% savings from \$2.25 | | Task duration | 30s | 33% faster with parallel | | Parallel speedup | 30-50% | On multi-tool tasks | | Typing speed | 8ms/char | Optimized from 50ms | | Bash timeout | 60s | Optimized from 120s | ### Cost Breakdown | Operation | Price | | ------------- | ----------------------- | | Input tokens | \$3.00/1M | | Output tokens | \$15.00/1M | | Cached input | \$0.30/1M (90% savings) | *** ## File Organization ``` stateset-computer-use-agent/ ├── main.py # Entry point, orchestration ├── agent/ │ ├── loop.py # Core sampling loop │ ├── parallel_executor.py # Parallel tool execution │ ├── context_optimizer.py # Context engineering │ ├── tool_guard.py # Safety checks │ ├── stuck_detection.py # Loop prevention │ ├── verification.py # Visual verification │ ├── subagent.py # Subagent spawning │ ├── mcp_client.py # MCP integration │ ├── structured_output.py # JSON schema validation │ ├── checkpoint.py # State persistence │ ├── metrics.py # Performance tracking │ ├── skill_manager.py # Skill system │ ├── config.py # Configuration │ ├── exceptions.py # Error hierarchy │ ├── logging_config.py # Structured logging │ ├── health.py # Health monitoring │ ├── observability/ # Unified observability │ │ ├── unified.py │ │ ├── tracing.py │ │ └── metrics.py │ └── tools/ # Tool implementations │ ├── base.py │ ├── collection.py │ ├── computer.py │ ├── bash.py │ ├── edit.py │ ├── memory.py │ ├── agi.py │ └── groups.py ├── dashboard/ │ ├── backend/ # FastAPI + Celery │ └── frontend/ # Next.js 14 ├── start-*.sh # Launch scripts └── test_*.py # Test suites ``` *** ## Extension Points ### Adding New Agents 1. Define AgentConfig in `AGENT_CONFIGS` 2. Add keyword detection in `get_active_agents()` 3. Create completion indicators in `analyze_task_completion()` ### Adding New Tools 1. Inherit from `BaseAnthropicTool` 2. Implement `__call__` returning `ToolResult` 3. Add to version groups in `agent/tools/groups.py` 4. Update tool traits if cacheable/read-only ### Adding MCP Servers ```python theme={null} await mcp_manager.add_server("custom-server", { "command": "npx", "args": ["-y", "@my/custom-mcp-server"], "env": {"API_KEY": "..."} }) ``` *** ## Quick Reference ### Environment Variables ```bash theme={null} # Required ANTHROPIC_API_KEY=sk-ant-api03-... DISPLAY=:1 # Optional STRIPE_API_KEY=sk_live_... WORKSPACE_PATH=/path/to/workspace AGENT_FAST_MODE=1 # Skip verification METRICS_PORT=9090 # Prometheus OTLP_ENDPOINT=localhost:4317 # OpenTelemetry LOG_FORMAT=json # json | human | compact LOG_LEVEL=INFO # DEBUG | INFO | WARNING | ERROR ``` ### Common Commands ```bash theme={null} # Run agents python main.py "auto-close tickets" python main.py "auto-close and social media" # Parallel # With options python main.py --effort medium "task" python main.py --tool-search regex --defer-tool agi_agent "task" # Dashboard cd dashboard && docker compose up -d ``` *** This architecture provides a scalable, maintainable foundation for computer use automation with AI agents, implementing production-grade patterns for reliability, observability, and cost optimization. # Developer Guide Source: https://docs.stateset.com/development Everything you need to build agentic commerce with StateSet # Build the Future of Commerce Welcome to the StateSet Documentation. Whether you're building your first AI agent or architecting a complex autonomous system, this guide will help you harness the full power of StateSet's platform. **New to StateSet?** Start with our [Quickstart Guide](/quickstart) to deploy your first agent, then come back here to dive deeper. ## Why Developers Love StateSet Built with Rust, Axum, GraphQL, and cutting-edge AI models Clean APIs, comprehensive SDKs for 11 languages, and documentation that actually helps From intent to outcome in minutes, not months ## Getting Started ### Prerequisites Before you begin, ensure you have: * **Node.js 22+** or **Python 3.8+** * **TypeScript**: For better developer experience - **Git**: For version control - **Docker**: For local development ### Installation ```bash npm theme={null} npm install -g @stateset/cli npm install @stateset/embedded ``` ```bash python theme={null} pip install stateset-embedded ``` ## Core Concepts ### 1. Agents: Your AI Workforce Agents are autonomous AI entities that can understand, decide, and act on behalf of your business. Each agent has: * **Role & Personality**: Define its behavior and communication style * **Capabilities**: Specific skills like order management, support, or analytics * **Knowledge Base**: Access to your business documents and processes * **Integrations**: Connections to external systems and APIs ```typescript theme={null} const agent = await client.agents.create({ name: "Support Specialist", role: "Senior Customer Success Manager", personality: { traits: ["empathetic", "solution-oriented", "professional"], tone: "friendly yet professional", }, capabilities: ["order_management", "refund_processing", "technical_support"], knowledge_bases: ["product_docs", "support_playbook"], }); ``` ### 2. Sandboxes: Orchestrating Agentic Operations Sandboxes are isolated environments that allow you to run your AI Agents in a safe and controlled manner. They provide: * **Secure Execution**: Run code and tools without affecting production * **Resource Management**: Control compute and memory allocation * **Network Isolation**: Isolate external calls and webhooks * **State Management**: Track agent decisions and outcomes **🚀 Ship faster with StateSet Sandbox** Get free sandbox credits when you [sign up today](https://sandbox.stateset.app). No credit card required. ### 3. Workflows: Orchestrating Multi-Step Operations Workflows handle long-running processes that span multiple steps and systems: ```typescript theme={null} const workflow = await client.workflows.create({ name: "Order Fulfillment", trigger: { event: "order.created" }, steps: [ { name: "Check Inventory", action: "inventory.check", timeout: "30s", }, { name: "Process Payment", action: "payment.process", retry: { max: 3 }, }, { name: "Create Shipment", action: "shipping.create_label", }, { name: "Notify Customer", action: "customer.notify", template: "order_confirmation", }, ], }); ``` ### 4. Events: Real-Time Business Signals StateSet emits events for every meaningful state change: ```typescript theme={null} // Subscribe to order events client.events.subscribe({ events: ["order.*"], handler: async (event) => { switch (event.type) { case "order.created": await handleNewOrder(event.data); break; case "order.paid": await triggerFulfillment(event.data); break; case "order.shipped": await sendTrackingUpdate(event.data); break; } }, }); ``` ## Essential SDK Methods ### Injecting Messages Send messages to agents or conversations: ```typescript theme={null} await client.messages.send({ to: "agent_id", body: "Customer is asking about order status", context: { orderId: "ord_12345", customerId: "cust_67890", }, }); ``` ### Handling Conversations Manage multi-turn conversations: ```typescript theme={null} const conversation = await client.conversations.create({ participants: [ { id: "agent_id", role: "agent" }, { id: "customer_id", role: "customer" }, ], metadata: { source: "web", campaign: "summer_sale", }, }); // Stream responses const stream = await conversation.stream(); for await (const message of stream) { console.log("Agent says:", message.content); } ``` ### Managing Knowledge Base Upload and query documents: ```typescript theme={null} // Create knowledge base const kb = await client.knowledgeBases.create({ name: "Product Documentation", agent_id: "agent_id", }); // Upload documents await kb.uploadDocument("./product-guide.pdf"); await kb.uploadDocument("./faq.md"); // Query knowledge const results = await kb.query({ question: "What is your return policy?", top_k: 3, }); ``` ## Architecture Patterns ### Pattern 1: Agent + Integration Connect agents to your existing systems: ```typescript theme={null} await agent.addIntegration({ type: "webhook", name: "order_lookup", endpoint: "https://api.yourstore.com/orders", authentication: { type: "api_key", key: process.env.STORE_API_KEY, }, operations: ["read", "update"], }); ``` ### Pattern 2: Event-Driven Workflow React to business events automatically: ```typescript theme={null} client.events.subscribe({ events: ["inventory.low_stock"], handler: async (event) => { // Trigger restocking await client.workflows.trigger("restock", { sku: event.data.sku, quantity: event.data.reorder_point * 2, }); // Notify procurement team await client.notifications.send({ to: "procurement_team", message: `Low stock alert for ${event.data.sku}`, }); }, }); ``` ### Pattern 3: Multi-Agent Orchestration Coordinate multiple specialized agents: ```typescript theme={null} // Create specialized agents const salesAgent = await client.agents.create({ name: "Sales Specialist", role: "Sales Representative", capabilities: ["lead_qualification", "product_recommendation", "pricing"], }); const supportAgent = await client.agents.create({ name: "Support Specialist", role: "Customer Support", capabilities: ["troubleshooting", "returns", "faq"], }); // Route based on intent async function routeIntent(customerMessage) { const intent = await client.intents.detect({ message: customerMessage, }); if (intent.category === "sales") { return salesAgent; } else if (intent.category === "support") { return supportAgent; } else { return await escalateToHuman(); } } ``` ## Error Handling Best Practices ### Graceful Degradation ```typescript theme={null} try { const result = await client.agents.execute({ agentId: "agent_id", action: "process_order", data: orderData, }); } catch (error) { if (error.code === "TIMEOUT") { // Retry with exponential backoff await retry(orderData, { maxAttempts: 3, backoff: "exponential" }); } else if (error.code === "RATE_LIMIT") { // Queue for later processing await queue.push({ action: "process_order", data: orderData }); } else { // Log and escalate logger.error("Agent execution failed", { error, orderData }); await notifyTeam({ error, orderData }); } } ``` ### Retry Strategies ```typescript theme={null} async function withRetry(operation, options = {}) { const { maxAttempts = 3, backoff = "exponential", initialDelay = 1000, } = options; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await operation(); } catch (error) { if (attempt === maxAttempts || !isRetryable(error)) { throw error; } const delay = backoff === "exponential" ? initialDelay * Math.pow(2, attempt - 1) : initialDelay * attempt; await sleep(delay); } } } ``` ## Performance Optimization ### Batch Operations ```typescript theme={null} // Process multiple items efficiently const orders = await client.orders.list({ limit: 100 }); const results = await Promise.allSettled( orders.map((order) => client.agent.execute({ agentId: "agent_id", action: "process_order", data: order, }), ), ); // Handle results results.forEach((result) => { if (result.status === "fulfilled") { logger.info("Order processed", result.value); } else { logger.error("Order failed", result.reason); } }); ``` ### Caching Strategy ```typescript theme={null} import { LRUCache } from "lru-cache"; const cache = new LRUCache({ max: 1000, ttl: 1000 * 60 * 15, // 15 minutes }); async function getCachedData(key, fetcher) { const cached = cache.get(key); if (cached) return cached; const data = await fetcher(); cache.set(key, data); return data; } ``` ## Testing ### Unit Testing Agents ```typescript theme={null} describe("Order Agent", () => { it("should process new orders", async () => { const mockOrder = { items: [{ sku: "prod_123", quantity: 2 }], total: 99.99, }; const result = await agent.process(mockOrder); expect(result.status).toBe("success"); expect(result.orderId).toBeDefined(); }); it("should handle low inventory", async () => { const mockOrder = { items: [{ sku: "out_of_stock_123", quantity: 10 }], }; const result = await agent.process(mockOrder); expect(result.status).toBe("failed"); expect(result.error).toContain("insufficient inventory"); }); }); ``` ### Integration Testing ```typescript theme={null} describe("Order Workflow Integration", () => { it("should fulfill order end-to-end", async () => { // Create order const order = await client.orders.create({ customer_id: "test_customer", items: [{ sku: "test_product", quantity: 1 }], }); // Wait for workflow completion await client.events.wait({ event: "order.fulfilled", orderId: order.id, timeout: 30000, }); // Verify fulfillment const fulfillment = await client.fulfillments.get(order.id); expect(fulfillment.tracking_number).toBeDefined(); }); }); ``` ## Monitoring & Debugging ### Enable Debug Logging ```typescript theme={null} const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, logger: { level: "debug", format: "json", }, }); ``` ### Track Agent Performance ```typescript theme={null} const metrics = await client.agents.getMetrics({ agent_id: "agent_id", period: "24h", metrics: [ "messages_sent", "response_time", "resolution_rate", "customer_satisfaction", ], }); console.log("Average response time:", metrics.response_time.avg); console.log("Resolution rate:", metrics.resolution_rate * 100, "%"); ``` ## Next Steps Complete API documentation with all endpoints and parameters Language-specific guides for Node.js, Python, Ruby, and more Production-ready patterns and security considerations *** ### Ready to Build? Start with the [Quickstart Guide](/quickstart) or explore the [API Reference](/api-reference/introduction) to begin integrating StateSet into your application. # Global Commerce Architecture Source: https://docs.stateset.com/global-commerce-architecture Technical architecture powering the world's commerce infrastructure with StateSet # Global Commerce Architecture: Building the World's Financial Operating System StateSet Commerce Network represents a fundamental reimagining of how global commerce operates. This document outlines the technical architecture, design principles, and infrastructure that enables StateSet to serve as the backend for the \$100+ trillion global economy. ## 🏗️ Architecture Overview ### High-Level System Design ```mermaid theme={null} graph TB subgraph "User Layer" A[Mobile Apps] B[Web Applications] C[Enterprise ERPs] D[Smart Agents] end subgraph "API Gateway Layer" E[REST APIs] F[GraphQL APIs] G[gRPC APIs] H[WebSocket APIs] end subgraph "Service Layer" I[Orders Service] J[Finance Service] K[Compliance Service] L[Global Commerce Service] M[Identity Service] N[Analytics Service] end subgraph "Blockchain Layer" O[StateSet Cosmos Chain] P[Smart Contracts] Q[IBC Protocol] R[Consensus Engine] end subgraph "Infrastructure Layer" S[Multi-Region Deployment] T[CDN & Caching] U[Monitoring & Observability] V[Security & Compliance] end subgraph "External Integrations" W[Banking Partners] X[Compliance Providers] Y[Logistics Networks] Z[Government Systems] end A --> E B --> F C --> G D --> H E --> I F --> J G --> K H --> L I --> O J --> P K --> Q L --> R O --> S P --> T Q --> U R --> V S --> W T --> X U --> Y V --> Z ``` ## 🌐 Global Infrastructure ### Multi-Region Deployment StateSet operates a globally distributed infrastructure to ensure low latency and high availability for commerce operations worldwide. #### Regional Architecture ```mermaid theme={null} graph TB subgraph "Americas" A1[US East - Virginia] A2[US West - California] A3[Canada - Toronto] A4[Brazil - São Paulo] end subgraph "Europe/Middle East/Africa" E1[Ireland - Dublin] E2[Germany - Frankfurt] E3[UK - London] E4[UAE - Dubai] E5[South Africa - Cape Town] end subgraph "Asia Pacific" P1[Singapore] P2[Japan - Tokyo] P3[Australia - Sydney] P4[India - Mumbai] P5[South Korea - Seoul] end subgraph "Cross-Region Services" CR1[Global Load Balancer] CR2[Cross-Region Replication] CR3[Global CDN] CR4[Distributed Consensus] end A1 --> CR1 A2 --> CR1 E1 --> CR1 P1 --> CR1 CR1 --> CR2 CR2 --> CR3 CR3 --> CR4 ``` #### Performance Characteristics by Region | Region | Latency (p95) | Throughput | Availability | Validators | | -------------- | ------------- | ---------- | ------------ | ---------- | | North America | 45ms | 15,000 TPS | 99.99% | 35 | | Europe | 38ms | 12,000 TPS | 99.99% | 28 | | Asia Pacific | 52ms | 18,000 TPS | 99.98% | 37 | | Global Average | 45ms | 45,000 TPS | 99.99% | 100+ | ### Network Topology ```typescript theme={null} // Global network configuration const networkTopology = { consensus: { engine: 'Tendermint BFT', validators: 100, block_time: '1s', finality: 'instant' }, regions: [ { name: 'us-east-1', validators: 35, rpc_endpoints: [ 'https://rpc-us-east.stateset.network', 'https://rpc-backup-us-east.stateset.network' ], api_endpoints: [ 'https://api-us-east.stateset.network' ] }, { name: 'eu-west-1', validators: 28, rpc_endpoints: [ 'https://rpc-eu-west.stateset.network', 'https://rpc-backup-eu-west.stateset.network' ], api_endpoints: [ 'https://api-eu-west.stateset.network' ] }, { name: 'ap-southeast-1', validators: 37, rpc_endpoints: [ 'https://rpc-ap-southeast.stateset.network', 'https://rpc-backup-ap-southeast.stateset.network' ], api_endpoints: [ 'https://api-ap-southeast.stateset.network' ] } ], cross_region: { replication: 'synchronous', backup_strategy: '3-2-1', disaster_recovery: 'automated' } }; ``` ## ⚡ Scalability Architecture ### Horizontal Scaling Strategy StateSet employs multiple scaling techniques to handle global commerce volumes: #### 1. Sharding Strategy ```mermaid theme={null} graph TB subgraph "Order Sharding" OS1[Shard 1: Americas Orders] OS2[Shard 2: EMEA Orders] OS3[Shard 3: APAC Orders] OS4[Shard 4: High-Volume Merchants] end subgraph "Geographic Sharding" GS1[North America] GS2[Europe] GS3[Asia Pacific] GS4[Global Merchants] end subgraph "Functional Sharding" FS1[Payments Processing] FS2[Order Management] FS3[Compliance Checking] FS4[Analytics Pipeline] end LB[Global Load Balancer] LB --> OS1 LB --> OS2 LB --> OS3 LB --> OS4 OS1 --> GS1 OS2 --> GS2 OS3 --> GS3 OS4 --> GS4 GS1 --> FS1 GS2 --> FS2 GS3 --> FS3 GS4 --> FS4 ``` #### 2. Auto-Scaling Configuration ```yaml theme={null} # Kubernetes auto-scaling configuration apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: stateset-orders-api spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: orders-api minReplicas: 10 maxReplicas: 1000 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 - type: Pods pods: metric: name: requests_per_second target: type: AverageValue averageValue: "1000" behavior: scaleUp: stabilizationWindowSeconds: 30 policies: - type: Percent value: 100 periodSeconds: 15 scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 ``` ### Performance Optimization #### Caching Strategy ```mermaid theme={null} graph TB subgraph "L1 Cache - Application" L1A[In-Memory Cache] L1B[Application State] end subgraph "L2 Cache - Regional" L2A[Redis Cluster] L2B[Regional Data] end subgraph "L3 Cache - Global" L3A[CDN Edge Cache] L3B[Static Assets] end subgraph "L4 Cache - Database" L4A[Query Result Cache] L4B[Computed Views] end Request[API Request] --> L1A L1A --> L2A L2A --> L3A L3A --> L4A L4A --> DB[Database] DB --> L4A L4A --> L3A L3A --> L2A L2A --> L1A L1A --> Response[API Response] ``` #### Database Architecture ```typescript theme={null} // Multi-tier database strategy const databaseArchitecture = { // Hot data - frequent access hot_tier: { technology: 'CockroachDB', replication: 'multi_region', sla: '99.99%', use_cases: ['active_orders', 'real_time_payments'] }, // Warm data - moderate access warm_tier: { technology: 'PostgreSQL', sharding: 'by_time_range', backup: 'continuous', use_cases: ['order_history', 'analytics'] }, // Cold data - archival cold_tier: { technology: 'Amazon S3 + Glacier', encryption: 'at_rest', retention: '7_years', use_cases: ['compliance_records', 'audit_trails'] }, // Search and analytics search_tier: { technology: 'Elasticsearch', indices: 'time_based', analytics: 'real_time', use_cases: ['order_search', 'business_intelligence'] } }; ``` ## 🔐 Security Architecture ### Zero-Trust Security Model StateSet implements a comprehensive zero-trust security architecture: ```mermaid theme={null} graph TB subgraph "Identity & Access" IA1[Multi-Factor Authentication] IA2[Role-Based Access Control] IA3[Attribute-Based Access Control] IA4[Zero-Trust Network Access] end subgraph "Data Protection" DP1[Encryption at Rest] DP2[Encryption in Transit] DP3[Field-Level Encryption] DP4[Key Management HSM] end subgraph "Network Security" NS1[Web Application Firewall] NS2[DDoS Protection] NS3[API Rate Limiting] NS4[VPC Isolation] end subgraph "Compliance & Monitoring" CM1[SIEM/SOAR] CM2[Compliance Monitoring] CM3[Threat Detection] CM4[Incident Response] end User[API User] --> IA1 IA1 --> IA2 IA2 --> IA3 IA3 --> IA4 IA4 --> DP1 DP1 --> DP2 DP2 --> DP3 DP3 --> DP4 DP4 --> NS1 NS1 --> NS2 NS2 --> NS3 NS3 --> NS4 NS4 --> CM1 CM1 --> CM2 CM2 --> CM3 CM3 --> CM4 ``` ### Cryptographic Standards ```typescript theme={null} // Encryption configuration const securityConfig = { encryption: { algorithms: { symmetric: 'AES-256-GCM', asymmetric: 'RSA-4096, ECDSA-P384', hashing: 'SHA-3-256', signatures: 'Ed25519' }, key_management: { provider: 'AWS KMS + Azure Key Vault', rotation: 'automatic_90_days', backup: 'multi_region', access_logging: true }, data_classification: { public: 'no_encryption', internal: 'AES-256', confidential: 'AES-256 + field_level', restricted: 'AES-256 + HSM + multi_signature' } }, network_security: { tls_version: '1.3', cipher_suites: ['TLS_AES_256_GCM_SHA384'], hsts: true, certificate_transparency: true, ocsp_stapling: true } }; ``` ## 🔗 Blockchain Integration ### StateSet Cosmos Chain Architecture ```mermaid theme={null} graph TB subgraph "Application Layer" AL1[Orders Module] AL2[Finance Module] AL3[Compliance Module] AL4[Identity Module] end subgraph "Cosmos SDK Framework" CS1[ABCI Interface] CS2[State Machine] CS3[Transaction Pool] CS4[Module Manager] end subgraph "Tendermint Core" TC1[Consensus Engine] TC2[P2P Networking] TC3[Block Production] TC4[State Synchronization] end subgraph "Storage Layer" SL1[Merkle Tree State] SL2[Block Store] SL3[Evidence Store] SL4[State Snapshots] end AL1 --> CS1 AL2 --> CS2 AL3 --> CS3 AL4 --> CS4 CS1 --> TC1 CS2 --> TC2 CS3 --> TC3 CS4 --> TC4 TC1 --> SL1 TC2 --> SL2 TC3 --> SL3 TC4 --> SL4 ``` ### Smart Contract Platform ```rust theme={null} // StateSet smart contract structure use cosmwasm_std::{ DepsMut, Env, MessageInfo, Response, Result, Uint128, Addr, Binary }; #[derive(Clone, Debug, PartialEq)] pub struct GlobalCommerceContract { // Core commerce functionality pub order_management: OrderManager, pub payment_processing: PaymentProcessor, pub compliance_engine: ComplianceEngine, pub cross_border_handler: CrossBorderHandler, } impl GlobalCommerceContract { pub fn execute_order_flow( &self, deps: DepsMut, env: Env, info: MessageInfo, order: Order, ) -> Result { // 1. Validate order self.order_management.validate_order(&order)?; // 2. Check compliance self.compliance_engine.screen_transaction(&order)?; // 3. Process payment let payment = self.payment_processing.process_usdc_payment( &order.payment_info )?; // 4. Handle cross-border requirements if order.is_cross_border() { self.cross_border_handler.apply_regulations(&order)?; } // 5. Update state and emit events Ok(Response::new() .add_attribute("action", "order_executed") .add_attribute("order_id", order.id) .add_attribute("payment_id", payment.id)) } } ``` ### IBC Interoperability ```mermaid theme={null} graph LR subgraph "StateSet Chain" SS[StateSet Commerce] SSRP[Relayer Processes] end subgraph "Connected Chains" OS[Osmosis DEX] CH[Cosmos Hub] JU[Juno] AX[Axelar] end subgraph "External Networks" ETH[Ethereum] BSC[Binance Smart Chain] POLY[Polygon] end SS <--> SSRP SSRP <--> OS SSRP <--> CH SSRP <--> JU SSRP <--> AX AX <--> ETH AX <--> BSC AX <--> POLY ``` ## 📊 Data Architecture ### Event-Driven Architecture StateSet uses an event-driven architecture to ensure real-time responsiveness and system decoupling: ```mermaid theme={null} graph TB subgraph "Event Sources" ES1[Order Events] ES2[Payment Events] ES3[Compliance Events] ES4[External API Events] end subgraph "Event Processing" EP1[Event Bus - Apache Kafka] EP2[Stream Processing - Apache Flink] EP3[Event Store - EventStore DB] end subgraph "Event Consumers" EC1[Real-time Analytics] EC2[Notification Service] EC3[Audit Logging] EC4[External Webhooks] EC5[AI/ML Pipeline] end ES1 --> EP1 ES2 --> EP1 ES3 --> EP1 ES4 --> EP1 EP1 --> EP2 EP2 --> EP3 EP3 --> EC1 EP3 --> EC2 EP3 --> EC3 EP3 --> EC4 EP3 --> EC5 ``` ### Real-Time Data Pipeline ```yaml theme={null} # Apache Kafka cluster configuration kafka_cluster: brokers: 9 partitions_per_topic: 12 replication_factor: 3 retention_policy: "7_days" topics: - name: "orders" partitions: 12 cleanup_policy: "compact" - name: "payments" partitions: 12 cleanup_policy: "delete" - name: "compliance_events" partitions: 6 cleanup_policy: "compact" - name: "cross_border_transactions" partitions: 8 cleanup_policy: "delete" # Stream processing configuration flink_jobs: - name: "real_time_analytics" parallelism: 8 checkpointing: "exactly_once" state_backend: "rocksdb" - name: "fraud_detection" parallelism: 4 machine_learning: true model_serving: "tensorflow_extended" - name: "compliance_monitoring" parallelism: 6 external_apis: ["sanctions_lists", "export_controls"] ``` ## 🔍 Observability & Monitoring ### Comprehensive Monitoring Stack ```mermaid theme={null} graph TB subgraph "Metrics Collection" MC1[Prometheus] MC2[Grafana] MC3[Custom Metrics] end subgraph "Logging & Tracing" LT1[ELK Stack] LT2[Jaeger Tracing] LT3[OpenTelemetry] end subgraph "Alerting & Incident Response" AI1[PagerDuty] AI2[OpsGenie] AI3[Slack Integration] end subgraph "Business Intelligence" BI1[Data Warehouse] BI2[Business Dashboards] BI3[ML Analytics] end Apps[Applications] --> MC1 Apps --> LT1 MC1 --> MC2 MC2 --> MC3 LT1 --> LT2 LT2 --> LT3 MC3 --> AI1 LT3 --> AI2 AI1 --> AI3 MC3 --> BI1 BI1 --> BI2 BI2 --> BI3 ``` ### Key Performance Indicators (KPIs) ```typescript theme={null} // System KPIs dashboard configuration const systemKPIs = { availability: { target: 99.99, measurement: 'uptime_percentage', alerting: 'below_99.95' }, performance: { api_latency_p95: '< 100ms', api_latency_p99: '< 500ms', throughput: '> 10000 rps', error_rate: '< 0.1%' }, business_metrics: { orders_per_second: 'real_time', payment_success_rate: '> 99.5%', cross_border_completion: '> 95%', compliance_automation: '> 99%' }, security: { failed_auth_attempts: '< 1000/hour', api_abuse_detection: 'real_time', compliance_violations: '0', security_incidents: '0' } }; ``` ## 🌟 Advanced Capabilities ### AI/ML Integration ```mermaid theme={null} graph TB subgraph "Data Sources" DS1[Transaction Data] DS2[Market Data] DS3[Compliance Data] DS4[External Signals] end subgraph "ML Pipeline" ML1[Data Preprocessing] ML2[Feature Engineering] ML3[Model Training] ML4[Model Serving] end subgraph "AI Applications" AI1[Fraud Detection] AI2[Risk Assessment] AI3[Price Optimization] AI4[Demand Forecasting] end DS1 --> ML1 DS2 --> ML1 DS3 --> ML1 DS4 --> ML1 ML1 --> ML2 ML2 --> ML3 ML3 --> ML4 ML4 --> AI1 ML4 --> AI2 ML4 --> AI3 ML4 --> AI4 ``` ### Edge Computing Integration ```typescript theme={null} // Edge computing configuration const edgeDeployment = { edge_locations: [ { region: 'us-east-1-edge', capabilities: ['order_validation', 'payment_processing'], latency_target: '< 10ms', failover: 'regional_datacenter' }, { region: 'eu-west-1-edge', capabilities: ['compliance_checking', 'currency_conversion'], latency_target: '< 15ms', failover: 'regional_datacenter' } ], edge_services: { order_service: { cache_size: '10GB', cache_ttl: '60s', offline_capability: true }, payment_service: { pci_compliance: true, hsm_integration: true, token_caching: true } } }; ``` ## 🚀 Deployment & DevOps ### GitOps Deployment Pipeline ```mermaid theme={null} graph LR DEV[Development] --> TEST[Testing] TEST --> STAGE[Staging] STAGE --> PROD[Production] subgraph "CI/CD Pipeline" CI1[Code Commit] CI2[Unit Tests] CI3[Integration Tests] CI4[Security Scans] CI5[Performance Tests] CI6[Deployment] end CI1 --> CI2 CI2 --> CI3 CI3 --> CI4 CI4 --> CI5 CI5 --> CI6 subgraph "Infrastructure as Code" IAC1[Terraform] IAC2[Ansible] IAC3[Kubernetes] IAC4[Helm Charts] end CI6 --> IAC1 IAC1 --> IAC2 IAC2 --> IAC3 IAC3 --> IAC4 ``` ### Blue-Green Deployment Strategy ```yaml theme={null} # Blue-Green deployment configuration deployment_strategy: type: "blue_green" blue_environment: version: "v1.2.3" traffic_percentage: 100 health_check: "passing" green_environment: version: "v1.2.4" traffic_percentage: 0 deployment_status: "ready" cutover_strategy: validation_tests: ["smoke_tests", "load_tests"] rollback_criteria: ["error_rate > 0.5%", "latency_p95 > 200ms"] traffic_shifting: "instant" rollback_time: "< 30s" ``` ## 📈 Capacity Planning ### Growth Projections ```typescript theme={null} // Capacity planning model const capacityModel = { current_metrics: { daily_transactions: 1_000_000, peak_tps: 5_000, data_growth_tb_per_month: 2.5, global_merchants: 50_000 }, projected_growth: { "2024_q4": { daily_transactions: 5_000_000, peak_tps: 25_000, data_growth_tb_per_month: 12.5, global_merchants: 250_000 }, "2025_q4": { daily_transactions: 25_000_000, peak_tps: 125_000, data_growth_tb_per_month: 62.5, global_merchants: 1_250_000 }, "2026_q4": { daily_transactions: 100_000_000, peak_tps: 500_000, data_growth_tb_per_month: 250, global_merchants: 5_000_000 } }, infrastructure_scaling: { auto_scaling: true, predictive_scaling: true, cost_optimization: true, reserved_capacity: "20%_buffer" } }; ``` ## 🔄 Disaster Recovery ### Business Continuity Plan ```mermaid theme={null} graph TB subgraph "Primary Region" PR1[Primary Data Center] PR2[Active Services] PR3[Real-time Replication] end subgraph "Secondary Region" SR1[Secondary Data Center] SR2[Standby Services] SR3[Sync Replication] end subgraph "Tertiary Region" TR1[Disaster Recovery Site] TR2[Cold Standby] TR3[Async Replication] end subgraph "Recovery Procedures" RP1[Automated Failover] RP2[Health Monitoring] RP3[Data Validation] RP4[Service Restoration] end PR1 --> PR3 PR3 --> SR3 SR3 --> TR3 PR2 --> RP2 RP2 --> RP1 RP1 --> SR2 SR2 --> RP3 RP3 --> RP4 ``` ### Recovery Time Objectives (RTO) & Recovery Point Objectives (RPO) | Service Tier | RTO Target | RPO Target | Recovery Strategy | | -------------------- | ------------- | ------------- | ---------------------------------- | | Critical (Payments) | \< 30 seconds | \< 1 second | Hot standby + Auto failover | | Important (Orders) | \< 5 minutes | \< 30 seconds | Warm standby + Manual failover | | Standard (Analytics) | \< 1 hour | \< 15 minutes | Cold standby + Restore from backup | ## 🌍 Global Compliance Architecture ### Regulatory Framework ```mermaid theme={null} graph TB subgraph "Global Regulations" GR1[GDPR - Europe] GR2[CCPA - California] GR3[SOX - US Public Companies] GR4[PCI DSS - Payment Processing] end subgraph "Financial Regulations" FR1[BSA/AML - US] FR2[MiFID II - Europe] FR3[FINTRAC - Canada] FR4[AUSTRAC - Australia] end subgraph "Trade Regulations" TR1[EAR - Export Administration] TR2[ITAR - Defense Trade] TR3[OFAC - Sanctions] TR4[Customs Regulations] end subgraph "Compliance Engine" CE1[Real-time Screening] CE2[Automated Reporting] CE3[Audit Trails] CE4[Policy Enforcement] end GR1 --> CE1 GR2 --> CE1 FR1 --> CE2 FR2 --> CE2 TR1 --> CE3 TR2 --> CE3 GR3 --> CE4 GR4 --> CE4 ``` ## 🎯 Performance Benchmarks ### Load Testing Results | Test Scenario | Peak Load | Response Time | Success Rate | Notes | | ------------------- | ---------------- | ------------- | ------------ | ----------------------- | | Order Creation | 50,000 TPS | 45ms (p95) | 99.99% | Global distribution | | Payment Processing | 25,000 TPS | 85ms (p95) | 99.95% | Including compliance | | Cross-border Orders | 15,000 TPS | 125ms (p95) | 99.90% | Multi-region validation | | Real-time Analytics | 100,000 events/s | 15ms (p95) | 99.99% | Stream processing | ### Stress Testing Results ```typescript theme={null} // Stress test configuration and results const stressTestResults = { test_duration: "4_hours", peak_concurrent_users: 100000, geographical_distribution: "global", results: { maximum_sustained_tps: 75000, peak_burst_tps: 125000, memory_usage_peak: "85%", cpu_usage_peak: "78%", database_connections_peak: 5000, failure_points: { database_connection_pool: "at_5500_connections", memory_exhaustion: "none_observed", cpu_saturation: "none_observed", network_bandwidth: "none_observed" }, auto_scaling_performance: { scale_up_time: "45_seconds", scale_down_time: "8_minutes", efficiency: "98.5%" } } }; ``` ## 🔮 Future Architecture Evolution ### Next-Generation Capabilities ```mermaid theme={null} graph TB subgraph "2024 Roadmap" R1[Quantum-Resistant Cryptography] R2[Advanced AI Integration] R3[IoT Supply Chain Integration] R4[CBDCs Integration] end subgraph "2025+ Vision" V1[Autonomous Commerce Agents] V2[Predictive Trade Finance] V3[Zero-Knowledge Compliance] V4[Interplanetary Commerce Ready] end R1 --> V1 R2 --> V2 R3 --> V3 R4 --> V4 ``` *** This architecture represents the foundation for enabling the next era of global commerce - where any business, anywhere in the world, can participate in the global economy with the same ease as making a local transaction. StateSet Commerce Network is not just building an API; we're building the infrastructure for the future of human commerce. *Ready to build on the world's commerce infrastructure? [Get started with our APIs →](https://docs.stateset.network)* # Agent Objectives, Goals, Metrics & Rewards Guide Source: https://docs.stateset.com/guides/agent-objectives-guide Comprehensive guide for implementing agent objectives, goals, metrics, and rewards in your AI agent ecosystem # Agent Objectives, Goals, Metrics & Rewards Guide ## Overview This guide provides a comprehensive framework for implementing agent objectives, goals, metrics, and rewards in your AI agent ecosystem. Based on the Agentic Commerce Platform dashboard, this system combines goal-setting methodologies, performance metrics, and reinforcement learning principles to create a powerful agent optimization framework. ## Table of Contents 1. [Strategic Goals & Objectives](#strategic-goals--objectives) 2. [Key Performance Metrics](#key-performance-metrics) 3. [Reward System Architecture](#reward-system-architecture) 4. [Reinforcement Learning Integration](#reinforcement-learning-integration) 5. [Implementation Guide](#implementation-guide) 6. [Best Practices](#best-practices) ## Strategic Goals & Objectives ### Goal Definition Framework Goals in the agent ecosystem follow a structured approach with clear, measurable outcomes: ```typescript theme={null} interface AgentGoal { id: number; title: string; description: string; targetDate: string; priority: 'high' | 'medium' | 'low'; owner: string; agent: string; successMetrics: SuccessMetric[]; estimatedROI: string; businessImpact: string; status: 'active' | 'planning' | 'completed'; progress: number; } interface SuccessMetric { metric: string; current: number; target: number; unit: string; } ``` ### Example Goals #### 1. First-Call Resolution Excellence * **Objective**: Achieve 95% first-call resolution rate * **Current State**: 82% resolution rate * **Target Metrics**: * First-call resolution: 82% → 95% * Customer satisfaction: 4.2/5 → 4.6/5 * Average handle time: 8.5 min → 7.0 min * **ROI**: \$150K annually * **Business Impact**: Directly affects customer satisfaction and operational efficiency #### 2. Response Time Optimization * **Objective**: Reduce response time to under 30 seconds * **Current State**: Average 65 seconds * **Target Metrics**: * Average response time: 45s → 30s * Response quality score: 8.4/10 → 8.5/10 * Throughput: 150 req/hr → 200 req/hr * **ROI**: \$85K annually * **Business Impact**: Improves user experience and system efficiency #### 3. Sentiment Detection Mastery * **Objective**: Enhance sentiment detection accuracy * **Current State**: 94% accuracy * **Target Metrics**: * Sentiment accuracy: 94% → 98% * False positive rate: 3% → 1% * Response appropriateness: 9.2/10 → 9.5/10 * **ROI**: \$200K annually * **Business Impact**: Critical for maintaining positive customer relationships ## Key Performance Metrics ### Real-Time Metrics Dashboard Monitor your agent ecosystem with these essential real-time metrics: ```typescript theme={null} interface RealtimeMetrics { activeAgents: number; // Currently active agents requestsPerSecond: number; // System throughput avgResponseTime: number; // Response latency in seconds successRate: number; // Percentage of successful interactions activeExperiments: number; // Running A/B tests learningRate: number; // Agent improvement velocity } ``` ### Agent-Specific Performance Indicators Each agent tracks individual performance metrics: ```typescript theme={null} interface AgentPerformance { accuracy: number; // Task completion accuracy (%) speed: number; // Response speed percentile satisfaction: number; // Customer satisfaction score successRate: number; // Overall success rate (%) avgReward: number; // Average reward per action penalties: number; // Number of penalties incurred streak: number; // Consecutive days without penalties } ``` ### Success Metric Categories 1. **Operational Metrics** * Response time * Throughput * Availability * Error rate 2. **Quality Metrics** * Accuracy * Precision * Recall * F1 Score 3. **Business Metrics** * Customer satisfaction (CSAT) * Net Promoter Score (NPS) * First contact resolution (FCR) * Cost per interaction 4. **Learning Metrics** * Improvement rate * Adaptation speed * Knowledge retention * Skill acquisition ## Reward System Architecture ### Reward Components The reward system uses a multi-faceted approach to incentivize optimal agent behavior: ```typescript theme={null} interface RewardPolicy { id: number; name: string; description: string; baseReward: number; conditions: string[]; multipliers: Multiplier[]; penaltyConditions: string[]; active: boolean; } interface Multiplier { condition: string; multiplier: number; } ``` ### Core Reward Policies #### 1. First-Call Resolution Reward * **Base Reward**: 20 points * **Conditions**: * Resolution time \< 10 minutes * No escalation required * Customer satisfied * **Multipliers**: * Complex issue: 1.5x * VIP customer: 2.0x * **Penalties**: False resolution, customer complaint #### 2. Speed Excellence Reward * **Base Reward**: 10 points * **Conditions**: * Response time \< 30 seconds * **Multipliers**: * Under 15 seconds: 2.0x * Maintained quality: 1.3x * **Penalties**: Quality score \< 80% #### 3. Sentiment Mastery Reward * **Base Reward**: 15 points * **Conditions**: * Sentiment accuracy > 95% * Appropriate tone match * **Multipliers**: * De-escalated situation: 3.0x * **Penalties**: Misread critical sentiment ### Achievement System Gamification elements to drive long-term engagement: ```typescript theme={null} interface Achievement { id: number; name: string; description: string; icon: string; rarity: 'common' | 'rare' | 'epic' | 'legendary'; rewardValue: number; unlockedBy: string[]; progress: { current: number; target: number; }; } ``` #### Example Achievements 1. **Speed Demon** (Rare) * Maintain average response time under 30s for 100 interactions * Reward: 500 points 2. **Customer Champion** (Epic) * Achieve 95% customer satisfaction rating * Reward: 1000 points 3. **Streak Master** (Legendary) * Maintain a 10-day streak without penalties * Reward: 1500 points 4. **Learning Machine** (Epic) * Improve performance metrics by 20% in 30 days * Reward: 800 points ## Reinforcement Learning Integration ### RL Metrics Framework ```typescript theme={null} interface RLMetrics { episodes: number; // Total training episodes averageEpisodeReward: number; // Mean reward per episode maxEpisodeReward: number; // Best episode performance minEpisodeReward: number; // Worst episode performance convergenceRate: number; // Learning convergence (0-1) bellmanError: number; // Value function accuracy policyEntropy: number; // Exploration measure stateValueEstimates: Record; actionDistribution: Record; } ``` ### Key RL Parameters 1. **Learning Parameters** * Learning rate: 0.001 * Discount factor: 0.95 * Exploration rate: 15% 2. **Policy Metrics** * Policy gradient: 0.73 * Value function: 0.85 * Advantage estimate: 0.28 3. **State Values** * Greeting: 12.5 * Problem solving: 45.2 * Escalation: -5.8 * Resolution: 85.3 ### Action Distribution Optimal action probabilities: * Provide solution: 45% * Ask clarification: 25% * Escalate: 5% * Offer alternative: 25% ### Value Functions Value functions estimate the long-term expected rewards from a given state, helping agents make farsighted decisions. Use explicit value functions to go beyond immediate rewards. ### Preventing Reward Hacking Design reward functions carefully to avoid exploitation of loopholes. Incorporate human feedback via RLHF to align with intended goals. ### Modern Practices * Use dense rewards for frequent feedback and sparse rewards for ultimate goals. * Implement intrinsic rewards to encourage exploration. ## Implementation Guide ### 1. Setting Up Goals ```javascript theme={null} // Create a new goal const newGoal = { title: "Improve Customer Satisfaction", description: "Increase CSAT score through better response quality", targetDate: "2024-06-30", priority: "high", owner: "Sarah Chen", agent: "CustomerSupport-v2.1", successMetrics: [ { metric: "CSAT Score", current: 4.2, target: 4.6, unit: "/5" }, { metric: "Response Quality", current: 85, target: 92, unit: "%" } ], estimatedROI: "$200K annually", businessImpact: "High - directly impacts customer retention" }; ``` ### 2. Configuring Rewards ```javascript theme={null} // Define a reward policy const rewardPolicy = { name: "Quality Response Bonus", description: "Reward high-quality, helpful responses", baseReward: 25, conditions: [ "Response quality score > 90%", "Customer feedback positive", "No follow-up needed" ], multipliers: [ { condition: "Technical complexity high", multiplier: 1.5 }, { condition: "First attempt resolution", multiplier: 1.3 } ], penaltyConditions: [ "Incorrect information provided", "Customer escalation required" ], active: true }; ``` ### 3. Tracking Performance ```javascript theme={null} // Monitor agent performance const agentMetrics = { agentId: "CustomerSupport-v2.1", totalRewards: 3500, recentRewards: 450, performance: { successRate: 94, avgReward: 15.2, penalties: 12, streak: 7 }, level: 12, nextLevelProgress: 78 }; ``` ### 4. Running Experiments ```javascript theme={null} // Design an experiment const experiment = { name: "Response Template Optimization", hypothesis: "Structured templates will improve resolution rate by 10%", type: "ab_test", duration: "2 weeks", successCriteria: [ "Resolution rate improves by >10%", "Customer satisfaction maintained or improved", "No increase in handle time" ], sampleSize: 1000, significanceLevel: 0.05 }; ``` ## Best Practices ### 1. Goal Setting * **SMART Goals**: Specific, Measurable, Achievable, Relevant, Time-bound * **Incremental Targets**: Set progressive milestones * **Regular Reviews**: Weekly progress checks * **Data-Driven**: Base targets on historical performance ### 2. Metric Selection * **Balanced Scorecard**: Mix operational, quality, and business metrics * **Leading Indicators**: Focus on predictive metrics * **Actionable Insights**: Ensure metrics drive specific actions * **Avoid Vanity Metrics**: Focus on impact, not activity ### 3. Reward Design * **Immediate Feedback**: Real-time reward attribution * **Clear Criteria**: Unambiguous reward conditions * **Balanced Incentives**: Avoid gaming the system * **Progressive Difficulty**: Scale rewards with agent maturity ### 4. Continuous Improvement * **A/B Testing**: Regularly experiment with new approaches * **Feedback Loops**: Incorporate learnings quickly * **Cross-Agent Learning**: Share successful strategies * **Human-in-the-Loop**: Regular coaching and guidance ### 5. Risk Management * **Penalty Caps**: Limit maximum penalties * **Safety Checks**: Prevent harmful optimizations * **Rollback Plans**: Quick reversion capabilities * **Monitoring Alerts**: Real-time anomaly detection ### 6. Reward Design Best Practices * **Avoid Reward Hacking**: Design rewards to prevent agents from exploiting loopholes. Ensure rewards align with intended behaviors without unintended shortcuts. * **Use RLHF**: Incorporate Reinforcement Learning from Human Feedback for aligning rewards with human preferences. * **Dense vs. Sparse Rewards**: Balance immediate feedback (dense) with long-term goals (sparse) to guide learning effectively. * **Intrinsic Motivation**: Add rewards for exploration and novelty to encourage robust learning. * **Regular Audits**: Continuously monitor and update reward functions to adapt to new behaviors and prevent drift. ## Conclusion This framework provides a comprehensive approach to managing agent objectives, goals, metrics, and rewards. By combining clear goal-setting, robust performance tracking, and intelligent reward systems with reinforcement learning principles, you can create a self-improving agent ecosystem that delivers measurable business value. Remember to: * Start with clear, measurable objectives * Implement comprehensive tracking from day one * Design rewards that align with business goals * Use experiments to validate improvements * Continuously iterate based on data The key to success is maintaining a balance between automation and human oversight, ensuring your agents improve while staying aligned with your organization's values and objectives. ## References * Sutton and Barto, "Reinforcement Learning: An Introduction" * "What Agents Desire? Reward and Value Functions in AI" by Ksenia Se (Turing Post, 2025) * "Establishing Best Practices for Building Rigorous Agentic Benchmarks" (arXiv:2507.02825) # Agent Training Guide Source: https://docs.stateset.com/guides/agent-trainer-guide Comprehensive guide for training AI agents: knowledge bases, model selection, datasets, evaluation, and MCP tools # Agent Training Guide Welcome to the comprehensive Agent Training Guide. This document provides best practices and methodologies for training AI agents effectively, covering everything from knowledge base design to model selection and evaluation strategies. ## Table of Contents 1. [Introduction](#introduction) 2. [Knowledge Base vs Rules](#knowledge-base-vs-rules) 3. [Base Model vs Finetuned Model](#base-model-vs-finetuned-model) 4. [Datasets, Training, and Evaluations](#datasets-training-and-evaluations) 5. [MCP Tool for Google Drive Documents](#mcp-tool-for-google-drive-documents) 6. [Best Practices](#best-practices) 7. [Troubleshooting](#troubleshooting) 8. [Conclusion](#conclusion) *** ## Introduction Training effective AI agents requires understanding the fundamental differences between various approaches and tools. This guide will help you make informed decisions about: * When to use knowledge bases versus rule-based systems * Choosing between base models and finetuned models * Creating effective training datasets and evaluation frameworks * Leveraging MCP (Model Context Protocol) tools for document integration *** ## Knowledge Base vs Rules ### Knowledge Base Approach A **knowledge base** is a structured repository of information that agents can query and reference dynamically. #### Advantages: * **Flexibility**: Easy to update without retraining * **Scalability**: Can handle vast amounts of information * **Context-Aware**: Enables semantic search and retrieval * **Dynamic Updates**: Real-time information updates possible #### Disadvantages: * **Retrieval Overhead**: May increase response latency * **Context Limitations**: Limited by retrieval quality * **Complexity**: Requires robust indexing and search infrastructure #### Best Use Cases: ```yaml theme={null} knowledge_base_ideal_for: - FAQ systems - Product documentation - Dynamic information (prices, inventory) - Multi-domain applications - Frequently updated content ``` ### Rule-Based Approach **Rules** are predefined logic patterns that dictate agent behavior based on specific conditions. #### Advantages: * **Predictability**: Deterministic outcomes * **Performance**: Fast execution without retrieval * **Precision**: Exact control over responses * **Auditability**: Clear decision paths #### Disadvantages: * **Rigidity**: Hard to scale and maintain * **Limited Flexibility**: Cannot handle edge cases well * **Manual Updates**: Requires code changes for modifications * **Complexity Growth**: Rules become unwieldy as they multiply #### Best Use Cases: ```yaml theme={null} rules_ideal_for: - Compliance requirements - Simple decision trees - High-stakes operations - Regulatory workflows - Fixed business logic ``` ### Hybrid Approach Often, the best solution combines both approaches: ```python theme={null} class HybridAgent: def process_query(self, query): # Check rules first for critical paths if self.check_compliance_rules(query): return self.execute_rule_based_action(query) # Fall back to knowledge base for general queries context = self.knowledge_base.retrieve(query) return self.generate_response(query, context) ``` *** ## Base Model vs Finetuned Model ### Base Models Base models are pre-trained on vast datasets but not specialized for specific tasks. #### Characteristics: * **General Purpose**: Broad knowledge across domains * **Zero-Shot Capable**: Can handle diverse tasks without specific training * **Large Context Windows**: Modern base models support extensive context * **Consistent Updates**: Benefit from provider improvements #### When to Use Base Models: ```yaml theme={null} base_model_scenarios: - Prototyping and POCs - Multi-purpose agents - When training data is limited - Rapidly changing requirements - Cost-sensitive applications ``` ### Finetuned Models Finetuned models are specialized versions trained on domain-specific data. #### Characteristics: * **Domain Expertise**: Superior performance on specific tasks * **Consistency**: More predictable outputs * **Efficiency**: Often smaller and faster * **Custom Behavior**: Tailored to exact requirements #### When to Use Finetuned Models: ```yaml theme={null} finetuned_model_scenarios: - Domain-specific applications - High-volume, repetitive tasks - When accuracy is critical - Custom tone/style requirements - Proprietary knowledge encoding ``` ### Decision Flow: When to Finetune Choosing between a base model and a finetuned model can be simplified with the following decision flow: ```mermaid theme={null} graph TD A[Start: New AI Task] --> B{Need domain-specific
expertise or style?}; B -- No --> D[Use Base Model]; B -- Yes --> C{Have >1k high-quality
training examples?}; C -- Yes --> E[Finetune a Model]; C -- No --> F{Can you generate/acquire
high-quality data?}; F -- Yes --> G[Generate/Acquire Data]; G --> E; F -- No --> H[Use Base Model with
Advanced Prompting / RAG]; subgraph "Base Model Path" D; H; end subgraph "Finetuning Path" E; G; end D --> I[Deploy & Monitor]; E --> I; H --> I; ``` ### Comparison Matrix | Aspect | Base Model | Finetuned Model | | --------------------- | ---------------- | -------------------------- | | **Setup Time** | Immediate | Weeks to months | | **Cost** | Pay-per-use | Training + inference | | **Flexibility** | High | Limited to training domain | | **Performance** | Good general | Excellent specific | | **Maintenance** | Provider managed | Self-managed | | **Data Requirements** | None | Thousands of examples | *** ## Datasets, Training, and Evaluations ### Dataset Creation Creating high-quality training datasets is crucial for agent performance. #### Dataset Components: ```json theme={null} { "training_example": { "input": "User query or context", "expected_output": "Ideal agent response", "metadata": { "category": "customer_support", "difficulty": "medium", "tags": ["refund", "policy"] } } } ``` #### Best Practices for Dataset Creation: 1. **Diversity**: Cover edge cases and variations 2. **Quality**: Ensure accuracy and consistency 3. **Balance**: Represent all categories equally 4. **Annotation**: Include clear labels and metadata 5. **Validation**: Have experts review samples ### Training Process #### 1. Data Preparation ```python theme={null} # Example data preprocessing pipeline def prepare_training_data(raw_data): processed_data = [] for item in raw_data: # Clean and normalize text (e.g., lowercase, remove punctuation) cleaned_input = normalize_text(item['input']) cleaned_output = normalize_text(item['output']) # Validate data quality (e.g., check for length, language, non-empty) if validate_pair(cleaned_input, cleaned_output): processed_data.append({ 'input': cleaned_input, 'output': cleaned_output, 'metadata': item.get('metadata', {}) }) # Split into training, validation, and test sets (e.g., 80/10/10) return split_data(processed_data) # train/val/test splits ``` #### 2. Training Configuration ```yaml theme={null} training_config: base_model: "claude-3.5-sonnet" # Updated to recent model learning_rate: 1e-5 batch_size: 32 epochs: 3 validation_split: 0.2 early_stopping: patience: 3 metric: "validation_loss" ``` #### 3. Monitoring Training * Track loss curves * Monitor validation metrics * Check for overfitting * Evaluate on holdout test set ### Evaluation Framework #### Automated Metrics: ```python theme={null} evaluation_metrics = { "accuracy": calculate_exact_match, "bleu_score": calculate_bleu, "perplexity": calculate_perplexity, "response_time": measure_latency, "token_efficiency": count_tokens } ``` #### Human Evaluation Criteria: 1. **Relevance**: Does the response address the query? 2. **Accuracy**: Is the information correct? 3. **Completeness**: Are all aspects covered? 4. **Tone**: Is the style appropriate? 5. **Coherence**: Is the response well-structured? #### A/B Testing Framework: ```python theme={null} class ABTestFramework: def __init__(self, model_a, model_b): self.model_a = model_a self.model_b = model_b self.results = {"model_a": [], "model_b": []} def run_test(self, test_queries, metric_fn): for query in test_queries: response_a = self.model_a.generate(query) response_b = self.model_b.generate(query) score_a = metric_fn(query, response_a) score_b = metric_fn(query, response_b) self.results["model_a"].append(score_a) self.results["model_b"].append(score_b) return self.analyze_results() def analyze_results(self): # Example: Perform statistical test (e.g., t-test) # to see if one model is significantly better. import numpy as np from scipy.stats import ttest_ind scores_a = np.array(self.results["model_a"]) scores_b = np.array(self.results["model_b"]) if len(scores_a) < 2 or len(scores_b) < 2: return {"error": "Not enough data to run t-test."} t_stat, p_value = ttest_ind(scores_a, scores_b) return { "mean_score_a": np.mean(scores_a), "mean_score_b": np.mean(scores_b), "p_value": p_value, "winner": "model_a" if np.mean(scores_a) > np.mean(scores_b) else "model_b" } ``` *** ## Reinforcement Learning in Agent Training ### Overview Reinforcement Learning (RL) is a key method for training agents to make sequential decisions by interacting with an environment, receiving rewards or penalties based on actions. Recent shifts in LLM training emphasize post-training with RL to enable complex, agentic behaviors. #### Key Advantages: * **Handles Long-Horizon Tasks**: RL excels in scenarios requiring multi-step reasoning, such as planning in games or real-world simulations. * **Exploration and Curiosity**: Encourages agents to explore novel strategies, reducing compounding errors seen in pure imitation learning. * **Alignment with Human Values**: Techniques like RLHF (Reinforcement Learning from Human Feedback) and Constitutional AI align agents with ethical guidelines. #### Best Practices: * **Combine with Imitation Learning**: Start with imitation for basic behaviors, then use RL for refinement. * **Use Reward Models**: Train models to evaluate outputs, enabling scalable feedback without constant human input. * **Incorporate Human-in-the-Loop**: Platforms like GUIDE allow real-time human feedback for nuanced guidance. * **Benchmark and Avoid Overfitting**: Use diverse environments and standardize evaluations to ensure real-world applicability. #### Example: Training an Agent in a Game Environment ```python theme={null} import gym env = gym.make('CartPole-v1') # RL training loop example for episode in range(1000): state = env.reset() done = False while not done: action = agent.select_action(state) # RL policy next_state, reward, done, _ = env.step(action) agent.update(reward, next_state) # Update with RL algorithm (e.g., Q-Learning) ``` Recent models like o1 and Claude 3.5 demonstrate RL's impact on reasoning capabilities. *** ## MCP Tool for Google Drive Documents ### Overview The Model Context Protocol (MCP) enables agents to interact with Google Drive documents seamlessly, providing real-time access to organizational knowledge. ### Setup and Configuration #### 1. Install MCP Server ```bash theme={null} npm install @modelcontextprotocol/server-gdrive ``` #### 2. Configure Authentication ```json theme={null} { "google_drive_mcp": { "client_id": "your-client-id", "client_secret": "your-client-secret", "redirect_uri": "https://yourapp.com:3000/callback", "scopes": [ "https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/documents.readonly" ] } } ``` #### 3. Initialize MCP Tool ```javascript theme={null} const { GoogleDriveMCP } = require('@modelcontextprotocol/server-gdrive'); const driveTool = new GoogleDriveMCP({ credentials: googleCredentials, settings: { maxResults: 10, includeSharedDrives: true, mimeTypes: [ 'application/vnd.google-apps.document', 'application/vnd.google-apps.spreadsheet', 'application/pdf' ] } }); ``` ### Usage Patterns #### Document Search ```javascript theme={null} // Search for relevant documents const searchResults = await driveTool.search({ query: "customer onboarding procedures", filters: { modifiedAfter: "2024-01-01", owners: ["team@company.com"] } }); ``` #### Content Extraction ```javascript theme={null} // Extract content from a specific document const documentContent = await driveTool.getDocument({ documentId: "1234567890abcdef", format: "markdown", includeMetadata: true }); ``` #### Integration with Agent ```python theme={null} class GoogleDriveAgent: def __init__(self, mcp_tool, llm): self.mcp_tool = mcp_tool self.llm = llm async def answer_with_docs(self, query): # Search relevant documents docs = await self.mcp_tool.search({ "query": query, "limit": 5 }) # Extract content context = "" for doc in docs: content = await self.mcp_tool.get_content(doc.id) context += f"\n\n{doc.title}:\n{content[:1000]}" # Generate response with context prompt = f""" Based on the following documents, answer the query: {query} Documents: {context} """ return await self.llm.generate(prompt) ``` ### Best Practices 1. **Caching**: Implement caching for frequently accessed documents 2. **Permissions**: Respect document permissions and access controls 3. **Rate Limiting**: Handle API rate limits gracefully 4. **Error Handling**: Implement robust error handling for network issues 5. **Incremental Sync**: Use change tokens for efficient updates *** ## Best Practices ### 1. Start Simple * Begin with base models and simple prompts * Add complexity incrementally * Measure improvements at each step ### 2. Data Quality Over Quantity * 1,000 high-quality examples are more valuable than 10,000 mediocre ones. * **Invest in data cleaning and validation**: * **Clarity**: Unambiguous input/output pairs. * **Consistency**: Uniform style, format, and tone. * **Coverage**: Represents the full range of expected user interactions, including edge cases. * **Correctness**: Factually accurate and grammatically correct. * **Regularly audit training data** to remove outdated or incorrect examples. * **Incorporate Diverse Sources**: Use human-synthetic data blends and ensure representativeness to avoid biases (from Toloka guide). ### 3. Continuous Evaluation and Learning * Set up automated evaluation pipelines to monitor performance on key metrics. * Regular human evaluation sessions to assess nuanced aspects of quality. * Monitor production performance closely to catch regressions or new failure modes. * Implement continuous learning post-deployment for adaptability. ### 4. Version Control * **Use version control for everything**: training data, prompts, model configurations, and evaluation results. * This allows for reproducibility, easy rollbacks, and clear tracking of experiments. * Tools like Git, DVC (Data Version Control), and MLflow can be invaluable. ### 5. Security Considerations * Sanitize all user inputs and training data to prevent data poisoning. * Implement strict access controls for training infrastructure and models. * **Be aware of prompt injection**: Design prompts and agent logic to be resilient against adversarial inputs. * Conduct regular security audits of your entire AI/ML pipeline. * Align agents with human values using RLHF to prevent misalignment (from arXiv papers). *** ## Challenges and Solutions in Agent Training ### Common Challenges * **Data Scarcity and Quality**: Insufficient or biased data leads to poor generalization. * **Misalignment with Human Values**: Agents may optimize for wrong objectives, ignoring ethics. * **Overfitting to Benchmarks**: High benchmark scores may not translate to real-world performance. * **Exploration in Complex Environments**: Agents struggle with long-horizon tasks and sparse rewards. ### Solutions * **High-Quality Datasets**: Prioritize diverse, representative data; use synthetic data generation. * **Alignment Techniques**: Employ RLHF, Constitutional AI, and human-in-the-loop feedback. * **Robust Evaluation**: Use multi-metric benchmarks and real-world testing (e.g., GUIDE framework for human interactions). * **Advanced Tools**: Leverage open-source like PyTorch or proprietary like Azure for scalable training. *** ## Troubleshooting ### Common Issues and Solutions #### 1. Poor Model Performance ```yaml theme={null} symptoms: - Inaccurate responses - Inconsistent behavior - High error rates solutions: - Review training data quality - Increase dataset diversity - Adjust training parameters - Consider different base models ``` #### 2. Knowledge Base Retrieval Issues ```yaml theme={null} symptoms: - Irrelevant results - Missing information - Slow retrieval solutions: - Improve indexing strategy - Enhance search queries - Optimize embedding models - Implement caching ``` #### 3. MCP Integration Problems ```yaml theme={null} symptoms: - Authentication failures - Timeout errors - Missing documents solutions: - Verify credentials - Check network connectivity - Review permission scopes - Implement retry logic ``` *** ## Conclusion Building powerful AI agents is a journey of iterative refinement. It begins with a strategic choice of architecture—balancing the predictability of rules with the flexibility of knowledge bases—and selecting the right model for your task. Success hinges on a disciplined approach to data, training, and evaluation. By curating high-quality datasets, establishing robust evaluation frameworks, and continuously monitoring performance, you create a virtuous cycle of improvement. Integrating powerful tools like MCP for real-time data access further enhances your agent's capabilities. Recent advancements emphasize reinforcement learning for enabling agentic behaviors and long-horizon reasoning. As AI evolves, focus on alignment, real-world benchmarks, and human-AI collaboration to build agents that are not only intelligent but truly effective and ethical. The principles in this guide provide a roadmap for this journey. Embrace a mindset of continuous learning, rigorous experimentation, and a relentless focus on quality. By doing so, you can build reliable, intelligent, and valuable AI agents that are not just technically impressive, but truly effective. # Agentic Commerce Protocol Handler Source: https://docs.stateset.com/guides/agentic-commerce-protocol-handler Self-hosted server implementing the Agentic Commerce Protocol for ChatGPT Instant Checkout Agentic Commerce Protocol (ACP) Handler is a Rust server that implements OpenAI's Agentic Commerce Protocol. It provides checkout session APIs, delegated payments, and optional gRPC access so you can keep orders and compliance in your own stack while enabling ChatGPT Instant Checkout experiences. ## Key capabilities * Full checkout session lifecycle for the ACP spec * Delegated payment endpoint with vault token support * Optional Stripe PaymentIntent integration * Idempotency keys and request tracing * Swagger UI at `/docs` and OpenAPI JSON at `/openapi.json` * gRPC API mirroring the HTTP endpoints ## Architecture overview ```mermaid theme={null} graph LR ChatGPT[ChatGPT or client] -->|HTTP or gRPC| Handler[ACP Handler] Handler --> Redis[Redis or in-memory sessions] Handler --> Commerce[iCommerce or SQLite backend] Handler --> PSP[Payment service provider] ``` ## Quickstart ```bash theme={null} cargo build --release cargo run --release ``` The HTTP server listens on `http://0.0.0.0:8080` by default. The gRPC server listens on `0.0.0.0:50051`. To run the demo flow: ```bash theme={null} ./demo_test.sh ``` ## Create a checkout session ```bash theme={null} curl -X POST https://yourapp.com:8080/checkout_sessions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer api_key_123" \ -H "API-Version: 2025-09-29" \ -d '{ "items": [{ "id": "item_123", "quantity": 2 }], "buyer": { "email": "buyer@example.com" } }' ``` ## Core endpoints | Method | Endpoint | Description | | ------ | ------------------------------------ | ---------------------------------- | | POST | `/checkout_sessions` | Create a checkout session | | GET | `/checkout_sessions/:id` | Retrieve a checkout session | | POST | `/checkout_sessions/:id` | Update a checkout session | | POST | `/checkout_sessions/:id/complete` | Complete checkout and create order | | POST | `/checkout_sessions/:id/cancel` | Cancel a checkout session | | POST | `/agentic_commerce/delegate_payment` | Delegated payment (vault token) | | GET | `/health` | Health check | | GET | `/ready` | Readiness check | | GET | `/docs` | Swagger UI | | GET | `/openapi.json` | OpenAPI spec | ## Delegated payments The delegated payment endpoint accepts payment tokens from a PSP vault. Tokens are validated for allowance and expiry and are consumed after use. ## Stripe integration Set the following environment variables before starting the server to process delegated payments with Stripe: * `STRIPE_SECRET_KEY` * `STRIPE_PUBLISHABLE_KEY` (optional) * `STRIPE_WEBHOOK_SECRET` (optional, for webhook signature verification) ## gRPC access The gRPC API mirrors the HTTP endpoints and uses the same API keys. Send `authorization: Bearer ` as gRPC metadata. ## Related components The repository also includes: * A Next.js dashboard for monitoring checkout sessions * A ChatGPT widget server for MCP-based agent flows * Kubernetes and Docker Compose deployment assets # Agents Quickstart Source: https://docs.stateset.com/guides/agents-quickstart This guide will walk you through creating and managing Agents on ResponseCX. ## Prerequisites Before you begin creating agents, ensure you have: * A StateSet account ([Sign up here](https://StateSet.com/sign-up)) * API credentials from the [StateSet Dashboard](https://app.StateSet.com/settings/api-keys) * ResponseCX enabled in your workspace * Node.js 16+ installed on your development machine * Basic understanding of REST APIs and JavaScript/TypeScript * Text editor or IDE for code development * Understanding of conversational AI concepts and customer service workflows * Access to your customer support systems (if planning integrations) * Knowledge of your brand voice and customer interaction requirements ## What are Agents? In ResponseCX, an Agent is an autonomous conversational AI that can interact with your customers. You can customize its name, personality, and instructions to fit your business needs. Agents can be used in chat sessions to provide support, answer questions, and guide users. ## Creating an Agent You can create an agent through the ResponseCX dashboard or using the SDK. ### Using the Dashboard 1. Navigate to the **Agents** section of the ResponseCX dashboard. 2. Click the **Add New Agent** button. 3. Fill in the agent's details: * **Name:** A recognizable name for your agent (e.g., "Support Bot"). * **Description:** A brief summary of the agent's purpose. * **Type:** The type of agent. For most use cases, you'll use `Conversational AI Agent`. * **Voice Model:** The voice your agent will use for voice interactions. `Asteria` is a popular choice. 4. Click **Add Agent** to save your new agent. ### Using the SDK Here's how to create an agent using our SDKs with proper error handling: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import winston from 'winston'; // Configure logger const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [new winston.transports.Console()] }); // Initialize the client const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); async function createAgent() { try { const agent = await client.agents.create({ name: "My SDK Agent", description: "This agent was created via the SDK.", type: "Conversational AI Agent", role: "E-commerce Assistant", instructions: "You are a friendly and helpful assistant for an online store.", goal: "Help customers find products and answer questions about their orders.", voice_model: "Asteria", }); logger.info('Agent created successfully', { agentId: agent.id, name: agent.name }); return agent; } catch (error) { logger.error('Failed to create agent', { error: error.message, stack: error.stack }); throw error; } } // Usage const agent = await createAgent(); ``` ```python theme={null} import os import logging from StateSet import StateSetClient # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Initialize the client client = StateSetClient(api_key=os.getenv('STATESET_API_KEY')) def create_agent(): try: agent = client.agents.create( name="My SDK Agent", description="This agent was created via the SDK.", type="Conversational AI Agent", role="E-commerce Assistant", instructions="You are a friendly and helpful assistant for an online store.", goal="Help customers find products and answer questions about their orders.", voice_model="Asteria" ) logger.info(f'Agent created successfully: {agent.id} - {agent.name}') return agent except Exception as error: logger.error(f'Failed to create agent: {str(error)}') raise # Usage agent = create_agent() ``` ```ruby theme={null} require 'StateSet' require 'logger' # Configure logging logger = Logger.new(STDOUT) logger.level = Logger::INFO # Configure client StateSet.configure do |config| config.api_key = ENV['STATESET_API_KEY'] end def create_agent agent = StateSet::Agent.create( name: "My SDK Agent", description: "This agent was created via the SDK.", type: "Conversational AI Agent", role: "E-commerce Assistant", instructions: "You are a friendly and helpful assistant for an online store.", goal: "Help customers find products and answer questions about their orders.", voice_model: "Asteria" ) logger.info "Agent created successfully: #{agent.id} - #{agent.name}" agent rescue => error logger.error "Failed to create agent: #{error.message}" raise end # Usage agent = create_agent ``` ```php theme={null} pushHandler(new StreamHandler('php://stdout', Logger::INFO)); // Initialize the client $client = new StateSetClient([ 'api_key' => $_ENV['STATESET_API_KEY'] ]); function createAgent($client, $logger) { try { $agent = $client->agents->create([ 'name' => 'My SDK Agent', 'description' => 'This agent was created via the SDK.', 'type' => 'Conversational AI Agent', 'role' => 'E-commerce Assistant', 'instructions' => 'You are a friendly and helpful assistant for an online store.', 'goal' => 'Help customers find products and answer questions about their orders.', 'voice_model' => 'Asteria' ]); $logger->info('Agent created successfully', [ 'agent_id' => $agent['id'], 'name' => $agent['name'] ]); return $agent; } catch (Exception $error) { $logger->error('Failed to create agent', [ 'error' => $error->getMessage() ]); throw $error; } } // Usage $agent = createAgent($client, $logger); ?> ``` ```bash theme={null} # Create an agent using cURL curl -X POST "https://api.StateSet.com/v1/agents" \ -H "Authorization: Bearer $STATESET_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "My SDK Agent", "description": "This agent was created via the SDK.", "type": "Conversational AI Agent", "role": "E-commerce Assistant", "instructions": "You are a friendly and helpful assistant for an online store.", "goal": "Help customers find products and answer questions about their orders.", "voice_model": "Asteria" }' | jq '.' # Save the response to get the agent ID AGENT_ID=$(curl -s -X POST "https://api.StateSet.com/v1/agents" \ -H "Authorization: Bearer $STATESET_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "My SDK Agent", "description": "This agent was created via the SDK.", "type": "Conversational AI Agent", "role": "E-commerce Assistant", "instructions": "You are a friendly and helpful assistant for an online store.", "goal": "Help customers find products and answer questions about their orders.", "voice_model": "Asteria" }' | jq -r '.id') echo "Agent created with ID: $AGENT_ID" ``` **Agent Properties:** * `name` (string, required): The name of the agent. * `description` (string): A short description of the agent. * `type` (string): The type of agent. * `role` (string): The role you want the agent to adopt (e.g., "Customer Support Agent"). * `instructions` (string): Specific instructions for the agent on how to behave. This is where you define its personality and operational guidelines. * `goal` (string): The primary objective for the agent in conversations. * `voice_model` (string): The voice model for text-to-speech. ## Managing Agents You can view, update, and delete your agents. ### Listing Agents Retrieve a list of all your agents with pagination support: ```javascript theme={null} async function listAgents(page = 1, limit = 10) { try { const agents = await client.agents.list({ page, limit, sort: 'created_at:desc' }); return { agents: agents.data, totalCount: agents.total, hasMore: agents.has_more }; } catch (error) { logger.error('Failed to list agents:', error); throw new Error('Unable to retrieve agents at this time'); } } ``` ## Updating an Agent You can update an agent's properties in the dashboard or through the SDK. ### Using the Dashboard 1. In the **Agents** list, click the **Update** button for the agent you want to modify. 2. Change the desired fields in the agent editor. 3. Click **Save** to apply the changes. ### Using the SDK ```javascript theme={null} async function updateAgent(agentId, updates) { try { const updatedAgent = await client.agents.update({ id: agentId, ...updates }); // Audit trail for compliance await auditLog.record({ action: 'agent.updated', agentId: agentId, changes: updates, timestamp: new Date() }); return { success: true, agent: updatedAgent, message: 'Agent updated successfully' }; } catch (error) { if (error.code === 'AGENT_NOT_FOUND') { throw new Error('Agent not found'); } logger.error('Failed to update agent:', error); throw error; } } // Example usage const updates = { name: "My Updated Agent Name", description: "Updated description with new capabilities", instructions: "You are now specialized in technical support..." }; await updateAgent(agentId, updates); ``` ## Deleting an Agent You can delete an agent from the dashboard or via the SDK. Deleting an agent is permanent and cannot be undone. ```javascript theme={null} async function deleteAgent(agentId) { try { // Check if agent has active conversations const activeConversations = await client.conversations.list({ agent_id: agentId, status: 'active' }); if (activeConversations.total > 0) { throw new Error('Cannot delete agent with active conversations'); } // Archive agent data before deletion (for compliance) await archiveAgentData(agentId); // Delete the agent await client.agents.delete({ id: agentId }); return { success: true, message: 'Agent deleted successfully' }; } catch (error) { logger.error('Failed to delete agent:', error); throw error; } } ``` ## Best Practices ### 1. Agent Instructions Be specific and clear in your instructions: ```javascript theme={null} const goodInstructions = `You are a friendly customer support agent for Acme Store. - Always greet customers warmly - Ask clarifying questions before providing solutions - Never share customer personal information - Escalate to human support for refund requests over $100`; const poorInstructions = "Help customers"; ``` ### 2. Error Handling Always implement robust error handling: ```javascript theme={null} async function safeAgentOperation(operation) { const maxRetries = 3; let lastError; for (let i = 0; i < maxRetries; i++) { try { return await operation(); } catch (error) { lastError = error; // Don't retry on client errors if (error.status >= 400 && error.status < 500) { throw error; } // Exponential backoff await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000)); } } throw lastError; } ``` ### 3. Monitoring Agent Performance Track your agent's effectiveness: ```javascript theme={null} async function getAgentMetrics(agentId, timeframe = '7d') { const metrics = await client.agents.getMetrics({ id: agentId, timeframe }); return { conversationCount: metrics.total_conversations, satisfactionScore: metrics.avg_satisfaction, resolutionRate: metrics.resolution_rate, avgResponseTime: metrics.avg_response_time_ms }; } ``` ## Next Steps Now that you've created an agent, you can start using it in your application. Here are some things you might want to do next: * **Create a Chat:** Learn how to initiate a chat session with your new agent. * **Explore advanced features:** Dive into more complex agent capabilities like using functions and knowledge bases. For more information on how to use Agents, please reach out at [support@StateSet.com](mailto:support@StateSet.com) # API Rate Limiting & Optimization Source: https://docs.stateset.com/guides/api-rate-limiting Understanding StateSet API rate limits, implementing efficient request patterns, and optimizing API usage for better performance # API Rate Limiting & Optimization StateSet implements rate limiting to ensure fair usage and maintain service reliability for all users. This guide covers understanding rate limits, implementing efficient request patterns, and optimizing your API usage. ## Rate Limit Overview StateSet uses a **sliding window** rate limiting algorithm that provides smooth, predictable limits across different time windows. Prevents burst traffic spikes and ensures responsive service Controls sustained request volume over longer periods Manages overall API consumption and prevents abuse ## Current Rate Limits ### By Plan Type | Endpoint Category | Per Second | Per Minute | Per Hour | | ----------------- | ---------- | ---------- | -------- | | **Orders API** | 10 | 300 | 5,000 | | **Customers API** | 5 | 150 | 2,500 | | **Returns API** | 5 | 150 | 2,500 | | **Webhooks** | 20 | 600 | 10,000 | | **Analytics** | 2 | 60 | 1,000 | | Endpoint Category | Per Second | Per Minute | Per Hour | | ----------------- | ---------- | ---------- | -------- | | **Orders API** | 50 | 1,500 | 25,000 | | **Customers API** | 25 | 750 | 12,500 | | **Returns API** | 25 | 750 | 12,500 | | **Webhooks** | 100 | 3,000 | 50,000 | | **Analytics** | 10 | 300 | 5,000 | | Endpoint Category | Per Second | Per Minute | Per Hour | | ----------------- | ---------- | ---------- | -------- | | **Orders API** | 200 | 6,000 | 100,000 | | **Customers API** | 100 | 3,000 | 50,000 | | **Returns API** | 100 | 3,000 | 50,000 | | **Webhooks** | 500 | 15,000 | 250,000 | | **Analytics** | 50 | 1,500 | 25,000 | ### Special Considerations * Batch endpoints have **higher rate limits** but count as multiple requests * Each item in a batch counts toward your rate limit * Maximum batch size: **100 items per request** * List endpoints with large `limit` parameters consume more quota * Requests with `limit > 100` count as `Math.ceil(limit/100)` requests * Use pagination instead of large limit values * Webhook deliveries **do not count** against your rate limits * Failed webhook retries use separate retry quotas * Webhook verification calls are not rate limited ## Rate Limit Headers Every API response includes rate limit information in the headers: ```http theme={null} HTTP/1.1 200 OK X-RateLimit-Limit: 1500 X-RateLimit-Remaining: 1247 X-RateLimit-Reset: 1640995200 X-RateLimit-Window: 60 X-RateLimit-Category: orders-api Retry-After: 45 ``` ### Header Descriptions | Header | Description | | ----------------------- | ----------------------------------------------------------- | | `X-RateLimit-Limit` | Maximum requests allowed in the current window | | `X-RateLimit-Remaining` | Requests remaining in the current window | | `X-RateLimit-Reset` | Unix timestamp when the window resets | | `X-RateLimit-Window` | Window duration in seconds (60 for per-minute limits) | | `X-RateLimit-Category` | API category for this endpoint | | `Retry-After` | Seconds to wait before retrying (present when rate limited) | ## Implementing Rate Limit Handling ### Basic Rate Limit Detection ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import winston from 'winston'; const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [new winston.transports.Console()] }); class RateLimitHandler { constructor(client) { this.client = client; this.requestCounts = new Map(); } async makeRequest(operation, ...args) { try { const response = await operation(...args); this.logRateLimitInfo(response); return response; } catch (error) { if (error.status === 429) { return this.handleRateLimit(error, operation, ...args); } throw error; } } logRateLimitInfo(response) { const headers = response.headers || {}; logger.info('Rate limit status', { remaining: headers['x-ratelimit-remaining'], limit: headers['x-ratelimit-limit'], resetTime: new Date(headers['x-ratelimit-reset'] * 1000), category: headers['x-ratelimit-category'] }); } async handleRateLimit(error, operation, ...args) { const retryAfter = error.headers?.['retry-after'] || 60; logger.warn('Rate limit exceeded, waiting before retry', { retryAfter, category: error.headers?.['x-ratelimit-category'] }); await this.sleep(retryAfter * 1000); return this.makeRequest(operation, ...args); } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Usage const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); const rateLimitHandler = new RateLimitHandler(client); const orders = await rateLimitHandler.makeRequest( () => client.orders.list({ limit: 50 }) ); ``` ### Advanced Rate Limiting with Queue ```javascript theme={null} import PQueue from 'p-queue'; class AdvancedRateLimitHandler { constructor(client, options = {}) { this.client = client; this.queues = new Map(); this.rateLimitInfo = new Map(); // Default queue options this.defaultQueueOptions = { concurrency: 5, interval: 1000, intervalCap: 10, ...options.queueOptions }; } getQueue(category = 'default') { if (!this.queues.has(category)) { const queueOptions = this.getCategoryQueueOptions(category); this.queues.set(category, new PQueue(queueOptions)); } return this.queues.get(category); } getCategoryQueueOptions(category) { const categorySettings = { 'orders-api': { concurrency: 10, interval: 1000, intervalCap: 10 }, 'customers-api': { concurrency: 5, interval: 1000, intervalCap: 5 }, 'returns-api': { concurrency: 5, interval: 1000, intervalCap: 5 }, 'analytics': { concurrency: 2, interval: 1000, intervalCap: 2 } }; return { ...this.defaultQueueOptions, ...categorySettings[category] }; } async makeRequest(operation, category = 'default', priority = 0) { const queue = this.getQueue(category); return queue.add(async () => { try { const response = await operation(); this.updateRateLimitInfo(category, response); return response; } catch (error) { if (error.status === 429) { await this.handleRateLimit(error, category); throw error; // Re-queue will happen automatically } throw error; } }, { priority }); } updateRateLimitInfo(category, response) { const headers = response.headers || {}; this.rateLimitInfo.set(category, { remaining: parseInt(headers['x-ratelimit-remaining']) || 0, limit: parseInt(headers['x-ratelimit-limit']) || 1000, resetTime: parseInt(headers['x-ratelimit-reset']) || 0, lastUpdated: Date.now() }); } async handleRateLimit(error, category) { const retryAfter = parseInt(error.headers?.['retry-after']) || 60; const queue = this.getQueue(category); logger.warn('Rate limit exceeded for category', { category, retryAfter, queueSize: queue.size, pending: queue.pending }); // Pause the queue queue.pause(); await this.sleep(retryAfter * 1000); // Resume the queue queue.start(); } getRateLimitStatus(category = 'default') { return this.rateLimitInfo.get(category) || null; } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Usage with priority queueing const handler = new AdvancedRateLimitHandler(client); // High priority request (emergency order processing) const criticalOrder = await handler.makeRequest( () => client.orders.get(orderId), 'orders-api', 10 ); // Normal priority batch processing const orders = await Promise.all([ handler.makeRequest(() => client.orders.list({ page: 1 }), 'orders-api', 0), handler.makeRequest(() => client.orders.list({ page: 2 }), 'orders-api', 0), handler.makeRequest(() => client.orders.list({ page: 3 }), 'orders-api', 0) ]); ``` ## Optimization Strategies ### 1. Efficient Pagination Instead of requesting large datasets at once: ```javascript theme={null} // ❌ Inefficient - May trigger rate limits const allOrders = await client.orders.list({ limit: 1000 }); // ✅ Efficient - Paginated requests async function getAllOrdersPaginated() { const allOrders = []; let hasMore = true; let cursor = null; while (hasMore) { const response = await client.orders.list({ limit: 100, cursor: cursor }); allOrders.push(...response.data); cursor = response.next_cursor; hasMore = response.has_more; // Small delay to respect rate limits await new Promise(resolve => setTimeout(resolve, 100)); } return allOrders; } ``` ### 2. Batch Operations Use batch endpoints when available: ```javascript theme={null} // ❌ Multiple individual requests for (const order of orders) { await client.orders.update(order.id, { status: 'processed' }); } // ✅ Single batch request await client.orders.batchUpdate( orders.map(order => ({ id: order.id, status: 'processed' })) ); ``` ### 3. Webhook-First Architecture Reduce polling by using webhooks: ```javascript theme={null} // ❌ Constant polling setInterval(async () => { const orders = await client.orders.list({ status: 'pending', updated_since: lastCheck }); processNewOrders(orders); }, 30000); // ✅ Webhook-driven updates app.post('/webhooks/StateSet', (req, res) => { const event = req.body; if (event.type === 'order.updated') { processOrderUpdate(event.data); } res.status(200).send('OK'); }); ``` ### 4. Intelligent Caching Cache frequently requested data: ```javascript theme={null} class StateSetCache { constructor(client, ttl = 300000) { // 5 minutes default TTL this.client = client; this.cache = new Map(); this.ttl = ttl; } async get(key, fetchFunction) { const cached = this.cache.get(key); const now = Date.now(); if (cached && (now - cached.timestamp) < this.ttl) { logger.debug('Cache hit', { key }); return cached.data; } logger.debug('Cache miss, fetching', { key }); const data = await fetchFunction(); this.cache.set(key, { data, timestamp: now }); return data; } clear(key) { if (key) { this.cache.delete(key); } else { this.cache.clear(); } } } // Usage const cache = new StateSetCache(client); const customer = await cache.get( `customer:${customerId}`, () => client.customers.get(customerId) ); ``` ## Monitoring Rate Limits ### Rate Limit Dashboard Create a monitoring dashboard for your rate limit usage: ```javascript theme={null} class RateLimitMonitor { constructor() { this.metrics = { requests: new Map(), rateLimits: new Map(), errors: new Map() }; } recordRequest(category, success = true) { const key = `${category}:${this.getTimeWindow()}`; const current = this.metrics.requests.get(key) || { success: 0, total: 0 }; current.total++; if (success) current.success++; this.metrics.requests.set(key, current); } recordRateLimit(category, remainingRequests, totalLimit) { const key = `${category}:${this.getTimeWindow()}`; this.metrics.rateLimits.set(key, { remaining: remainingRequests, total: totalLimit, utilizationPct: ((totalLimit - remainingRequests) / totalLimit) * 100, timestamp: Date.now() }); } getTimeWindow() { return Math.floor(Date.now() / 60000); // 1-minute windows } getUtilizationReport() { const report = {}; for (const [key, data] of this.metrics.rateLimits) { const [category] = key.split(':'); if (!report[category]) report[category] = []; report[category].push(data); } return report; } // Alert when utilization is high checkAlerts() { const report = this.getUtilizationReport(); for (const [category, dataPoints] of Object.entries(report)) { const latest = dataPoints[dataPoints.length - 1]; if (latest.utilizationPct > 80) { logger.warn('High API utilization detected', { category, utilization: latest.utilizationPct, remaining: latest.remaining }); } } } } // Usage with middleware const monitor = new RateLimitMonitor(); const monitoredClient = new Proxy(client, { get(target, prop) { const original = target[prop]; if (typeof original === 'object' && original !== null) { return new Proxy(original, { get(apiTarget, apiProp) { const apiMethod = apiTarget[apiProp]; if (typeof apiMethod === 'function') { return async (...args) => { const category = `${prop}-api`; try { const result = await apiMethod.apply(apiTarget, args); monitor.recordRequest(category, true); if (result.headers) { monitor.recordRateLimit( category, parseInt(result.headers['x-ratelimit-remaining']), parseInt(result.headers['x-ratelimit-limit']) ); } return result; } catch (error) { monitor.recordRequest(category, false); throw error; } }; } return apiMethod; } }); } return original; } }); ``` ## Best Practices Summary * Use pagination instead of large limit values * Implement batch operations where possible * Cache frequently requested data * Use webhooks to reduce polling * Always check rate limit headers * Implement exponential backoff for retries * Use queues to manage request flow * Monitor and alert on high utilization * Design webhook-first integrations * Implement circuit breakers for resilience * Use separate queues for different priorities * Cache aggressively with smart invalidation * Track utilization across all categories * Set alerts at 80% utilization threshold * Monitor request success rates * Review patterns during peak usage ## Getting Help If you're consistently hitting rate limits or need higher limits: 1. **Review your usage patterns** using the monitoring tools above 2. **Optimize your integration** following the strategies in this guide 3. **Consider upgrading** to a higher plan with increased limits 4. **Contact support** at [support@StateSet.com](mailto:support@StateSet.com) for custom rate limits ## Related Resources * [Error Handling Best Practices](/guides/error-handling-best-practices) * [Webhook Security Guide](/guides/webhook-security) * [API Testing Strategies](/guides/api-testing) * [Performance Optimization](/guides/performance-optimization) # API Testing Guide Source: https://docs.stateset.com/guides/api-testing Comprehensive guide to testing StateSet API integrations with practical examples and best practices # API Testing Guide Testing your StateSet API integration is crucial for ensuring reliability, catching bugs early, and maintaining confidence in your application. This guide covers comprehensive testing strategies from unit tests to end-to-end integration testing. Test individual API calls and error handling Test complete workflows and data flow Test without hitting live APIs Test real user scenarios end-to-end ## Testing Strategy Overview ### Test Pyramid for API Integration ``` 🔺 E2E Tests (Few) ↗ Complex user workflows ↗ Critical business paths ↗ Cross-system integration 🔷 Integration Tests (Some) ↗ API endpoint interactions ↗ Data transformation ↗ Error handling flows 🔲 Unit Tests (Many) ↗ Individual functions ↗ Input validation ↗ Business logic ↗ Error scenarios ``` ## Environment Setup ### Test Environment Configuration ```javascript theme={null} // test/setup.js import { StateSetClient } from 'StateSet-node'; import dotenv from 'dotenv'; // Load test environment variables dotenv.config({ path: '.env.test' }); // Test configuration export const testConfig = { apiKey: process.env.STATESET_TEST_API_KEY, baseUrl: process.env.STATESET_TEST_BASE_URL || 'https://api.sandbox.StateSet.com/v1', timeout: 10000, retries: 3 }; // Create test client export const testClient = new StateSetClient({ apiKey: testConfig.apiKey, baseUrl: testConfig.baseUrl, timeout: testConfig.timeout }); // Test data factory export const createTestData = { customer: (overrides = {}) => ({ email: `test+${Date.now()}@example.com`, first_name: 'Test', last_name: 'Customer', phone: '+1-555-123-4567', ...overrides }), order: (customerId, overrides = {}) => ({ customer_id: customerId, items: [ { sku: 'TEST-ITEM-001', quantity: 1, price: 29.99 } ], currency: 'USD', ...overrides }), address: (overrides = {}) => ({ street1: '123 Test Street', city: 'Test City', state: 'CA', postal_code: '12345', country: 'US', ...overrides }) }; // Test helpers export const testHelpers = { generateUniqueEmail: () => `test+${Date.now()}+${Math.random().toString(36)}@example.com`, waitFor: (ms) => new Promise(resolve => setTimeout(resolve, ms)), retry: async (fn, maxAttempts = 3, delay = 1000) => { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { if (attempt === maxAttempts) throw error; await testHelpers.waitFor(delay * attempt); } } }, cleanupResources: async (resources) => { for (const resource of resources) { try { await resource.cleanup(); } catch (error) { console.warn('Cleanup failed:', error.message); } } } }; ``` ### Environment Variables ```bash theme={null} # .env.test STATESET_TEST_API_KEY=sk_test_your_test_key_here STATESET_TEST_BASE_URL=https://api.sandbox.StateSet.com/v1 NODE_ENV=test LOG_LEVEL=warn # Test database (if applicable) TEST_DATABASE_URL=postgresql://user:pass@localhost:5432/test_db # External service mocks MOCK_STRIPE_ENABLED=true MOCK_EMAIL_ENABLED=true ``` ## Unit Testing ### Testing API Client Methods ```javascript theme={null} // test/unit/StateSetClient.test.js import { jest } from '@jest/globals'; import { StateSetClient } from 'StateSet-node'; import { StateSetAPIError } from 'StateSet-node/errors'; describe('StateSetClient', () => { let client; let mockFetch; beforeEach(() => { mockFetch = jest.fn(); global.fetch = mockFetch; client = new StateSetClient({ apiKey: 'sk_test_123', baseUrl: 'https://api.test.StateSet.com/v1' }); }); afterEach(() => { jest.restoreAllMocks(); }); describe('customers.create', () => { it('should create customer successfully', async () => { const customerData = { email: 'test@example.com', first_name: 'John', last_name: 'Doe' }; const expectedResponse = { id: 'cust_123', ...customerData, created_at: '2024-01-15T10:30:00Z' }; mockFetch.mockResolvedValueOnce({ ok: true, status: 201, json: async () => expectedResponse }); const result = await client.customers.create(customerData); expect(mockFetch).toHaveBeenCalledWith( 'https://api.test.StateSet.com/v1/customers', { method: 'POST', headers: { 'Authorization': 'Bearer sk_test_123', 'Content-Type': 'application/json' }, body: JSON.stringify(customerData) } ); expect(result).toEqual(expectedResponse); }); it('should handle validation errors', async () => { const invalidCustomerData = { email: 'invalid-email', first_name: '', last_name: 'Doe' }; const errorResponse = { error: { code: 'VALIDATION_ERROR', message: 'Request validation failed', errors: [ { field: 'email', message: 'Invalid email format' }, { field: 'first_name', message: 'First name is required' } ] } }; mockFetch.mockResolvedValueOnce({ ok: false, status: 400, json: async () => errorResponse }); await expect(client.customers.create(invalidCustomerData)) .rejects.toThrow(StateSetAPIError); try { await client.customers.create(invalidCustomerData); } catch (error) { expect(error.code).toBe('VALIDATION_ERROR'); expect(error.details.errors).toHaveLength(2); expect(error.details.errors[0].field).toBe('email'); } }); it('should handle network errors', async () => { mockFetch.mockRejectedValueOnce(new Error('Network error')); await expect(client.customers.create({})) .rejects.toThrow('Network error'); }); it('should handle rate limiting with retry', async () => { const customerData = { email: 'test@example.com' }; const successResponse = { id: 'cust_123', ...customerData }; // First call returns rate limit error mockFetch .mockResolvedValueOnce({ ok: false, status: 429, headers: new Map([['Retry-After', '1']]), json: async () => ({ error: { code: 'RATE_LIMITED', message: 'Rate limit exceeded' } }) }) // Second call succeeds .mockResolvedValueOnce({ ok: true, status: 201, json: async () => successResponse }); const result = await client.customers.create(customerData); expect(mockFetch).toHaveBeenCalledTimes(2); expect(result).toEqual(successResponse); }); }); describe('orders.list', () => { it('should list orders with filters', async () => { const filters = { status: 'shipped', created_after: '2024-01-01', limit: 10 }; const expectedResponse = { orders: [ { id: 'ord_1', status: 'shipped' }, { id: 'ord_2', status: 'shipped' } ], pagination: { has_more: false, total_count: 2 } }; mockFetch.mockResolvedValueOnce({ ok: true, status: 200, json: async () => expectedResponse }); const result = await client.orders.list(filters); // Verify URL construction with query parameters const expectedUrl = 'https://api.test.StateSet.com/v1/orders?' + 'status=shipped&created_after=2024-01-01&limit=10'; expect(mockFetch).toHaveBeenCalledWith( expectedUrl, expect.objectContaining({ method: 'GET', headers: expect.objectContaining({ 'Authorization': 'Bearer sk_test_123' }) }) ); expect(result).toEqual(expectedResponse); }); }); }); ``` ### Testing Error Handling ```javascript theme={null} // test/unit/errorHandling.test.js import { StateSetErrorHandler } from '../../src/utils/errorHandler'; describe('StateSetErrorHandler', () => { describe('validation errors', () => { it('should extract field errors correctly', () => { const error = { code: 'VALIDATION_ERROR', message: 'Request validation failed', details: { errors: [ { field: 'email', message: 'Invalid email format' }, { field: 'phone', message: 'Phone number required' } ] } }; const result = StateSetErrorHandler.handle(error); expect(result.type).toBe('validation'); expect(result.fieldErrors).toEqual({ email: 'Invalid email format', phone: 'Phone number required' }); }); }); describe('rate limiting', () => { it('should handle rate limit with retry delay', () => { const error = { code: 'RATE_LIMITED', details: { retry_after: 30 } }; const result = StateSetErrorHandler.handle(error); expect(result.type).toBe('rate_limit'); expect(result.retryAfter).toBe(30); expect(result.message).toContain('30 seconds'); }); }); describe('duplicate resources', () => { it('should suggest appropriate action for duplicate email', () => { const error = { code: 'DUPLICATE_EMAIL', details: { email: 'test@example.com', existing_customer_id: 'cust_123' } }; const result = StateSetErrorHandler.handle(error); expect(result.type).toBe('duplicate'); expect(result.suggestion).toBe('Try logging in instead'); }); }); }); ``` ### Testing Business Logic ```javascript theme={null} // test/unit/orderProcessor.test.js import { OrderProcessor } from '../../src/services/orderProcessor'; import { StateSetClient } from 'StateSet-node'; jest.mock('StateSet-node'); describe('OrderProcessor', () => { let orderProcessor; let mockClient; beforeEach(() => { mockClient = { customers: { create: jest.fn(), get: jest.fn() }, orders: { create: jest.fn() }, inventory: { check: jest.fn(), reserve: jest.fn() } }; StateSetClient.mockImplementation(() => mockClient); orderProcessor = new OrderProcessor(); }); describe('processOrder', () => { it('should create customer and order successfully', async () => { const orderData = { customer: { email: 'test@example.com', first_name: 'John', last_name: 'Doe' }, items: [ { sku: 'ITEM-001', quantity: 1, price: 29.99 } ] }; // Mock customer creation mockClient.customers.create.mockResolvedValue({ id: 'cust_123', email: 'test@example.com' }); // Mock inventory check mockClient.inventory.check.mockResolvedValue({ available: true, items: [{ sku: 'ITEM-001', available: true, quantity: 10 }] }); // Mock order creation mockClient.orders.create.mockResolvedValue({ id: 'ord_123', status: 'pending', customer_id: 'cust_123' }); const result = await orderProcessor.processOrder(orderData); expect(mockClient.customers.create).toHaveBeenCalledWith(orderData.customer); expect(mockClient.inventory.check).toHaveBeenCalledWith({ items: orderData.items }); expect(mockClient.orders.create).toHaveBeenCalledWith({ customer_id: 'cust_123', items: orderData.items }); expect(result.orderId).toBe('ord_123'); expect(result.customerId).toBe('cust_123'); }); it('should handle insufficient inventory', async () => { const orderData = { customer: { email: 'test@example.com' }, items: [{ sku: 'ITEM-001', quantity: 5 }] }; mockClient.inventory.check.mockResolvedValue({ available: false, items: [{ sku: 'ITEM-001', available: false, quantity: 2 }] }); await expect(orderProcessor.processOrder(orderData)) .rejects.toThrow('Insufficient inventory'); expect(mockClient.orders.create).not.toHaveBeenCalled(); }); it('should handle existing customer', async () => { const orderData = { customer: { email: 'existing@example.com' }, items: [{ sku: 'ITEM-001', quantity: 1 }] }; // Customer creation fails with duplicate email mockClient.customers.create.mockRejectedValue({ code: 'DUPLICATE_EMAIL', details: { existing_customer_id: 'cust_existing' } }); // Get existing customer mockClient.customers.get.mockResolvedValue({ id: 'cust_existing', email: 'existing@example.com' }); mockClient.inventory.check.mockResolvedValue({ available: true }); mockClient.orders.create.mockResolvedValue({ id: 'ord_456', customer_id: 'cust_existing' }); const result = await orderProcessor.processOrder(orderData); expect(mockClient.customers.get).toHaveBeenCalledWith('cust_existing'); expect(result.customerId).toBe('cust_existing'); }); }); }); ``` ## Integration Testing ### Testing API Endpoints ```javascript theme={null} // test/integration/customers.test.js import { testClient, createTestData, testHelpers } from '../setup.js'; describe('Customer API Integration', () => { const createdResources = []; afterEach(async () => { await testHelpers.cleanupResources(createdResources); createdResources.length = 0; }); describe('Customer lifecycle', () => { it('should create, update, and delete customer', async () => { // Create customer const customerData = createTestData.customer(); const customer = await testClient.customers.create(customerData); createdResources.push({ cleanup: () => testClient.customers.delete(customer.id) }); expect(customer.id).toBeDefined(); expect(customer.email).toBe(customerData.email); expect(customer.status).toBe('active'); // Update customer const updateData = { first_name: 'Updated', customer_tier: 'gold' }; const updatedCustomer = await testClient.customers.update( customer.id, updateData ); expect(updatedCustomer.first_name).toBe('Updated'); expect(updatedCustomer.customer_tier).toBe('gold'); expect(updatedCustomer.email).toBe(customerData.email); // Should remain unchanged // Get customer const retrievedCustomer = await testClient.customers.get(customer.id); expect(retrievedCustomer).toEqual(updatedCustomer); // List customers (should include our customer) const customers = await testClient.customers.list({ email: customerData.email }); expect(customers.customers).toHaveLength(1); expect(customers.customers[0].id).toBe(customer.id); }); it('should prevent duplicate email addresses', async () => { const customerData = createTestData.customer(); // Create first customer const customer1 = await testClient.customers.create(customerData); createdResources.push({ cleanup: () => testClient.customers.delete(customer1.id) }); // Try to create second customer with same email await expect(testClient.customers.create(customerData)) .rejects.toMatchObject({ code: 'DUPLICATE_EMAIL', details: expect.objectContaining({ email: customerData.email, existing_customer_id: customer1.id }) }); }); it('should validate required fields', async () => { const invalidData = { email: 'invalid-email', first_name: '', // Required but empty last_name: 'Test' }; await expect(testClient.customers.create(invalidData)) .rejects.toMatchObject({ code: 'VALIDATION_ERROR', details: expect.objectContaining({ errors: expect.arrayContaining([ expect.objectContaining({ field: 'email', message: expect.stringContaining('Invalid email format') }), expect.objectContaining({ field: 'first_name', message: expect.stringContaining('required') }) ]) }) }); }); }); describe('Customer search and filtering', () => { beforeEach(async () => { // Create test customers with different tiers and statuses const customers = [ { ...createTestData.customer(), customer_tier: 'bronze', first_name: 'Alice' }, { ...createTestData.customer(), customer_tier: 'gold', first_name: 'Bob' }, { ...createTestData.customer(), customer_tier: 'platinum', first_name: 'Charlie' } ]; for (const customerData of customers) { const customer = await testClient.customers.create(customerData); createdResources.push({ cleanup: () => testClient.customers.delete(customer.id) }); } // Wait for eventual consistency await testHelpers.waitFor(1000); }); it('should filter customers by tier', async () => { const goldCustomers = await testClient.customers.list({ customer_tier: 'gold' }); expect(goldCustomers.customers).toHaveLength(1); expect(goldCustomers.customers[0].first_name).toBe('Bob'); }); it('should search customers by name', async () => { const searchResults = await testClient.customers.list({ search: 'Alice' }); expect(searchResults.customers).toHaveLength(1); expect(searchResults.customers[0].first_name).toBe('Alice'); }); it('should paginate results correctly', async () => { const page1 = await testClient.customers.list({ limit: 2, offset: 0 }); expect(page1.customers).toHaveLength(2); expect(page1.pagination.has_more).toBe(true); const page2 = await testClient.customers.list({ limit: 2, offset: 2 }); expect(page2.customers).toHaveLength(1); expect(page2.pagination.has_more).toBe(false); // Ensure no overlap between pages const page1Ids = page1.customers.map(c => c.id); const page2Ids = page2.customers.map(c => c.id); expect(page1Ids).not.toEqual(expect.arrayContaining(page2Ids)); }); }); }); ``` ### Testing Complex Workflows ```javascript theme={null} // test/integration/orderWorkflow.test.js import { testClient, createTestData, testHelpers } from '../setup.js'; describe('Order Workflow Integration', () => { const createdResources = []; afterEach(async () => { await testHelpers.cleanupResources(createdResources); createdResources.length = 0; }); describe('Complete order lifecycle', () => { it('should process order from creation to fulfillment', async () => { // 1. Create customer const customerData = createTestData.customer(); const customer = await testClient.customers.create(customerData); createdResources.push({ cleanup: () => testClient.customers.delete(customer.id) }); // 2. Create order const orderData = createTestData.order(customer.id); const order = await testClient.orders.create(orderData); createdResources.push({ cleanup: () => testClient.orders.delete(order.id) }); expect(order.status).toBe('pending'); expect(order.customer_id).toBe(customer.id); // 3. Process payment (mock payment in sandbox) const payment = await testClient.orders.pay(order.id, { payment_method: { type: 'card', card: { number: '4242424242424242', // Test card exp_month: 12, exp_year: 2025, cvc: '123' } } }); expect(payment.status).toBe('succeeded'); // 4. Check order status updated const paidOrder = await testClient.orders.get(order.id); expect(paidOrder.status).toBe('paid'); expect(paidOrder.payment_status).toBe('paid'); // 5. Ship order const shipment = await testClient.orders.ship(order.id, { carrier: 'fedex', tracking_number: 'TEST123456789', items: orderData.items }); expect(shipment.tracking_number).toBe('TEST123456789'); // 6. Verify final status const shippedOrder = await testClient.orders.get(order.id); expect(shippedOrder.status).toBe('shipped'); expect(shippedOrder.tracking_number).toBe('TEST123456789'); // 7. Create return const returnRequest = await testClient.returns.create({ order_id: order.id, items: [ { sku: orderData.items[0].sku, quantity: 1, reason: 'not_as_described' } ], customer_email: customer.email, reason_code: 'not_satisfied' }); expect(returnRequest.status).toBe('requested'); expect(returnRequest.order_id).toBe(order.id); createdResources.push({ cleanup: () => testClient.returns.delete(returnRequest.id) }); }); it('should handle inventory constraints', async () => { const customer = await testClient.customers.create(createTestData.customer()); createdResources.push({ cleanup: () => testClient.customers.delete(customer.id) }); // Try to order more items than available const orderData = { customer_id: customer.id, items: [ { sku: 'LIMITED-STOCK-ITEM', quantity: 999999, // Exceeds available inventory price: 29.99 } ] }; await expect(testClient.orders.create(orderData)) .rejects.toMatchObject({ code: 'INSUFFICIENT_INVENTORY', details: expect.objectContaining({ unavailable_items: expect.arrayContaining(['LIMITED-STOCK-ITEM']) }) }); }); }); describe('Bulk operations', () => { it('should handle bulk customer creation', async () => { const customerBatch = Array.from({ length: 5 }, () => createTestData.customer()); const results = await Promise.all( customerBatch.map(data => testClient.customers.create(data)) ); // Clean up created customers results.forEach(customer => { createdResources.push({ cleanup: () => testClient.customers.delete(customer.id) }); }); expect(results).toHaveLength(5); results.forEach((customer, index) => { expect(customer.email).toBe(customerBatch[index].email); expect(customer.id).toBeDefined(); }); }); it('should respect rate limits during bulk operations', async () => { const customerBatch = Array.from({ length: 20 }, () => createTestData.customer()); // Create customers with proper rate limiting const results = []; for (const customerData of customerBatch) { try { const customer = await testClient.customers.create(customerData); results.push(customer); createdResources.push({ cleanup: () => testClient.customers.delete(customer.id) }); // Small delay to avoid hitting rate limits await testHelpers.waitFor(100); } catch (error) { if (error.code === 'RATE_LIMITED') { // Wait for rate limit reset and retry await testHelpers.waitFor(error.details.retry_after * 1000); const customer = await testClient.customers.create(customerData); results.push(customer); } else { throw error; } } } expect(results).toHaveLength(20); }); }); }); ``` ## Mock Testing ### Setting Up API Mocks ```javascript theme={null} // test/mocks/StateSetMock.js import { rest } from 'msw'; import { setupServer } from 'msw/node'; // Mock data store const mockData = { customers: new Map(), orders: new Map(), returns: new Map() }; // ID generators const generateId = (prefix) => `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2)}`; // Mock API handlers const handlers = [ // Customer endpoints rest.post('https://api.sandbox.StateSet.com/v1/customers', (req, res, ctx) => { const customerData = req.body; // Validate required fields if (!customerData.email || !customerData.first_name || !customerData.last_name) { return res( ctx.status(400), ctx.json({ error: { code: 'VALIDATION_ERROR', message: 'Missing required fields', errors: [ ...(customerData.email ? [] : [{ field: 'email', message: 'Email is required' }]), ...(customerData.first_name ? [] : [{ field: 'first_name', message: 'First name is required' }]), ...(customerData.last_name ? [] : [{ field: 'last_name', message: 'Last name is required' }]) ] } }) ); } // Check for duplicate email const existingCustomer = Array.from(mockData.customers.values()) .find(c => c.email === customerData.email); if (existingCustomer) { return res( ctx.status(409), ctx.json({ error: { code: 'DUPLICATE_EMAIL', message: 'Customer with this email already exists', details: { email: customerData.email, existing_customer_id: existingCustomer.id } } }) ); } // Create customer const customer = { id: generateId('cust'), ...customerData, status: 'active', created_at: new Date().toISOString(), updated_at: new Date().toISOString() }; mockData.customers.set(customer.id, customer); return res( ctx.status(201), ctx.json(customer) ); }), rest.get('https://api.sandbox.StateSet.com/v1/customers/:id', (req, res, ctx) => { const { id } = req.params; const customer = mockData.customers.get(id); if (!customer) { return res( ctx.status(404), ctx.json({ error: { code: 'RESOURCE_NOT_FOUND', message: 'Customer not found' } }) ); } return res(ctx.json(customer)); }), rest.get('https://api.sandbox.StateSet.com/v1/customers', (req, res, ctx) => { const searchParams = req.url.searchParams; const limit = parseInt(searchParams.get('limit')) || 20; const offset = parseInt(searchParams.get('offset')) || 0; const email = searchParams.get('email'); const tier = searchParams.get('customer_tier'); let customers = Array.from(mockData.customers.values()); // Apply filters if (email) { customers = customers.filter(c => c.email === email); } if (tier) { customers = customers.filter(c => c.customer_tier === tier); } // Apply pagination const totalCount = customers.length; const paginatedCustomers = customers.slice(offset, offset + limit); return res( ctx.json({ customers: paginatedCustomers, pagination: { has_more: offset + limit < totalCount, total_count: totalCount } }) ); }), // Order endpoints rest.post('https://api.sandbox.StateSet.com/v1/orders', (req, res, ctx) => { const orderData = req.body; // Validate customer exists if (!mockData.customers.has(orderData.customer_id)) { return res( ctx.status(400), ctx.json({ error: { code: 'INVALID_CUSTOMER', message: 'Customer not found' } }) ); } // Check inventory (simplified) const hasLimitedStock = orderData.items.some(item => item.sku === 'LIMITED-STOCK-ITEM' && item.quantity > 10 ); if (hasLimitedStock) { return res( ctx.status(422), ctx.json({ error: { code: 'INSUFFICIENT_INVENTORY', message: 'Insufficient inventory', details: { unavailable_items: ['LIMITED-STOCK-ITEM'] } } }) ); } const order = { id: generateId('ord'), ...orderData, status: 'pending', payment_status: 'pending', created_at: new Date().toISOString(), updated_at: new Date().toISOString() }; mockData.orders.set(order.id, order); return res( ctx.status(201), ctx.json(order) ); }), // Rate limiting simulation rest.use((req, res, ctx) => { // Simulate rate limiting for high-frequency requests const isRateLimited = Math.random() < 0.1; // 10% chance if (isRateLimited && req.method === 'POST') { return res( ctx.status(429), ctx.json({ error: { code: 'RATE_LIMITED', message: 'Rate limit exceeded', details: { retry_after: 2 } } }) ); } }) ]; // Create mock server export const mockServer = setupServer(...handlers); // Helper functions export const mockHelpers = { resetData: () => { mockData.customers.clear(); mockData.orders.clear(); mockData.returns.clear(); }, addCustomer: (customer) => { const id = customer.id || generateId('cust'); const fullCustomer = { id, status: 'active', created_at: new Date().toISOString(), updated_at: new Date().toISOString(), ...customer }; mockData.customers.set(id, fullCustomer); return fullCustomer; }, getCustomers: () => Array.from(mockData.customers.values()), getOrders: () => Array.from(mockData.orders.values()) }; ``` ### Using Mocks in Tests ```javascript theme={null} // test/unit/customerService.mock.test.js import { mockServer, mockHelpers } from '../mocks/StateSetMock.js'; import { CustomerService } from '../../src/services/customerService.js'; describe('CustomerService with mocks', () => { let customerService; beforeAll(() => { mockServer.listen(); }); beforeEach(() => { mockHelpers.resetData(); customerService = new CustomerService({ apiKey: 'sk_test_mock', baseUrl: 'https://api.sandbox.StateSet.com/v1' }); }); afterEach(() => { mockServer.resetHandlers(); }); afterAll(() => { mockServer.close(); }); it('should create and retrieve customer', async () => { const customerData = { email: 'test@example.com', first_name: 'John', last_name: 'Doe' }; // Create customer const customer = await customerService.createCustomer(customerData); expect(customer.id).toBeDefined(); expect(customer.email).toBe(customerData.email); // Retrieve customer const retrievedCustomer = await customerService.getCustomer(customer.id); expect(retrievedCustomer).toEqual(customer); }); it('should handle validation errors', async () => { const invalidData = { email: 'test@example.com', // Missing required fields }; await expect(customerService.createCustomer(invalidData)) .rejects.toMatchObject({ code: 'VALIDATION_ERROR' }); }); it('should handle duplicate emails', async () => { const customerData = { email: 'duplicate@example.com', first_name: 'John', last_name: 'Doe' }; // Create first customer await customerService.createCustomer(customerData); // Try to create duplicate await expect(customerService.createCustomer(customerData)) .rejects.toMatchObject({ code: 'DUPLICATE_EMAIL' }); }); it('should paginate customer list', async () => { // Create multiple customers const customers = []; for (let i = 0; i < 5; i++) { customers.push(mockHelpers.addCustomer({ email: `test${i}@example.com`, first_name: `Test${i}`, last_name: 'User' })); } // Get first page const page1 = await customerService.listCustomers({ limit: 2, offset: 0 }); expect(page1.customers).toHaveLength(2); expect(page1.pagination.has_more).toBe(true); // Get second page const page2 = await customerService.listCustomers({ limit: 2, offset: 2 }); expect(page2.customers).toHaveLength(2); expect(page2.pagination.has_more).toBe(true); // Get third page const page3 = await customerService.listCustomers({ limit: 2, offset: 4 }); expect(page3.customers).toHaveLength(1); expect(page3.pagination.has_more).toBe(false); }); }); ``` ## End-to-End Testing ### E2E Test Setup ```javascript theme={null} // test/e2e/setup.js import { Browser, chromium } from '@playwright/test'; import { testClient } from '../setup.js'; export class E2ETestEnvironment { constructor() { this.browser = null; this.context = null; this.page = null; this.baseUrl = process.env.E2E_BASE_URL || 'https://yourapp.com:3000'; } async setup() { this.browser = await chromium.launch({ headless: process.env.CI === 'true' }); this.context = await this.browser.newContext({ // Record videos for failed tests recordVideo: { dir: 'test-results/videos/', size: { width: 1280, height: 720 } } }); this.page = await this.context.newPage(); // Setup API interception for debugging this.page.on('request', request => { if (request.url().includes('api.StateSet.com')) { logger.info('API Request:', request.method(), request.url()); } }); this.page.on('response', response => { if (response.url().includes('api.StateSet.com')) { logger.info('API Response:', response.status(), response.url()); } }); } async teardown() { await this.page?.close(); await this.context?.close(); await this.browser?.close(); } async createTestCustomer() { const customerData = { email: `e2e-test-${Date.now()}@example.com`, first_name: 'E2E', last_name: 'Test', phone: '+1-555-123-4567' }; return await testClient.customers.create(customerData); } async navigateTo(path) { await this.page.goto(`${this.baseUrl}${path}`); } async waitForApiCall(urlPattern) { return await this.page.waitForResponse( response => response.url().includes(urlPattern) && response.status() === 200 ); } } ``` ### E2E User Journey Tests ```javascript theme={null} // test/e2e/customerJourney.test.js import { test, expect } from '@playwright/test'; import { E2ETestEnvironment } from './setup.js'; test.describe('Customer Journey E2E', () => { let testEnv; test.beforeEach(async () => { testEnv = new E2ETestEnvironment(); await testEnv.setup(); }); test.afterEach(async () => { await testEnv.teardown(); }); test('complete customer signup and first order', async () => { const { page } = testEnv; // 1. Navigate to signup page await testEnv.navigateTo('/sign-up'); // 2. Fill out customer form await page.fill('[data-testid="email"]', 'e2e-customer@example.com'); await page.fill('[data-testid="first-name"]', 'John'); await page.fill('[data-testid="last-name"]', 'Doe'); await page.fill('[data-testid="phone"]', '+1-555-123-4567'); // 3. Submit form and wait for API call const createCustomerPromise = testEnv.waitForApiCall('/v1/customers'); await page.click('[data-testid="submit-button"]'); await createCustomerPromise; // 4. Verify redirect to dashboard await expect(page).toHaveURL(/\/dashboard/); // 5. Check customer data is displayed await expect(page.locator('[data-testid="customer-name"]')).toContainText('John Doe'); // 6. Navigate to products page await page.click('[data-testid="products-link"]'); await expect(page).toHaveURL(/\/products/); // 7. Add product to cart await page.click('[data-testid="add-to-cart"]:first-of-type'); // 8. Verify cart updates await expect(page.locator('[data-testid="cart-count"]')).toContainText('1'); // 9. Go to checkout await page.click('[data-testid="cart-button"]'); await page.click('[data-testid="checkout-button"]'); // 10. Fill shipping address await page.fill('[data-testid="street1"]', '123 Test Street'); await page.fill('[data-testid="city"]', 'Test City'); await page.selectOption('[data-testid="state"]', 'CA'); await page.fill('[data-testid="postal-code"]', '12345'); // 11. Enter payment information (test mode) await page.fill('[data-testid="card-number"]', '4242424242424242'); await page.fill('[data-testid="card-expiry"]', '12/25'); await page.fill('[data-testid="card-cvc"]', '123'); // 12. Submit order const createOrderPromise = testEnv.waitForApiCall('/v1/orders'); await page.click('[data-testid="place-order-button"]'); await createOrderPromise; // 13. Verify order confirmation await expect(page).toHaveURL(/\/order-confirmation/); await expect(page.locator('[data-testid="order-number"]')).toBeVisible(); // 14. Extract order number for cleanup const orderNumber = await page.locator('[data-testid="order-number"]').textContent(); logger.info('Created order:', orderNumber); }); test('customer support chat flow', async () => { const { page } = testEnv; // Create a customer first const customer = await testEnv.createTestCustomer(); // 1. Navigate to support page with customer context await testEnv.navigateTo(`/support?customer_id=${customer.id}`); // 2. Start chat await page.click('[data-testid="start-chat-button"]'); // 3. Send message await page.fill('[data-testid="chat-input"]', 'I need help with my order'); await page.click('[data-testid="send-message"]'); // 4. Wait for AI response await page.waitForSelector('[data-testid="ai-response"]', { timeout: 10000 }); // 5. Verify response appears const response = await page.locator('[data-testid="ai-response"]').textContent(); expect(response.length).toBeGreaterThan(0); // 6. Test escalation to human await page.fill('[data-testid="chat-input"]', 'I want to speak to a human'); await page.click('[data-testid="send-message"]'); // 7. Verify escalation UI appears await expect(page.locator('[data-testid="human-handoff"]')).toBeVisible(); }); test('return request flow', async () => { const { page } = testEnv; // Setup: Create customer and order const customer = await testEnv.createTestCustomer(); // Navigate to returns page await testEnv.navigateTo('/returns/create'); // 1. Enter order information await page.fill('[data-testid="order-number"]', 'ORD-TEST-123'); await page.fill('[data-testid="email"]', customer.email); // 2. Click lookup order await page.click('[data-testid="lookup-order"]'); // 3. Select items to return await page.check('[data-testid="return-item-0"]'); // 4. Select reason await page.selectOption('[data-testid="return-reason"]', 'defective'); // 5. Add description await page.fill('[data-testid="return-description"]', 'Product arrived damaged'); // 6. Submit return request const createReturnPromise = testEnv.waitForApiCall('/v1/returns'); await page.click('[data-testid="submit-return"]'); await createReturnPromise; // 7. Verify return confirmation await expect(page.locator('[data-testid="return-number"]')).toBeVisible(); await expect(page.locator('[data-testid="return-status"]')).toContainText('Requested'); }); }); ``` ## Performance Testing ### Load Testing API Endpoints ```javascript theme={null} // test/performance/loadTest.js import { check, sleep } from 'k6'; import http from 'k6/http'; export let options = { stages: [ { duration: '2m', target: 100 }, // Ramp up to 100 users { duration: '5m', target: 100 }, // Stay at 100 users { duration: '2m', target: 200 }, // Ramp up to 200 users { duration: '5m', target: 200 }, // Stay at 200 users { duration: '2m', target: 0 }, // Ramp down to 0 users ], thresholds: { http_req_duration: ['p(95)<500'], // 95% of requests under 500ms http_req_failed: ['rate<0.1'], // Less than 10% error rate }, }; const API_BASE_URL = 'https://api.sandbox.StateSet.com/v1'; const API_KEY = __ENV.STATESET_TEST_API_KEY; export default function () { const headers = { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', }; // Test customer creation const customerData = { email: `loadtest-${__VU}-${__ITER}@example.com`, first_name: 'Load', last_name: 'Test', }; const createResponse = http.post( `${API_BASE_URL}/customers`, JSON.stringify(customerData), { headers } ); check(createResponse, { 'customer creation status is 201': (r) => r.status === 201, 'customer creation response time < 500ms': (r) => r.timings.duration < 500, }); if (createResponse.status === 201) { const customer = JSON.parse(createResponse.body); // Test customer retrieval const getResponse = http.get( `${API_BASE_URL}/customers/${customer.id}`, { headers } ); check(getResponse, { 'customer retrieval status is 200': (r) => r.status === 200, 'customer retrieval response time < 200ms': (r) => r.timings.duration < 200, }); // Test customer list const listResponse = http.get( `${API_BASE_URL}/customers?limit=10`, { headers } ); check(listResponse, { 'customer list status is 200': (r) => r.status === 200, 'customer list response time < 300ms': (r) => r.timings.duration < 300, }); } sleep(1); } ``` ## Continuous Integration ### GitHub Actions Workflow ```yaml theme={null} # .github/workflows/api-tests.yml name: API Tests on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run unit tests run: npm run test:unit env: NODE_ENV: test - name: Upload coverage uses: codecov/codecov-action@v3 with: file: ./coverage/lcov.info integration-tests: runs-on: ubuntu-latest needs: unit-tests steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run integration tests run: npm run test:integration env: STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }} NODE_ENV: test - name: Upload test results uses: actions/upload-artifact@v3 if: failure() with: name: integration-test-results path: test-results/ e2e-tests: runs-on: ubuntu-latest needs: integration-tests steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Install Playwright run: npx playwright install --with-deps - name: Start application run: | npm run build npm run start & sleep 10 env: NODE_ENV: test - name: Run E2E tests run: npm run test:e2e env: STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }} E2E_BASE_URL: https://yourapp.com:3000 - name: Upload E2E results uses: actions/upload-artifact@v3 if: failure() with: name: e2e-test-results path: test-results/ performance-tests: runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 - name: Run k6 performance tests uses: grafana/k6-action@v0.3.0 with: filename: test/performance/loadTest.js env: STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }} ``` ## Test Data Management ### Test Data Factory ```javascript theme={null} // test/factories/testDataFactory.js import { faker } from '@faker-js/faker'; export class TestDataFactory { static customer(overrides = {}) { return { email: faker.internet.email(), first_name: faker.person.firstName(), last_name: faker.person.lastName(), phone: faker.phone.number('+1-###-###-####'), date_of_birth: faker.date.birthdate({ min: 18, max: 80, mode: 'age' }).toISOString().split('T')[0], address: this.address(), customer_tier: faker.helpers.arrayElement(['bronze', 'silver', 'gold', 'platinum']), marketing_consent: faker.datatype.boolean(), ...overrides }; } static address(overrides = {}) { return { street1: faker.location.streetAddress(), street2: faker.helpers.maybe(() => faker.location.secondaryAddress(), 0.3), city: faker.location.city(), state: faker.location.state({ abbreviated: true }), postal_code: faker.location.zipCode(), country: 'US', ...overrides }; } static order(customerId, overrides = {}) { return { customer_id: customerId, items: [this.orderItem()], currency: 'USD', shipping_address: this.address(), billing_address: this.address(), ...overrides }; } static orderItem(overrides = {}) { return { sku: faker.helpers.arrayElement(['WIDGET-001', 'GADGET-002', 'TOOL-003']), quantity: faker.number.int({ min: 1, max: 5 }), price: parseFloat(faker.commerce.price({ min: 10, max: 100, dec: 2 })), ...overrides }; } static returnRequest(orderId, overrides = {}) { return { order_id: orderId, reason_code: faker.helpers.arrayElement(['defective', 'not_satisfied', 'wrong_item']), customer_notes: faker.lorem.sentence(), items: [this.returnItem()], ...overrides }; } static returnItem(overrides = {}) { return { sku: faker.helpers.arrayElement(['WIDGET-001', 'GADGET-002', 'TOOL-003']), quantity: faker.number.int({ min: 1, max: 3 }), reason: faker.helpers.arrayElement(['defective', 'not_as_described', 'wrong_item']), condition: faker.helpers.arrayElement(['A', 'B', 'C']), ...overrides }; } // Scenario-based data generation static scenarioData = { // High-value enterprise customer enterpriseCustomer: () => this.customer({ customer_tier: 'platinum', custom_fields: { company_name: faker.company.name(), industry: 'Technology', company_size: '500+' } }), // Problem order for testing returns problematicOrder: (customerId) => this.order(customerId, { items: [ this.orderItem({ sku: 'DEFECTIVE-ITEM', quantity: 1 }) ] }), // Bulk order bulkOrder: (customerId) => this.order(customerId, { items: Array.from({ length: 5 }, () => this.orderItem()) }) }; } ``` *** ## Summary Comprehensive API testing ensures: 1. **Unit Tests** - Fast feedback on individual components 2. **Integration Tests** - Verify API interactions work correctly 3. **Mock Tests** - Test without external dependencies 4. **E2E Tests** - Validate complete user workflows 5. **Performance Tests** - Ensure system handles load 6. **CI/CD Integration** - Automated testing in deployment pipeline **Testing Best Practices:** * Write tests before implementing features (TDD) * Use descriptive test names that explain the scenario * Keep tests isolated and independent * Clean up test data after each test * Mock external dependencies for faster, more reliable tests * Monitor test performance and maintain fast feedback loops This comprehensive testing approach helps ensure your StateSet API integration is robust, reliable, and ready for production. # Agent Attributes & Personality Source: https://docs.stateset.com/guides/attributes-quickstart Design sophisticated agent personalities with dynamic attributes and behavioral patterns ## Prerequisites Before creating agent attributes, ensure you have: * StateSet account with API access * At least one agent created in your StateSet workspace * API credentials from the [StateSet Dashboard](https://app.StateSet.com/settings/api-keys) * Node.js 16+ installed (for SDK examples) * Basic understanding of JavaScript and REST APIs * Text editor or IDE for development * Familiarity with personality modeling and behavioral psychology concepts * Understanding of your brand voice and customer interaction requirements * Knowledge of customer service best practices and communication styles Code examples focus on core API calls. For production-ready patterns (structured logging, retries, and error handling), see [Error Handling Best Practices](/guides/error-handling-best-practices). ## Introduction Agent Attributes are the building blocks of personality in StateSet. They define not just how your agents communicate, but who they are—their tone, expertise level, decision-making style, and behavioral patterns. This guide shows you how to create agents with distinct, adaptable personalities that align with your brand and customer needs. ## What are Agent Attributes? Agent Attributes are dynamic parameters that shape your agent's behavior, communication style, and decision-making. Unlike static prompts, attributes can change in real-time based on context, allowing your agents to adapt their personality to different situations. ### Core Concepts Define communication style, empathy level, and formality Control decision-making, proactivity, and problem-solving approach Adjust attributes in real-time based on context and customer needs ## Attribute Categories ### 1. Communication Style Attributes ```javascript theme={null} const communicationAttributes = { // Tone and Voice formality: { type: 'scale', range: [0, 100], description: 'How formal vs casual the agent communicates', examples: { 0: "Hey! What's up? How can I help? 😊", 50: "Hello! How can I assist you today?", 100: "Good afternoon. How may I be of service?" } }, // Empathy and Emotional Intelligence empathy_level: { type: 'scale', range: [0, 100], description: 'How much emotional understanding the agent shows', impact: { low: 'Direct, solution-focused responses', medium: 'Acknowledges feelings while solving problems', high: 'Deeply validates emotions before addressing issues' } }, // Communication Preferences verbosity: { type: 'enum', values: ['concise', 'balanced', 'detailed'], description: 'How much detail to include in responses', use_cases: { concise: 'Quick answers for simple questions', balanced: 'Standard customer service', detailed: 'Technical support or complex issues' } }, // Language Complexity language_level: { type: 'enum', values: ['simple', 'standard', 'professional', 'technical'], description: 'Vocabulary and sentence complexity', adapts_to: ['customer_profile', 'topic_complexity'] } }; ``` ### 2. Behavioral Attributes ```javascript theme={null} const behavioralAttributes = { // Decision Making autonomy_level: { type: 'scale', range: [0, 100], description: 'How independently the agent makes decisions', thresholds: { 0: 'Always asks for confirmation', 30: 'Handles routine tasks independently', 70: 'Makes most decisions autonomously', 100: 'Full autonomy within defined bounds' } }, // Problem Solving Approach solution_style: { type: 'enum', values: ['step_by_step', 'quick_fix', 'comprehensive', 'educational'], description: 'How the agent approaches problem resolution', when_to_use: { step_by_step: 'Complex technical issues', quick_fix: 'Simple, common problems', comprehensive: 'VIP customers or critical issues', educational: 'First-time users or learning opportunities' } }, // Proactivity proactivity: { type: 'scale', range: [0, 100], description: 'How proactive vs reactive the agent is', behaviors: { low: 'Answers only what is asked', medium: 'Suggests related solutions', high: 'Anticipates needs and offers preventive advice' } } }; ``` ### 3. Expertise Attributes ```javascript theme={null} const expertiseAttributes = { // Domain Knowledge domain_expertise: { type: 'multi_select', values: ['product', 'technical', 'billing', 'shipping', 'legal'], description: 'Areas where the agent has deep knowledge', confidence_modifiers: { expert: 1.0, familiar: 0.7, basic: 0.4 } }, // Technical Depth technical_level: { type: 'scale', range: [0, 100], description: 'How technical the agent can get', auto_adjust: true, based_on: ['customer_technical_level', 'topic_complexity'] }, // Industry Specialization industry_focus: { type: 'enum', values: ['retail', 'saas', 'healthcare', 'finance', 'general'], description: 'Industry-specific knowledge and compliance', includes: ['terminology', 'regulations', 'best_practices'] } }; ``` ## Creating Dynamic Attributes ### Basic Attribute Creation ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); async function createBasicAttribute(agentId) { const attribute = await client.attributes.create({ agent_id: agentId, type: 'personality', name: 'friendliness', description: 'How warm and friendly the agent appears', value_type: 'scale', default_value: 75, range: { min: 0, max: 100 }, impact: { greeting: 'Affects warmth of initial greeting', sign_off: 'Influences closing statements', emoji_usage: 'Controls emoji frequency' } }); return attribute; } ``` ### Advanced Attribute with Conditions ```javascript theme={null} async function createConditionalAttribute(agentId) { const attribute = await client.attributes.create({ agent_id: agentId, type: 'behavioral', name: 'urgency_response', description: 'How the agent responds to urgent situations', // Dynamic value based on conditions value_logic: { type: 'conditional', conditions: [ { if: 'ticket.priority === "critical"', then: { urgency: 100, response_time: 'immediate' } }, { if: 'customer.tier === "vip" && ticket.priority === "high"', then: { urgency: 90, response_time: '5_minutes' } }, { if: 'ticket.age > 24_hours', then: { urgency: 'urgency + 20', response_time: '30_minutes' } } ], default: { urgency: 50, response_time: '2_hours' } }, // How this affects behavior behaviors: { high_urgency: [ 'Skip pleasantries', 'Get to solution immediately', 'Offer immediate escalation option', 'Follow up proactively' ], low_urgency: [ 'Full greeting and rapport building', 'Thorough explanation', 'Educational approach' ] } }); return attribute; } ``` ### Composite Personality Profiles ```javascript theme={null} class PersonalityBuilder { async createPersonalityProfile(agentId, profileType) { const profiles = { technical_expert: { formality: 70, empathy: 50, technical_depth: 95, verbosity: 'detailed', solution_style: 'educational', proactivity: 80, emoji_usage: 0, code_examples: true }, friendly_support: { formality: 20, empathy: 90, technical_depth: 40, verbosity: 'balanced', solution_style: 'step_by_step', proactivity: 70, emoji_usage: 80, humor_allowed: true }, enterprise_account_manager: { formality: 90, empathy: 70, technical_depth: 60, verbosity: 'concise', solution_style: 'comprehensive', proactivity: 95, business_focus: true, upsell_awareness: 80 }, crisis_manager: { formality: 60, empathy: 85, urgency: 100, verbosity: 'concise', solution_style: 'quick_fix', escalation_threshold: 20, calm_reassurance: true } }; const profile = profiles[profileType]; const attributes = []; for (const [name, value] of Object.entries(profile)) { const attr = await client.attributes.create({ agent_id: agentId, name, value, profile_group: profileType }); attributes.push(attr); } return attributes; } } ``` ## Dynamic Attribute Adjustment ### Real-time Adaptation ```javascript theme={null} class DynamicPersonality { constructor(agentId) { this.agentId = agentId; this.baselineAttributes = {}; this.currentAttributes = {}; } async adaptToContext(context) { const adjustments = this.calculateAdjustments(context); for (const [attribute, adjustment] of Object.entries(adjustments)) { await this.updateAttribute(attribute, adjustment); } } calculateAdjustments(context) { const adjustments = {}; // Adjust formality based on customer if (context.customer.age > 60) { adjustments.formality = 20; // More formal } else if (context.customer.age < 25) { adjustments.formality = -20; // Less formal } // Adjust empathy based on sentiment if (context.sentiment === 'angry') { adjustments.empathy = 30; adjustments.patience = 40; } // Adjust technical level based on customer knowledge if (context.customer.technical_score > 80) { adjustments.technical_depth = 30; adjustments.verbosity = 'detailed'; } // Adjust urgency based on issue type if (context.issue.type === 'outage') { adjustments.urgency = 50; adjustments.solution_style = 'quick_fix'; } return adjustments; } async updateAttribute(name, adjustment) { const current = this.currentAttributes[name] || this.baselineAttributes[name]; let newValue; if (typeof adjustment === 'number') { newValue = Math.max(0, Math.min(100, current + adjustment)); } else { newValue = adjustment; } await client.attributes.update({ agent_id: this.agentId, name, value: newValue }); this.currentAttributes[name] = newValue; } } ``` ### Learning and Evolution ```javascript theme={null} class EvolvingPersonality { async learnFromInteraction(agentId, conversation) { const feedback = await this.analyzeConversation(conversation); // Identify successful patterns if (feedback.satisfaction_score > 4.5) { await this.reinforceAttributes(agentId, conversation.attributes); } // Identify areas for improvement if (feedback.escalated || feedback.satisfaction_score < 3) { await this.adjustWeakAttributes(agentId, feedback.issues); } // Update long-term personality trends await this.updatePersonalityTrends(agentId, feedback); } async reinforceAttributes(agentId, successfulAttributes) { for (const [attr, value] of Object.entries(successfulAttributes)) { await client.attributes.updateTrend({ agent_id: agentId, attribute: attr, trend_direction: 'towards', target_value: value, learning_rate: 0.1 }); } } async analyzeConversation(conversation) { return { satisfaction_score: conversation.rating, escalated: conversation.escalated, resolution_time: conversation.duration, sentiment_progression: this.analyzeSentiment(conversation), successful_tactics: this.identifySuccessfulTactics(conversation) }; } } ``` ## Attribute Templates ### Industry-Specific Templates ```javascript theme={null} const industryTemplates = { healthcare: { attributes: { compliance_awareness: 100, empathy: 85, privacy_consciousness: 100, medical_terminology: true, formality: 70 }, restricted_behaviors: ['humor', 'medical_advice'], required_confirmations: ['patient_identity', 'consent'] }, financial_services: { attributes: { accuracy_focus: 100, regulatory_compliance: 100, formality: 80, numerical_precision: true, security_awareness: 95 }, audit_trail: true, pii_handling: 'strict' }, e_commerce: { attributes: { sales_awareness: 70, product_knowledge: 90, friendliness: 80, urgency_creation: 60, visual_description: true }, upsell_enabled: true, abandoned_cart_recovery: true }, saas_technical: { attributes: { technical_depth: 85, problem_solving: 'systematic', documentation_reference: true, code_literacy: 90, patience: 80 }, integration_knowledge: true, api_fluency: true } }; async function applyIndustryTemplate(agentId, industry) { const template = industryTemplates[industry]; if (!template) { throw new Error(`Unknown industry: ${industry}`); } // Apply all attributes for (const [name, value] of Object.entries(template.attributes)) { await client.attributes.create({ agent_id: agentId, name, value, category: 'industry_standard', locked: true // Prevent accidental changes }); } // Apply behavioral restrictions if (template.restricted_behaviors) { await client.agents.updateRestrictions({ agent_id: agentId, restrictions: template.restricted_behaviors }); } return template; } ``` ## Testing and Validation ### Personality Consistency Testing ```javascript theme={null} class PersonalityTester { async testConsistency(agentId, scenarios) { const results = []; for (const scenario of scenarios) { const response = await this.runScenario(agentId, scenario); const analysis = await this.analyzeResponse(response, scenario.expected_attributes); results.push({ scenario: scenario.name, consistency_score: analysis.consistency, attribute_alignment: analysis.alignment, deviations: analysis.deviations }); } return { overall_consistency: this.calculateOverallConsistency(results), recommendations: this.generateRecommendations(results) }; } async runScenario(agentId, scenario) { return client.agents.test({ agent_id: agentId, input: scenario.input, context: scenario.context, expected_attributes: scenario.expected_attributes }); } analyzeResponse(response, expectedAttributes) { const analysis = { consistency: 0, alignment: {}, deviations: [] }; // Check each expected attribute for (const [attr, expected] of Object.entries(expectedAttributes)) { const actual = this.measureAttribute(response, attr); const deviation = Math.abs(actual - expected); analysis.alignment[attr] = { expected, actual, deviation }; if (deviation > 20) { analysis.deviations.push({ attribute: attr, severity: 'high', recommendation: `Adjust ${attr} baseline or add conditional logic` }); } } analysis.consistency = 100 - (analysis.deviations.length * 10); return analysis; } } ``` ### A/B Testing Personalities ```javascript theme={null} class PersonalityABTest { async runTest(agentId, variantA, variantB, duration) { const test = await client.experiments.create({ type: 'personality_test', agent_id: agentId, variants: { control: variantA, treatment: variantB }, metrics: ['satisfaction_score', 'resolution_time', 'escalation_rate'], duration, traffic_split: 50 }); // Monitor results const monitor = setInterval(async () => { const results = await client.experiments.getResults(test.id); if (results.significant) { await this.applyWinner(agentId, results.winner); clearInterval(monitor); } }, 3600000); // Check hourly return test; } async applyWinner(agentId, winningVariant) { await client.attributes.bulkUpdate({ agent_id: agentId, attributes: winningVariant.attributes, source: 'ab_test_winner' }); } } ``` ## Best Practices ### 1. Attribute Hierarchies ```javascript theme={null} // Good: Clear hierarchy and relationships const attributeHierarchy = { communication: { parent: null, children: ['tone', 'formality', 'verbosity'], weight: 1.0 }, tone: { parent: 'communication', children: ['friendliness', 'professionalism', 'empathy'], weight: 0.8 }, friendliness: { parent: 'tone', children: ['emoji_usage', 'casual_language'], weight: 0.6, constraints: { max_if: { formality: '> 80', value: 30 } } } }; // Bad: Conflicting flat attributes const flatAttributes = { friendly: 100, formal: 100, // Conflicts with friendly professional: 0 // Conflicts with formal }; ``` ### 2. Context-Aware Defaults ```javascript theme={null} // Good: Dynamic defaults based on context const contextAwareDefaults = { getDefaultAttributes(context) { const defaults = { ...this.baseDefaults }; // Time-based adjustments const hour = new Date().getHours(); if (hour < 9 || hour > 17) { defaults.formality -= 10; defaults.brevity += 20; } // Channel-based adjustments if (context.channel === 'sms') { defaults.verbosity = 'concise'; defaults.emoji_usage = 0; } else if (context.channel === 'chat') { defaults.response_speed = 'quick'; defaults.emoji_usage = 40; } return defaults; } }; ``` ### 3. Attribute Validation ```javascript theme={null} class AttributeValidator { validateAttributes(attributes) { const errors = []; // Check for conflicts if (attributes.friendliness > 80 && attributes.formality > 80) { errors.push({ type: 'conflict', message: 'High friendliness conflicts with high formality', suggestion: 'Consider professional_warmth instead' }); } // Check for missing required attributes const required = ['empathy', 'clarity', 'helpfulness']; for (const req of required) { if (!(req in attributes)) { errors.push({ type: 'missing', attribute: req, message: `Required attribute ${req} is missing` }); } } // Check value ranges for (const [attr, value] of Object.entries(attributes)) { if (typeof value === 'number' && (value < 0 || value > 100)) { errors.push({ type: 'range', attribute: attr, message: `${attr} value ${value} is out of range [0-100]` }); } } return errors; } } ``` ## Monitoring and Analytics ### Attribute Performance Tracking ```javascript theme={null} async function trackAttributePerformance(agentId) { const metrics = await client.attributes.getPerformanceMetrics({ agent_id: agentId, timeframe: '30d', group_by: 'attribute' }); const insights = { high_impact: metrics.filter(m => m.correlation_with_satisfaction > 0.7), low_impact: metrics.filter(m => m.correlation_with_satisfaction < 0.3), optimal_ranges: {}, recommendations: [] }; // Find optimal ranges for (const metric of metrics) { const optimal = metric.satisfaction_by_value.reduce((best, current) => current.satisfaction > best.satisfaction ? current : best ); insights.optimal_ranges[metric.attribute] = { range: optimal.value_range, satisfaction: optimal.satisfaction }; } return insights; } ``` ## Next Steps Pre-built personalities for common use cases Build agents that understand and respond to emotions *** **Pro Tip**: Start with a base personality and use conditional attributes to adapt to specific situations. This provides consistency while allowing flexibility. For personality examples and templates, visit our [GitHub repository](https://github.com/StateSet/personality-templates) or contact [support@StateSet.com](mailto:support@StateSet.com). # Batch Operations Guide Source: https://docs.stateset.com/guides/batch-operations Comprehensive guide to batch processing and bulk operations with StateSet API for high-volume data management # Batch Operations Guide Learn how to efficiently process large volumes of data using StateSet's batch operation capabilities. This guide covers bulk creation, updates, imports, exports, and advanced processing patterns for high-throughput scenarios. ## Prerequisites Before you begin, ensure you have: * A StateSet account with appropriate rate limits * Understanding of asynchronous processing patterns * Node.js 16+ installed * Knowledge of database optimization techniques * Experience with queue systems (recommended) ## Core Batch Concepts ### Batch Operation Types Create multiple records in a single operation Update multiple records simultaneously Import large datasets from external sources Export large datasets for reporting or migration ### Performance Considerations ```javascript theme={null} // Batch processing configuration const BATCH_CONFIG = { // Optimal batch sizes for different operations CREATE_BATCH_SIZE: 100, UPDATE_BATCH_SIZE: 200, IMPORT_BATCH_SIZE: 500, EXPORT_BATCH_SIZE: 1000, // Concurrency limits MAX_CONCURRENT_BATCHES: 5, MAX_RETRY_ATTEMPTS: 3, // Rate limiting REQUESTS_PER_SECOND: 10, BURST_LIMIT: 50, // Timeouts BATCH_TIMEOUT: 60000, // 1 minute OPERATION_TIMEOUT: 300000 // 5 minutes }; ``` ## Setting Up Batch Processing Install required packages for batch processing: ```bash theme={null} npm install StateSet-node p-limit p-queue lodash csv-parser fast-csv # or yarn add StateSet-node p-limit p-queue lodash csv-parser fast-csv ``` Set up environment for batch operations: ```bash theme={null} # .env STATESET_API_KEY=your_api_key_here STATESET_ENVIRONMENT=production # Batch Processing Configuration BATCH_WORKER_CONCURRENCY=5 BATCH_QUEUE_SIZE=1000 BATCH_RETRY_ATTEMPTS=3 BATCH_TIMEOUT_MS=300000 # Storage Configuration TEMP_STORAGE_PATH=./temp/batch-files RESULTS_STORAGE_PATH=./results # Queue Configuration (Redis) REDIS_URL=redis://localhost:6379 QUEUE_NAME=StateSet-batch-operations ``` Create a robust batch processing client: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import pLimit from 'p-limit'; import _ from 'lodash'; class BatchProcessor { constructor(options = {}) { this.client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, timeout: options.timeout || 60000 }); this.concurrencyLimit = pLimit(options.concurrency || 5); this.retryAttempts = options.retryAttempts || 3; this.batchSizes = { create: options.createBatchSize || 100, update: options.updateBatchSize || 200, import: options.importBatchSize || 500, export: options.exportBatchSize || 1000 }; this.results = { successful: [], failed: [], skipped: [] }; } async processBatch(operation, data, options = {}) { const startTime = Date.now(); logger.info(`Starting batch ${operation} for ${data.length} items`); try { const batchSize = this.batchSizes[operation] || 100; const batches = _.chunk(data, batchSize); const results = await Promise.allSettled( batches.map((batch, index) => this.concurrencyLimit(() => this.processSingleBatch(operation, batch, index, options) ) ) ); const summary = this.compileBatchResults(results); logger.info(`Batch ${operation} completed in ${Date.now(); - startTime}ms`, summary); return summary; } catch (error) { logger.error(`Batch ${operation} failed:`, error); throw error; } } async processSingleBatch(operation, batch, batchIndex, options) { let attempt = 0; let lastError; while (attempt < this.retryAttempts) { try { logger.info(`Processing batch ${batchIndex + 1}, attempt ${attempt + 1}`); const result = await this.executeBatchOperation(operation, batch, options); return { batchIndex, success: true, count: batch.length, result }; } catch (error) { lastError = error; attempt++; if (attempt < this.retryAttempts) { const delay = Math.pow(2, attempt) * 1000; // Exponential backoff console.warn(`Batch ${batchIndex + 1} failed, retrying in ${delay}ms:`, error.message); await this.delay(delay); } } } return { batchIndex, success: false, count: batch.length, error: lastError.message }; } delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } compileBatchResults(results) { const summary = { total: results.length, successful: 0, failed: 0, totalItems: 0, errors: [] }; results.forEach(result => { if (result.status === 'fulfilled' && result.value.success) { summary.successful++; summary.totalItems += result.value.count; } else { summary.failed++; summary.errors.push(result.reason || result.value.error); } }); return summary; } } ``` ## Bulk Order Operations ### Bulk Order Creation Efficiently create multiple orders: ```javascript theme={null} class OrderBatchProcessor extends BatchProcessor { async bulkCreateOrders(ordersData, options = {}) { return await this.processBatch('create', ordersData, { ...options, validateInput: this.validateOrderData, transformInput: this.transformOrderData }); } async executeBatchOperation(operation, batch, options) { switch (operation) { case 'create': return await this.batchCreateOrders(batch, options); case 'update': return await this.batchUpdateOrders(batch, options); case 'cancel': return await this.batchCancelOrders(batch, options); default: throw new Error(`Unsupported operation: ${operation}`); } } async batchCreateOrders(orders, options = {}) { // Validate orders before processing const validatedOrders = orders.map(order => { if (options.validateInput) { return options.validateInput(order); } return this.validateOrderData(order); }); // Transform orders if needed const transformedOrders = validatedOrders.map(order => { if (options.transformInput) { return options.transformInput(order); } return this.transformOrderData(order); }); // Create orders in parallel with concurrency control const createLimit = pLimit(3); // Limit concurrent creations const results = await Promise.allSettled( transformedOrders.map(order => createLimit(async () => { try { const result = await this.client.orders.create(order); return { success: true, order: result, originalData: order }; } catch (error) { return { success: false, error: error.message, originalData: order }; } }) ) ); return this.processCreateResults(results); } validateOrderData(order) { const required = ['customer_email', 'items']; const missing = required.filter(field => !order[field]); if (missing.length > 0) { throw new Error(`Missing required fields: ${missing.join(', ')}`); } // Validate items if (!Array.isArray(order.items) || order.items.length === 0) { throw new Error('Order must have at least one item'); } order.items.forEach((item, index) => { if (!item.sku || !item.quantity || !item.price) { throw new Error(`Item ${index + 1} missing required fields: sku, quantity, or price`); } }); return order; } transformOrderData(order) { return { ...order, // Add default values status: order.status || 'pending', source: order.source || 'batch_import', created_at: order.created_at || new Date().toISOString(), // Ensure proper data types items: order.items.map(item => ({ ...item, quantity: parseInt(item.quantity, 10), price: parseFloat(item.price) })), // Add metadata metadata: { ...order.metadata, batch_import: true, import_timestamp: new Date().toISOString() } }; } processCreateResults(results) { const summary = { created: [], failed: [], total: results.length }; results.forEach(result => { if (result.status === 'fulfilled') { const value = result.value; if (value.success) { summary.created.push(value.order); } else { summary.failed.push({ error: value.error, data: value.originalData }); } } else { summary.failed.push({ error: result.reason.message, data: null }); } }); return summary; } } // Usage example const orderProcessor = new OrderBatchProcessor({ concurrency: 3 }); const sampleOrders = [ { customer_email: 'customer1@example.com', items: [ { sku: 'PRODUCT-001', quantity: 2, price: 29.99 }, { sku: 'PRODUCT-002', quantity: 1, price: 19.99 } ], shipping_address: { street1: '123 Main St', city: 'Anytown', state: 'CA', zip: '12345', country: 'US' } }, // ... more orders ]; async function bulkCreateOrdersExample() { try { const result = await orderProcessor.bulkCreateOrders(sampleOrders); logger.info(`Successfully created ${result.created.length} orders`); logger.info(`Failed to create ${result.failed.length} orders`); if (result.failed.length > 0) { logger.info('Failed orders:', result.failed); } } catch (error) { logger.error('Bulk order creation failed:', error); } } ``` ### Bulk Order Updates Update multiple orders efficiently: ```javascript theme={null} class OrderUpdateProcessor extends OrderBatchProcessor { async bulkUpdateOrders(updates, options = {}) { return await this.processBatch('update', updates, options); } async batchUpdateOrders(updates, options = {}) { const updateLimit = pLimit(5); // Higher concurrency for updates const results = await Promise.allSettled( updates.map(update => updateLimit(async () => { try { const { id, data } = update; const result = await this.client.orders.update(id, data); return { success: true, order: result, updateData: update }; } catch (error) { return { success: false, error: error.message, updateData: update }; } }) ) ); return this.processUpdateResults(results); } processUpdateResults(results) { const summary = { updated: [], failed: [], total: results.length }; results.forEach(result => { if (result.status === 'fulfilled') { const value = result.value; if (value.success) { summary.updated.push(value.order); } else { summary.failed.push({ error: value.error, data: value.updateData }); } } else { summary.failed.push({ error: result.reason.message, data: null }); } }); return summary; } // Bulk status updates async bulkUpdateOrderStatus(orderIds, newStatus, options = {}) { const updates = orderIds.map(id => ({ id, data: { status: newStatus, updated_at: new Date().toISOString(), status_history: [{ status: newStatus, timestamp: new Date().toISOString(), source: 'batch_update' }] } })); return await this.bulkUpdateOrders(updates, options); } // Bulk tracking number updates async bulkUpdateTrackingNumbers(trackingUpdates, options = {}) { const updates = trackingUpdates.map(({ orderId, trackingNumber, carrier }) => ({ id: orderId, data: { tracking_number: trackingNumber, carrier: carrier, status: 'shipped', shipped_at: new Date().toISOString() } })); return await this.bulkUpdateOrders(updates, options); } } // Usage examples const updateProcessor = new OrderUpdateProcessor(); // Bulk status update await updateProcessor.bulkUpdateOrderStatus( ['ord_123', 'ord_124', 'ord_125'], 'processing' ); // Bulk tracking number update await updateProcessor.bulkUpdateTrackingNumbers([ { orderId: 'ord_123', trackingNumber: 'TRACK123', carrier: 'UPS' }, { orderId: 'ord_124', trackingNumber: 'TRACK124', carrier: 'FedEx' }, { orderId: 'ord_125', trackingNumber: 'TRACK125', carrier: 'USPS' } ]); ``` ## Bulk Inventory Operations ### Inventory Import and Synchronization Handle large inventory datasets: ```javascript theme={null} class InventoryBatchProcessor extends BatchProcessor { async bulkUpdateInventory(inventoryData, options = {}) { return await this.processBatch('update', inventoryData, { ...options, validateInput: this.validateInventoryData, transformInput: this.transformInventoryData }); } async executeBatchOperation(operation, batch, options) { switch (operation) { case 'update': return await this.batchUpdateInventory(batch, options); case 'sync': return await this.batchSyncInventory(batch, options); case 'adjust': return await this.batchAdjustInventory(batch, options); default: throw new Error(`Unsupported inventory operation: ${operation}`); } } async batchUpdateInventory(inventoryItems, options = {}) { const updateLimit = pLimit(8); // Higher concurrency for inventory const results = await Promise.allSettled( inventoryItems.map(item => updateLimit(async () => { try { const result = await this.client.inventory.update(item.sku, { quantity: item.quantity, location: item.location || 'default', updated_at: new Date().toISOString(), source: 'batch_update' }); return { success: true, item: result, originalData: item }; } catch (error) { return { success: false, error: error.message, originalData: item }; } }) ) ); return this.processInventoryResults(results); } // Advanced inventory synchronization async batchSyncInventory(inventoryItems, options = {}) { const { source = 'external_system' } = options; // Group by location for efficient processing const itemsByLocation = _.groupBy(inventoryItems, 'location'); const locationResults = await Promise.allSettled( Object.entries(itemsByLocation).map(([location, items]) => this.syncLocationInventory(location, items, { source }) ) ); return this.compileSyncResults(locationResults); } async syncLocationInventory(location, items, options) { const { source } = options; // Get current inventory for comparison const currentInventory = await this.getCurrentInventory(location); const currentBySku = new Map( currentInventory.map(item => [item.sku, item]) ); const syncOperations = []; for (const item of items) { const current = currentBySku.get(item.sku); if (!current) { // New item - create syncOperations.push({ operation: 'create', sku: item.sku, data: { ...item, location, source, created_at: new Date().toISOString() } }); } else if (current.quantity !== item.quantity) { // Existing item with different quantity - update syncOperations.push({ operation: 'update', sku: item.sku, data: { quantity: item.quantity, location, source, updated_at: new Date().toISOString(), previous_quantity: current.quantity } }); } // Remove from current map (remaining items will be marked as discontinued) currentBySku.delete(item.sku); } // Handle discontinued items for (const [sku, current] of currentBySku.entries()) { if (options.markDiscontinued) { syncOperations.push({ operation: 'discontinue', sku, data: { quantity: 0, location, status: 'discontinued', discontinued_at: new Date().toISOString(), source } }); } } // Execute sync operations return await this.executeSyncOperations(syncOperations); } async executeSyncOperations(operations) { const operationLimit = pLimit(6); const results = await Promise.allSettled( operations.map(op => operationLimit(async () => { try { let result; switch (op.operation) { case 'create': result = await this.client.inventory.create(op.data); break; case 'update': result = await this.client.inventory.update(op.sku, op.data); break; case 'discontinue': result = await this.client.inventory.update(op.sku, op.data); break; default: throw new Error(`Unknown operation: ${op.operation}`); } return { success: true, operation: op.operation, sku: op.sku, result }; } catch (error) { return { success: false, operation: op.operation, sku: op.sku, error: error.message }; } }) ) ); return this.processSyncResults(results); } validateInventoryData(item) { const required = ['sku', 'quantity']; const missing = required.filter(field => item[field] === undefined || item[field] === null); if (missing.length > 0) { throw new Error(`Missing required fields: ${missing.join(', ')}`); } if (typeof item.quantity !== 'number' || item.quantity < 0) { throw new Error('Quantity must be a non-negative number'); } return item; } transformInventoryData(item) { return { ...item, sku: item.sku.toUpperCase().trim(), quantity: parseInt(item.quantity, 10), location: item.location || 'default', updated_at: new Date().toISOString() }; } processInventoryResults(results) { const summary = { updated: [], failed: [], total: results.length }; results.forEach(result => { if (result.status === 'fulfilled') { const value = result.value; if (value.success) { summary.updated.push(value.item); } else { summary.failed.push({ error: value.error, data: value.originalData }); } } else { summary.failed.push({ error: result.reason.message, data: null }); } }); return summary; } } // Usage example const inventoryProcessor = new InventoryBatchProcessor({ concurrency: 8 }); const inventoryUpdates = [ { sku: 'PRODUCT-001', quantity: 150, location: 'warehouse_1' }, { sku: 'PRODUCT-002', quantity: 75, location: 'warehouse_1' }, { sku: 'PRODUCT-003', quantity: 200, location: 'warehouse_2' }, // ... more inventory items ]; await inventoryProcessor.bulkUpdateInventory(inventoryUpdates); ``` ## File-Based Batch Operations ### CSV Import Processing Handle large CSV files efficiently: ```javascript theme={null} import fs from 'fs'; import csv from 'csv-parser'; import { createReadStream } from 'fs'; class CSVBatchProcessor extends BatchProcessor { async processCSVFile(filePath, options = {}) { const { batchSize = 1000, skipHeader = true, transform = null, validate = null } = options; return new Promise((resolve, reject) => { const results = []; const errors = []; let batch = []; let lineNumber = 0; createReadStream(filePath) .pipe(csv()) .on('data', async (row) => { lineNumber++; try { // Apply validation if provided if (validate) { validate(row, lineNumber); } // Apply transformation if provided const transformedRow = transform ? transform(row, lineNumber) : row; batch.push(transformedRow); // Process batch when it reaches the specified size if (batch.length >= batchSize) { const batchResults = await this.processBatch('import', batch); results.push(batchResults); batch = []; } } catch (error) { errors.push({ line: lineNumber, data: row, error: error.message }); } }) .on('end', async () => { try { // Process remaining items in the final batch if (batch.length > 0) { const batchResults = await this.processBatch('import', batch); results.push(batchResults); } resolve({ totalLines: lineNumber, totalBatches: results.length, results, errors }); } catch (error) { reject(error); } }) .on('error', reject); }); } // Order CSV import async importOrdersFromCSV(filePath, options = {}) { return await this.processCSVFile(filePath, { ...options, validate: this.validateOrderCSVRow, transform: this.transformOrderCSVRow }); } validateOrderCSVRow(row, lineNumber) { const required = ['customer_email', 'item_sku', 'item_quantity', 'item_price']; const missing = required.filter(field => !row[field] || row[field].trim() === ''); if (missing.length > 0) { throw new Error(`Line ${lineNumber}: Missing required fields: ${missing.join(', ')}`); } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(row.customer_email)) { throw new Error(`Line ${lineNumber}: Invalid email format`); } // Validate numeric fields if (isNaN(parseFloat(row.item_price)) || parseFloat(row.item_price) <= 0) { throw new Error(`Line ${lineNumber}: Invalid item price`); } if (isNaN(parseInt(row.item_quantity)) || parseInt(row.item_quantity) <= 0) { throw new Error(`Line ${lineNumber}: Invalid item quantity`); } } transformOrderCSVRow(row, lineNumber) { return { customer_email: row.customer_email.trim().toLowerCase(), customer_name: row.customer_name?.trim() || '', items: [{ sku: row.item_sku.trim().toUpperCase(), quantity: parseInt(row.item_quantity, 10), price: parseFloat(row.item_price), name: row.item_name?.trim() || '' }], shipping_address: { street1: row.shipping_street1?.trim() || '', street2: row.shipping_street2?.trim() || '', city: row.shipping_city?.trim() || '', state: row.shipping_state?.trim() || '', zip: row.shipping_zip?.trim() || '', country: row.shipping_country?.trim().toUpperCase() || 'US' }, source: 'csv_import', import_line_number: lineNumber, imported_at: new Date().toISOString() }; } // Generate import report generateImportReport(results, outputPath) { const report = { summary: { total_lines: results.totalLines, total_batches: results.totalBatches, successful_imports: 0, failed_imports: 0, error_count: results.errors.length }, batch_details: [], errors: results.errors }; results.results.forEach((batch, index) => { report.summary.successful_imports += batch.successful || 0; report.summary.failed_imports += batch.failed || 0; report.batch_details.push({ batch_number: index + 1, items_processed: batch.totalItems || 0, successful: batch.successful || 0, failed: batch.failed || 0, errors: batch.errors || [] }); }); // Write report to file fs.writeFileSync(outputPath, JSON.stringify(report, null, 2)); return report; } } // Usage example const csvProcessor = new CSVBatchProcessor({ concurrency: 3 }); async function importOrdersExample() { try { const results = await csvProcessor.importOrdersFromCSV('./orders.csv', { batchSize: 500 }); logger.info(`Processed ${results.totalLines} lines in ${results.totalBatches} batches`); logger.info(`Errors: ${results.errors.length}`); // Generate and save report const report = csvProcessor.generateImportReport(results, './import-report.json'); logger.info('Import report saved to ./import-report.json'); } catch (error) { logger.error('CSV import failed:', error); } } ``` ### Export Operations Export large datasets efficiently: ```javascript theme={null} import { createWriteStream } from 'fs'; import fastCsv from 'fast-csv'; class ExportProcessor extends BatchProcessor { async exportOrdersToCSV(filters = {}, outputPath, options = {}) { const { batchSize = 1000, includeFields = null, transform = null } = options; const writeStream = createWriteStream(outputPath); const csvStream = fastCsv.format({ headers: true }); csvStream.pipe(writeStream); let offset = 0; let hasMore = true; let totalExported = 0; try { while (hasMore) { logger.info(`Exporting batch starting at offset ${offset}`); const orders = await this.client.orders.list({ ...filters, limit: batchSize, offset, include: ['line_items', 'customer', 'shipping_address'] }); if (orders.orders.length === 0) { hasMore = false; break; } // Transform orders for CSV export const transformedOrders = orders.orders.map(order => { const baseData = { order_id: order.id, order_number: order.order_number, customer_email: order.customer_email, customer_name: order.customer_name, status: order.status, total_amount: order.total_amount, created_date: order.created_date, updated_date: order.updated_date }; // Include line items as separate rows or flatten if (order.order_line_items && order.order_line_items.length > 0) { return order.order_line_items.map(item => ({ ...baseData, item_sku: item.sku_name, item_name: item.product_name, item_quantity: item.quantity, item_price: item.sale_price, item_brand: item.brand })); } return [baseData]; }).flat(); // Apply custom transformation if provided const finalData = transform ? transformedOrders.map(transform) : transformedOrders; // Filter fields if specified const filteredData = includeFields ? finalData.map(row => _.pick(row, includeFields)) : finalData; // Write to CSV for (const row of filteredData) { csvStream.write(row); } totalExported += filteredData.length; offset += batchSize; // Check if we have more data hasMore = orders.orders.length === batchSize; // Add delay to respect rate limits await this.delay(100); } csvStream.end(); return new Promise((resolve, reject) => { writeStream.on('finish', () => { logger.info(`Export completed: ${totalExported} records exported to ${outputPath}`); resolve({ totalExported, outputPath }); }); writeStream.on('error', reject); }); } catch (error) { csvStream.end(); throw error; } } // Export with progress tracking async exportOrdersWithProgress(filters = {}, outputPath, options = {}) { const { onProgress = null, ...exportOptions } = options; // Get total count first const countResponse = await this.client.orders.list({ ...filters, limit: 1 }); const totalOrders = countResponse.total_count; let processedOrders = 0; // Wrap the export with progress tracking const progressTracker = { onProgress: (batch) => { processedOrders += batch.length; const progress = Math.round((processedOrders / totalOrders) * 100); logger.info(`Export progress: ${processedOrders}/${totalOrders} (${progress}%);`); if (onProgress) { onProgress({ processed: processedOrders, total: totalOrders, percentage: progress }); } } }; return await this.exportOrdersToCSV(filters, outputPath, { ...exportOptions, progressTracker }); } } // Usage example const exportProcessor = new ExportProcessor(); // Export all orders from the last 30 days const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(); await exportProcessor.exportOrdersWithProgress( { created_after: thirtyDaysAgo, status_in: ['processing', 'shipped', 'delivered'] }, './orders-export.csv', { batchSize: 500, includeFields: [ 'order_id', 'order_number', 'customer_email', 'status', 'total_amount', 'created_date', 'item_sku', 'item_quantity' ], onProgress: (progress) => { // Update progress bar or send notification logger.info(`Progress: ${progress.percentage}%`); } } ); ``` ## Queue-Based Batch Processing ### Background Job Processing Implement robust background processing with queues: ```javascript theme={null} import Queue from 'bull'; import Redis from 'ioredis'; class QueuedBatchProcessor extends BatchProcessor { constructor(options = {}) { super(options); this.redis = new Redis(process.env.REDIS_URL); this.batchQueue = new Queue('batch operations', process.env.REDIS_URL); this.setupJobProcessors(); this.setupEventHandlers(); } setupJobProcessors() { // Process batch creation jobs this.batchQueue.process('bulk-create-orders', 5, async (job) => { const { orders, options } = job.data; job.progress(0); try { const result = await this.bulkCreateOrders(orders, { ...options, onProgress: (progress) => { job.progress(Math.round((progress.completed / progress.total) * 100)); } }); job.progress(100); return result; } catch (error) { logger.error('Batch job failed:', error); throw error; } }); // Process batch update jobs this.batchQueue.process('bulk-update-orders', 3, async (job) => { const { updates, options } = job.data; job.progress(0); const result = await this.bulkUpdateOrders(updates, { ...options, onProgress: (progress) => { job.progress(Math.round((progress.completed / progress.total) * 100)); } }); job.progress(100); return result; }); // Process CSV import jobs this.batchQueue.process('csv-import', 1, async (job) => { const { filePath, type, options } = job.data; job.progress(0); let result; switch (type) { case 'orders': result = await this.importOrdersFromCSV(filePath, { ...options, onProgress: (progress) => { job.progress(Math.round((progress.completed / progress.total) * 100)); } }); break; case 'inventory': result = await this.importInventoryFromCSV(filePath, options); break; default: throw new Error(`Unsupported import type: ${type}`); } job.progress(100); return result; }); } setupEventHandlers() { this.batchQueue.on('completed', (job, result) => { logger.info(`Job ${job.id} completed successfully`); this.notifyJobCompletion(job, result, 'completed'); }); this.batchQueue.on('failed', (job, err) => { logger.error(`Job ${job.id} failed:`, err); this.notifyJobCompletion(job, null, 'failed', err); }); this.batchQueue.on('progress', (job, progress) => { logger.info(`Job ${job.id} progress: ${progress}%`); }); } async queueBulkCreateOrders(orders, options = {}) { const job = await this.batchQueue.add('bulk-create-orders', { orders, options }, { attempts: 3, backoff: { type: 'exponential', delay: 2000 }, removeOnComplete: 10, removeOnFail: 5 }); return { jobId: job.id, status: 'queued' }; } async queueCSVImport(filePath, type, options = {}) { const job = await this.batchQueue.add('csv-import', { filePath, type, options }, { attempts: 2, timeout: 300000, // 5 minutes removeOnComplete: 5, removeOnFail: 3 }); return { jobId: job.id, status: 'queued' }; } async getJobStatus(jobId) { const job = await this.batchQueue.getJob(jobId); if (!job) { return { status: 'not_found' }; } const state = await job.getState(); const progress = job.progress(); return { jobId: job.id, status: state, progress, data: job.data, result: job.returnvalue, error: job.failedReason, created: job.timestamp, processed: job.processedOn, finished: job.finishedOn }; } async notifyJobCompletion(job, result, status, error = null) { const notification = { jobId: job.id, jobType: job.name, status, timestamp: new Date().toISOString(), result, error: error?.message }; // Send webhook notification if (process.env.WEBHOOK_NOTIFICATION_URL) { try { await fetch(process.env.WEBHOOK_NOTIFICATION_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(notification) }); } catch (webhookError) { logger.error('Failed to send webhook notification:', webhookError); } } // Store notification in database or send email // Implementation depends on your notification system } } // Usage example const queueProcessor = new QueuedBatchProcessor(); // Queue a bulk order creation job const createJob = await queueProcessor.queueBulkCreateOrders(sampleOrders, { validateInput: true, notifyOnCompletion: true }); logger.info(`Bulk create job queued with ID: ${createJob.jobId}`); // Check job status setInterval(async () => { const status = await queueProcessor.getJobStatus(createJob.jobId); logger.info(`Job ${createJob.jobId} status:`, status); if (['completed', 'failed'].includes(status.status)) { clearInterval(this); } }, 5000); ``` ## Performance Optimization ### Memory Management and Streaming Handle very large datasets efficiently: ```javascript theme={null} class StreamingBatchProcessor extends BatchProcessor { async streamProcessLargeDataset(dataStream, processor, options = {}) { const { batchSize = 1000, maxMemoryUsage = 512 * 1024 * 1024, // 512MB gcInterval = 10000 // Force GC every 10k items } = options; let batch = []; let processedCount = 0; let errorCount = 0; return new Promise((resolve, reject) => { dataStream .on('data', async (item) => { batch.push(item); if (batch.length >= batchSize) { try { // Pause stream while processing batch dataStream.pause(); const result = await processor(batch); processedCount += result.successful || 0; errorCount += result.failed || 0; // Clear batch and force garbage collection if needed batch = []; if (processedCount % gcInterval === 0) { this.forceGarbageCollection(); this.checkMemoryUsage(maxMemoryUsage); } // Resume stream dataStream.resume(); } catch (error) { dataStream.destroy(error); return; } } }) .on('end', async () => { try { // Process final batch if (batch.length > 0) { const result = await processor(batch); processedCount += result.successful || 0; errorCount += result.failed || 0; } resolve({ processed: processedCount, errors: errorCount, total: processedCount + errorCount }); } catch (error) { reject(error); } }) .on('error', reject); }); } forceGarbageCollection() { if (global.gc) { global.gc(); logger.info('Forced garbage collection'); } } checkMemoryUsage(maxUsage) { const used = process.memoryUsage(); if (used.heapUsed > maxUsage) { console.warn(`High memory usage detected: ${Math.round(used.heapUsed / 1024 / 1024)}MB`); if (used.heapUsed > maxUsage * 1.5) { throw new Error('Memory usage too high, aborting batch processing'); } } } // Optimized batch processing with connection pooling async optimizedBatchProcess(data, operation, options = {}) { const { connectionPoolSize = 10, maxRetries = 3, retryDelay = 1000 } = options; // Create connection pool const pool = Array.from({ length: connectionPoolSize }, () => new StateSetClient({ apiKey: process.env.STATESET_API_KEY, timeout: 60000, keepAlive: true }) ); let poolIndex = 0; const getClient = () => { const client = pool[poolIndex % pool.length]; poolIndex++; return client; }; try { const processLimit = pLimit(connectionPoolSize); const results = await Promise.allSettled( data.map(item => processLimit(async () => { let attempt = 0; let lastError; while (attempt < maxRetries) { try { const client = getClient(); const result = await this.executeOperation(client, operation, item); return { success: true, result, item }; } catch (error) { lastError = error; attempt++; if (attempt < maxRetries) { await this.delay(retryDelay * Math.pow(2, attempt - 1)); } } } return { success: false, error: lastError.message, item }; }) ) ); return this.compileResults(results); } finally { // Clean up connection pool for (const client of pool) { if (client.destroy) { client.destroy(); } } } } async executeOperation(client, operation, item) { switch (operation) { case 'create_order': return await client.orders.create(item); case 'update_order': return await client.orders.update(item.id, item.data); case 'update_inventory': return await client.inventory.update(item.sku, item.data); default: throw new Error(`Unsupported operation: ${operation}`); } } } ``` ## Best Practices and Monitoring ### Comprehensive Monitoring Monitor batch operation performance: ```javascript theme={null} class BatchMonitor { constructor() { this.metrics = { totalOperations: 0, successfulOperations: 0, failedOperations: 0, averageProcessingTime: 0, peakMemoryUsage: 0, operationHistory: [] }; } recordOperation(operation, duration, success, memoryUsage) { this.metrics.totalOperations++; if (success) { this.metrics.successfulOperations++; } else { this.metrics.failedOperations++; } // Update average processing time const totalTime = this.metrics.averageProcessingTime * (this.metrics.totalOperations - 1) + duration; this.metrics.averageProcessingTime = totalTime / this.metrics.totalOperations; // Track peak memory usage if (memoryUsage > this.metrics.peakMemoryUsage) { this.metrics.peakMemoryUsage = memoryUsage; } // Store operation history (keep last 1000) this.metrics.operationHistory.push({ operation, duration, success, memoryUsage, timestamp: new Date().toISOString() }); if (this.metrics.operationHistory.length > 1000) { this.metrics.operationHistory.shift(); } } getSuccessRate() { if (this.metrics.totalOperations === 0) return 0; return (this.metrics.successfulOperations / this.metrics.totalOperations) * 100; } generateReport() { return { summary: { total_operations: this.metrics.totalOperations, successful_operations: this.metrics.successfulOperations, failed_operations: this.metrics.failedOperations, success_rate: `${this.getSuccessRate().toFixed(2)}%`, average_processing_time: `${this.metrics.averageProcessingTime.toFixed(2)}ms`, peak_memory_usage: `${(this.metrics.peakMemoryUsage / 1024 / 1024).toFixed(2)}MB` }, recent_operations: this.metrics.operationHistory.slice(-10), recommendations: this.generateRecommendations() }; } generateRecommendations() { const recommendations = []; const successRate = this.getSuccessRate(); if (successRate < 95) { recommendations.push('Consider reducing batch size or improving error handling'); } if (this.metrics.averageProcessingTime > 30000) { recommendations.push('Processing time is high, consider optimizing batch operations'); } if (this.metrics.peakMemoryUsage > 1024 * 1024 * 1024) { recommendations.push('High memory usage detected, consider streaming or smaller batches'); } return recommendations; } } // Enhanced batch processor with monitoring class MonitoredBatchProcessor extends StreamingBatchProcessor { constructor(options = {}) { super(options); this.monitor = new BatchMonitor(); } async processBatch(operation, data, options = {}) { const startTime = Date.now(); const startMemory = process.memoryUsage().heapUsed; try { const result = await super.processBatch(operation, data, options); const duration = Date.now() - startTime; const endMemory = process.memoryUsage().heapUsed; this.monitor.recordOperation(operation, duration, true, endMemory); return { ...result, processingTime: duration, memoryUsed: endMemory - startMemory }; } catch (error) { const duration = Date.now() - startTime; const endMemory = process.memoryUsage().heapUsed; this.monitor.recordOperation(operation, duration, false, endMemory); throw error; } } getMonitoringReport() { return this.monitor.generateReport(); } } ``` ## Troubleshooting * Use streaming for large datasets * Implement proper garbage collection * Monitor memory usage and set limits * Process data in smaller batches * Implement proper retry logic with exponential backoff * Use connection pooling * Monitor API rate limits * Distribute load across multiple time periods * Implement comprehensive validation * Use transformation functions * Handle edge cases and malformed data * Provide detailed error reporting * Optimize batch sizes for your use case * Use appropriate concurrency limits * Implement caching where possible * Monitor and profile operations ## Next Steps Test your batch operations thoroughly Set up comprehensive monitoring Optimize batch processing performance Learn integration best practices ## Conclusion Efficient batch processing is crucial for handling large volumes of data in production systems. This guide provides comprehensive patterns for: * ✅ Bulk order and inventory operations * ✅ CSV import/export processing * ✅ Queue-based background processing * ✅ Memory-efficient streaming operations * ✅ Performance monitoring and optimization With these patterns, you can build robust, scalable batch processing systems that handle high-volume operations efficiently while maintaining data integrity and system performance. # CCTP Module Integration Guide Source: https://docs.stateset.com/guides/cctp-module-integration Complete guide to integrating with StateSet's native CCTP module for cross-chain USDC transfers # CCTP Module Integration Guide ## Overview This guide covers integrating with StateSet's native CCTP module implementation. Unlike EVM chains where CCTP is implemented via smart contracts, StateSet has built CCTP directly into the blockchain as a Cosmos SDK module, providing superior performance, security, and integration capabilities. ## Architecture Overview ```mermaid theme={null} graph TB A[Your Application] --> B[StateSet CCTP Module] B --> C[Message Handler] B --> D[Attestation Manager] B --> E[Burn/Mint Engine] C --> F[Other Chains via IBC/CCTP] D --> G[Circle Attestation Service] E --> H[StateSet Bank Module] B --> I[Orders Module] B --> J[Finance Module] B --> K[Agent Module] ``` ## Setting Up Your Development Environment ### 1. Install StateSet CLI ```bash theme={null} # Download and install the StateSet CLI curl -L https://get.StateSet.network | bash # Verify installation StateSet version # Output: v1.0.0 # Configure for testnet StateSet config chain-id StateSet-testnet-1 StateSet config node https://rpc-test.StateSet.network:443 ``` ### 2. Create Test Accounts ```bash theme={null} # Create a new account StateSet keys add testaccount # Get testnet USDC from faucet curl -X POST https://faucet-test.StateSet.network/credit \ -H "Content-Type: application/json" \ -d '{"address": "StateSet1...", "coins": ["1000000usdc"]}' ``` ### 3. Install SDKs ```bash theme={null} # JavaScript/TypeScript npm install @StateSet/cctp-sdk @StateSet/client # Go go get github.com/StateSet/StateSet/x/cctp # Python pip install StateSet-cctp ``` ## Basic Integration ### JavaScript/TypeScript ```typescript theme={null} import { StateSetClient } from '@StateSet/client'; import { CCTPModule } from '@StateSet/cctp-sdk'; // Initialize client const client = await StateSetClient.connect('https://rpc.StateSet.network'); const cctp = new CCTPModule(client); // Set up signer const signer = await client.getSigner('your-mnemonic-or-private-key'); // Example: Burn USDC to transfer to Ethereum async function transferToEthereum() { const burnMsg = { from: signer.address, amount: { denom: 'usdc', amount: '1000000000' // 1000 USDC (6 decimals) }, destinationDomain: 0, // Ethereum mintRecipient: ethers.utils.hexZeroPad('0x742d35...', 32), burnToken: 'usdc' }; // Execute burn const tx = await cctp.depositForBurn(burnMsg); logger.info('Burn tx hash:', tx.transactionHash); logger.info('Message hash:', tx.messageHash); // Wait for attestation from Circle const attestation = await cctp.waitForAttestation(tx.messageHash); logger.info('Attestation received:', attestation); // The attestation can now be used on Ethereum to mint the USDC return { message: tx.message, attestation }; } ``` ### Go Integration ```go theme={null} package main import ( "context" "fmt" "github.com/cosmos/cosmos-sdk/client" "github.com/StateSet/StateSet/x/cctp/types" "github.com/StateSet/StateSet/x/cctp/client/cli" ) func TransferUSDC(ctx context.Context, clientCtx client.Context) error { // Create deposit for burn message msg := &types.MsgDepositForBurn{ From: clientCtx.GetFromAddress().String(), Amount: sdk.NewCoin("usdc", sdk.NewInt(1000000000)), DestinationDomain: 0, // Ethereum MintRecipient: hexutil.MustDecode("0x742d35Cc6634C0532925a3b844Bc9e7595f6E321"), BurnToken: "usdc", } // Validate message if err := msg.ValidateBasic(); err != nil { return fmt.Errorf("invalid message: %w", err) } // Broadcast transaction res, err := cli.BroadcastTx(clientCtx, msg) if err != nil { return fmt.Errorf("broadcast failed: %w", err) } // Extract message hash from events messageHash := ExtractMessageHash(res.Events) fmt.Printf("Message hash: %s\n", messageHash) return nil } ``` ### Python Integration ```python theme={null} from StateSet_cctp import CCTPClient, DepositForBurnMsg from StateSet_cctp.attestation import AttestationService # Initialize client client = CCTPClient( rpc_endpoint="https://rpc.StateSet.network", private_key="your-private-key" ) # Transfer USDC to Arbitrum async def transfer_to_arbitrum(): # Create burn message msg = DepositForBurnMsg( from_address=client.address, amount={"denom": "usdc", "amount": "500000000"}, # 500 USDC destination_domain=3, # Arbitrum mint_recipient=format_evm_address("0x742d35..."), burn_token="usdc" ) # Execute burn result = await client.deposit_for_burn(msg) print(f"Transaction hash: {result.tx_hash}") print(f"Message hash: {result.message_hash}") # Get attestation attestation_service = AttestationService() attestation = await attestation_service.get_attestation( result.message_hash ) return { "message": result.message, "attestation": attestation } ``` ## Advanced Integration Patterns ### 1. Cross-Chain Order Processing ```typescript theme={null} // Process orders with payment on any supported chain class CrossChainOrderProcessor { constructor( private cctp: CCTPModule, private orderModule: OrderModule ) {} async processOrderWithCrossChainPayment( orderId: string, paymentChain: number, paymentTx: string ) { // Verify payment on source chain const payment = await this.verifyPayment(paymentChain, paymentTx); if (paymentChain !== STATESET_DOMAIN) { // Wait for CCTP transfer to complete const cctpTransfer = await this.waitForCCTPTransfer( payment.messageHash ); // Update order with payment await this.orderModule.updatePayment({ orderId, paymentInfo: { type: 'cross_chain_usdc', sourceChain: paymentChain, amount: cctpTransfer.amount, transactionHash: cctpTransfer.txHash } }); } // Fulfill order await this.orderModule.fulfillOrder(orderId); } private async waitForCCTPTransfer(messageHash: string) { // Monitor for receive message transaction return new Promise((resolve) => { const subscription = this.cctp.subscribeToEvents({ messageHash }).subscribe(event => { if (event.type === 'mint_and_withdraw') { subscription.unsubscribe(); resolve(event); } }); }); } } ``` ### 2. Multi-Signature CCTP Operations ```typescript theme={null} // Require multiple signatures for large CCTP transfers class MultiSigCCTP { constructor( private cctp: CCTPModule, private multisig: MultisigModule ) {} async proposeTransfer(params: CCTPTransferParams) { // Create multisig proposal const proposal = await this.multisig.createProposal({ messages: [{ type: 'cctp/MsgDepositForBurn', value: { from: this.multisig.address, amount: params.amount, destinationDomain: params.destinationDomain, mintRecipient: params.recipient, burnToken: 'usdc' } }], metadata: { title: `CCTP Transfer ${params.amount.amount} USDC to chain ${params.destinationDomain}`, description: params.description } }); return proposal.id; } async executeTransfer(proposalId: string) { // Check if proposal is approved const proposal = await this.multisig.getProposal(proposalId); if (!proposal.isApproved()) { throw new Error('Proposal not approved'); } // Execute the transfer return await this.multisig.executeProposal(proposalId); } } ``` ### 3. Automated Cross-Chain Treasury Management ```typescript theme={null} // Automatically rebalance treasury across chains class TreasuryManager { private readonly TARGET_BALANCE = 100000; // $100k USDC per chain private readonly REBALANCE_THRESHOLD = 0.2; // 20% deviation async rebalanceAllChains() { const balances = await this.getAllChainBalances(); const transfers = this.calculateOptimalTransfers(balances); // Execute transfers in parallel where possible const transferPromises = transfers.map(transfer => this.executeCCTPTransfer(transfer) ); const results = await Promise.allSettled(transferPromises); // Log results results.forEach((result, index) => { if (result.status === 'fulfilled') { logger.info(`Transfer ${index} completed:`, result.value); } else { logger.error(`Transfer ${index} failed:`, result.reason); } }); } private calculateOptimalTransfers(balances: ChainBalance[]): Transfer[] { const totalBalance = balances.reduce((sum, b) => sum + b.amount, 0); const targetPerChain = totalBalance / balances.length; const transfers: Transfer[] = []; const surplus = balances.filter(b => b.amount > targetPerChain * (1 + this.REBALANCE_THRESHOLD)); const deficit = balances.filter(b => b.amount < targetPerChain * (1 - this.REBALANCE_THRESHOLD)); // Match surplus with deficit chains for (const source of surplus) { for (const dest of deficit) { const transferAmount = Math.min( source.amount - targetPerChain, targetPerChain - dest.amount ); if (transferAmount > 1000) { // Min $1k transfer transfers.push({ sourceChain: source.domain, destChain: dest.domain, amount: transferAmount }); source.amount -= transferAmount; dest.amount += transferAmount; } } } return transfers; } } ``` ### 4. CCTP Rate Limiting and Compliance ```typescript theme={null} // Implement rate limiting and compliance checks class ComplianceCCTP { private dailyLimits = new Map(); private readonly MAX_DAILY_LIMIT = 1000000; // $1M USDC async transferWithCompliance(params: CCTPTransferParams) { // Check daily limits const dailyTotal = await this.getDailyTotal(params.from); if (dailyTotal + parseInt(params.amount.amount) > this.MAX_DAILY_LIMIT) { throw new Error('Daily transfer limit exceeded'); } // Compliance checks if (await this.isBlacklisted(params.mintRecipient)) { throw new Error('Recipient address is blacklisted'); } // Check destination chain restrictions if (!await this.isDestinationAllowed(params.from, params.destinationDomain)) { throw new Error('Transfers to this destination not allowed'); } // Execute transfer with monitoring const result = await this.cctp.depositForBurn(params); // Record for compliance await this.recordTransfer({ from: params.from, amount: params.amount, destination: params.destinationDomain, recipient: params.mintRecipient, timestamp: Date.now(), messageHash: result.messageHash }); return result; } } ``` ## Module Queries ### CLI Queries ```bash theme={null} # Query module configuration StateSet query cctp owner StateSet query cctp signature-threshold StateSet query cctp max-message-body-size # Query attesters StateSet query cctp attesters StateSet query cctp attester StateSet1attester... # Query token pairs StateSet query cctp token-pairs StateSet query cctp token-pair 0 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 # Query burn limits StateSet query cctp per-message-burn-limit usdc # Query paused state StateSet query cctp burning-minting-paused StateSet query cctp sending-receiving-paused ``` ### SDK Queries ```typescript theme={null} // Query module state const owner = await cctp.query.owner(); const threshold = await cctp.query.signatureThreshold(); const attesters = await cctp.query.attesters(); // Query specific token pair const tokenPair = await cctp.query.tokenPair({ remoteDomain: 0, remoteToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' }); // Query burn limits const burnLimit = await cctp.query.perMessageBurnLimit({ token: 'usdc' }); ``` ## Event Monitoring ### Subscribe to CCTP Events ```typescript theme={null} // Monitor all CCTP events const subscription = cctp.subscribeToEvents() .subscribe(event => { switch(event.type) { case 'deposit_for_burn': logger.info('Burn initiated:', event); trackBurn(event); break; case 'message_sent': logger.info('Message sent:', event); break; case 'message_received': logger.info('Message received:', event); trackReceive(event); break; case 'mint_and_withdraw': logger.info('USDC minted:', event); completeTrasfer(event); break; } }); // Monitor specific message const messageSubscription = cctp.subscribeToMessage(messageHash) .subscribe(update => { logger.info('Message status:', update.status); if (update.status === 'completed') { messageSubscription.unsubscribe(); } }); ``` ### Webhook Integration ```typescript theme={null} // Set up webhooks for CCTP events app.post('/webhooks/cctp', async (req, res) => { const event = req.body; // Verify webhook signature if (!verifyWebhookSignature(req)) { return res.status(401).send('Invalid signature'); } // Process event switch(event.type) { case 'cctp.deposit_for_burn': await handleBurnEvent(event); break; case 'cctp.mint_and_withdraw': await handleMintEvent(event); break; case 'cctp.message_received': await handleMessageReceived(event); break; } res.status(200).send('OK'); }); ``` ## Testing ### Unit Tests ```typescript theme={null} import { MockCCTPModule } from '@StateSet/cctp-sdk/testing'; describe('CCTP Integration', () => { let cctp: MockCCTPModule; beforeEach(() => { cctp = new MockCCTPModule(); }); it('should burn USDC for cross-chain transfer', async () => { const burnMsg = { from: 'StateSet1test...', amount: { denom: 'usdc', amount: '1000000' }, destinationDomain: 0, mintRecipient: '0x742d35...', burnToken: 'usdc' }; const result = await cctp.depositForBurn(burnMsg); expect(result.transactionHash).toBeDefined(); expect(result.messageHash).toBeDefined(); expect(result.nonce).toBeGreaterThan(0); }); }); ``` ### Integration Tests ```typescript theme={null} // Test full cross-chain flow describe('Cross-chain USDC Transfer', () => { it('should complete transfer from StateSet to Ethereum', async () => { // 1. Burn on StateSet const burnResult = await StateSetCCTP.depositForBurn({ amount: { denom: 'usdc', amount: '1000000000' }, destinationDomain: 0, mintRecipient: ethRecipient, burnToken: 'usdc' }); // 2. Wait for attestation const attestation = await waitForAttestation(burnResult.messageHash); expect(attestation).toBeDefined(); // 3. Mint on Ethereum const mintTx = await ethereumCCTP.receiveMessage( burnResult.message, attestation ); // 4. Verify balance const balance = await ethereumUSDC.balanceOf(ethRecipient); expect(balance.toString()).toBe('1000000000'); }); }); ``` ## Error Handling ### Common Errors and Solutions ```typescript theme={null} class CCTPErrorHandler { async handleCCTPOperation(operation: () => Promise) { try { return await operation(); } catch (error) { if (error.code === 'INSUFFICIENT_FUNDS') { throw new Error('Insufficient USDC balance for transfer'); } if (error.code === 'INVALID_RECIPIENT') { throw new Error('Recipient address format is invalid'); } if (error.code === 'PAUSED') { throw new Error('CCTP operations are currently paused'); } if (error.code === 'BURN_LIMIT_EXCEEDED') { throw new Error('Transfer amount exceeds per-message burn limit'); } if (error.code === 'NONCE_ALREADY_USED') { throw new Error('This message has already been processed'); } // Unknown error logger.error('CCTP operation failed:', error); throw error; } } } ``` ## Performance Optimization ### 1. Batch Processing ```typescript theme={null} // Process multiple transfers efficiently class BatchCCTPProcessor { async processBatch(transfers: Transfer[]) { // Group by destination domain const grouped = this.groupByDomain(transfers); // Process each group in parallel const results = await Promise.all( Object.entries(grouped).map(([domain, transfers]) => this.processGroup(parseInt(domain), transfers) ) ); return results.flat(); } private async processGroup(domain: number, transfers: Transfer[]) { // For same destination, can optimize with batching if (transfers.length > 10) { return this.processBatchMessage(domain, transfers); } // Otherwise process individually in parallel return Promise.all(transfers.map(t => this.processSingle(t))); } } ``` ### 2. Caching and Memoization ```typescript theme={null} // Cache attestations and frequently used data class CachedCCTP { private attestationCache = new Map(); private tokenPairCache = new Map(); async getAttestation(messageHash: string): Promise { // Check cache first if (this.attestationCache.has(messageHash)) { return this.attestationCache.get(messageHash)!; } // Fetch from service const attestation = await this.attestationService.get(messageHash); // Cache for future use this.attestationCache.set(messageHash, attestation); return attestation; } } ``` ## Security Best Practices ### 1. Input Validation ```typescript theme={null} function validateCCTPTransfer(params: CCTPTransferParams) { // Validate amount const amount = parseInt(params.amount.amount); if (isNaN(amount) || amount <= 0) { throw new Error('Invalid amount'); } // Validate destination domain if (!SUPPORTED_DOMAINS.includes(params.destinationDomain)) { throw new Error('Unsupported destination domain'); } // Validate recipient address format if (!isValidAddressFormat(params.mintRecipient, params.destinationDomain)) { throw new Error('Invalid recipient address format'); } // Validate sender has sufficient balance if (!hasSufficientBalance(params.from, amount)) { throw new Error('Insufficient balance'); } } ``` ### 2. Rate Limiting ```typescript theme={null} // Implement rate limiting for CCTP operations class RateLimitedCCTP { private limits = new Map(); async checkRateLimit(address: string, amount: number) { const limit = this.limits.get(address) || this.createLimit(address); // Check per-transaction limit if (amount > limit.maxPerTransaction) { throw new Error('Transaction exceeds maximum allowed amount'); } // Check hourly limit const hourlyTotal = await this.getHourlyTotal(address); if (hourlyTotal + amount > limit.maxPerHour) { throw new Error('Hourly transfer limit exceeded'); } // Check daily limit const dailyTotal = await this.getDailyTotal(address); if (dailyTotal + amount > limit.maxPerDay) { throw new Error('Daily transfer limit exceeded'); } } } ``` ## Migration from Other CCTP Implementations ### From Noble to StateSet ```typescript theme={null} // Update your integration to use StateSet's native module class CCTPMigration { // Old Noble integration async oldTransfer() { await nobleClient.execute( nobleContract, { deposit_for_burn: { ... } } ); } // New StateSet integration async newTransfer() { await StateSetCCTP.depositForBurn({ from: signer.address, amount: { denom: 'usdc', amount: '1000000' }, destinationDomain: 0, mintRecipient: recipient, burnToken: 'usdc' }); } } ``` ## Resources * [StateSet CCTP Module Source](https://github.com/StateSet/StateSet/tree/main/x/cctp) * [CCTP SDK Documentation](https://docs.StateSet.network/sdks/cctp) * [Example Applications](https://github.com/StateSet/cctp-examples) * [Circle CCTP Docs](https://developers.circle.com/cctp) ## Support For integration support: * Discord: [#cctp-dev](https://discord.gg/VfcaqgZywq) * GitHub Issues: [github.com/StateSet/cctp-module/issues](https://github.com/StateSet/cctp-module/issues) * Email: [developers@StateSet.com](mailto:developers@StateSet.com) # COGS Source: https://docs.stateset.com/guides/cogs-quickstart Implement accurate Cost of Goods Sold (COGS) calculations using the StateSet API. # Cost of Goods Sold (COGS) Calculation with StateSet API This guide provides comprehensive instructions for calculating the Cost of Goods Sold (COGS) using the StateSet API. Designed for manufacturers and businesses managing inventory, this document details how to leverage StateSet to track inventory value, production costs, and ultimately determine COGS for improved profitability analysis and cost control. By following this guide, you will learn to integrate StateSet for managing inventory lifecycles, tracking costs associated with production, implementing standard COGS calculation methodologies, and recording COGS entries directly via the API. **Note:** This guide emphasizes a perpetual inventory system (real-time tracking of inventory and costs), which StateSet supports through inventory movements. For periodic systems, adjust reporting accordingly. ## Table of Contents 1. [Introduction](#introduction) 2. [Prerequisites](#prerequisites) 3. [Getting Started: SDK Setup](#getting-started-sdk-setup) 4. [Core Concepts: COGS, COGM, and Inventory Flow](#core-concepts-cogs-cogm-and-inventory-flow) 5. [API Workflow: Tracking Costs for COGS Calculation](#api-workflow-tracking-costs-for-cogs-calculation) * [Step 1: Recording Purchase Costs](#step-1-recording-purchase-costs) * [Step 2: Tracking Production Costs (Work Orders & BOMs)](#step-2-tracking-production-costs-work-orders--boms) * [Step 3: Calculating Cost of Goods Manufactured (COGM)](#step-3-calculating-cost-of-goods-manufactured-cogm) * [Step 4: Calculating COGS Using Inventory Data](#step-4-calculating-cogs-using-inventory-data) * [Step 5: Recording COGS Entries](#step-5-recording-cogs-entries) * [Step 6: Periodic COGS Reporting](#step-6-periodic-cogs-reporting) 6. [Costing Methodologies](#costing-methodologies) 7. [Advanced COGS Considerations](#advanced-cogs-considerations) 8. [Error Handling Best Practices](#error-handling-best-practices) 9. [Troubleshooting Common Issues](#troubleshooting-common-issues) 10. [Support Resources](#support-resources) 11. [Conclusion](#conclusion) *** ## Introduction Cost of Goods Sold (COGS) represents the direct costs incurred in producing goods sold by a company. Accurate COGS calculation is fundamental for assessing gross profit, managing operational expenses, and making strategic business decisions. This guide demonstrates how the StateSet API facilitates precise COGS tracking by managing purchase orders, inventory movements, work orders, and associated costs. **Key Distinction: COGM vs. COGS** * **Cost of Goods Manufactured (COGM):** The total cost of producing finished goods during a period, including direct materials, direct labor, and manufacturing overhead (MOH), adjusted for changes in Work-in-Progress (WIP) inventory. * **Cost of Goods Sold (COGS):** The cost of finished goods that were actually sold during the period. In a manufacturing context, COGS = Beginning Finished Goods Inventory + COGM - Ending Finished Goods Inventory. StateSet helps track these by recording costed inventory movements throughout the lifecycle. **What You'll Achieve:** * Configure the StateSet Node.js SDK for API interaction. * Understand the relationship between COGS, COGM, inventory valuation, and production processes. * Utilize the StateSet API to record costs from purchasing through production and sales. * Implement logic to calculate COGM and COGS using tracked data. * Record COGS entries directly via the API. * Generate periodic COGS reports for analysis. * Apply best practices for error handling and data integrity. *** ## Prerequisites * Node.js (version 16 or higher recommended). * An active StateSet account and API key. * Basic understanding of JavaScript (`async`/`await`) and REST APIs. * Familiarity with manufacturing concepts (Purchase Orders, Work Orders, BOMs, Inventory). * Understanding of accounting principles (e.g., GAAP/IFRS) for COGS methods. *** ## Getting Started: SDK Setup Begin by integrating the StateSet SDK into your application environment. ### 1. Install the StateSet Node.js SDK Use npm or yarn to add the SDK package to your project. ```bash theme={null} npm install @stateset/embedded ``` *** ## Core Concepts: COGS, COGM, and Inventory Flow Understanding these core concepts is essential for implementing COGS calculations effectively. **What is COGS?** COGS includes all direct costs associated with producing goods that a company sells. For manufacturers, this encompasses raw materials, direct labor, and manufacturing overhead directly tied to production. It excludes indirect costs like sales, marketing, or general administrative expenses. **What is COGM?** COGM calculates the cost of goods completed and transferred to finished goods inventory: Direct Materials Used + Direct Labor + MOH + Beginning WIP - Ending WIP. **COGS Formula (Periodic System):** COGS = Beginning Finished Goods Inventory Value + COGM - Ending Finished Goods Inventory Value. In a perpetual system (recommended with StateSet), COGS is the sum of costs assigned to inventory outflows (sales/shipments) during the period. **The Role of Inventory:** Inventory is central to COGS. The flow of costs through inventory directly impacts the final COGS value. StateSet helps track inventory quantity and value as it moves through different stages: ```mermaid theme={null} graph LR A[Purchase Order
(Record Initial Cost)] --> B(Raw Materials Inventory
(Value Increased)); B -- Consumption --> C{Work Order / BOM
(Allocate Costs, Add Labor/MOH)}; C --> D[Work in Progress (WIP) Inventory
(Value Transformed)]; D -- Completion --> E[Finished Goods Inventory
(Value Finalized as COGM)]; E -- Sale/Shipment --> F{Sales Transaction
(Recognize COGS)}; ``` * **Purchase Order (PO):** Captures the initial cost of raw materials, increasing raw material inventory value. * **Work Order (WO) / Bill of Materials (BOM):** Defines the components (raw materials, sub-assemblies) and potentially labor/overhead needed. Consuming components transfers their cost from Raw Materials to Work-in-Progress (WIP). * **Work-in-Progress (WIP):** Represents the value of partially completed goods. Track labor and overhead here if possible (e.g., via custom fields on WOs). * **Finished Goods:** Upon WO completion, the total cost accumulated in WIP transfers to Finished Goods inventory (this is COGM). * **Sale:** When a finished good is sold/shipped, its cost is removed from inventory and recognized as COGS on the income statement. **Costing Methods:** The method used to value inventory withdrawn affects COGS: * **Average Cost:** Uses a simple average cost of all identical items in inventory. * **Weighted Average Cost:** Recalculates average after each purchase, weighting by quantity. * **FIFO (First-In, First-Out):** Assumes oldest items sold first. * **LIFO (Last-In, First-Out):** Assumes newest items sold first (permitted under US GAAP but not IFRS; check local regulations as of 2025). StateSet provides the data foundation (tracking individual inventory receipts/movements with costs) to implement these methods. When creating negative inventory movements (consumptions/sales), assign costs based on your method and record them. **Perpetual vs. Periodic Inventory:** * **Perpetual:** Updates inventory and COGS in real-time with each transaction (StateSet supports this via movements). * **Periodic:** Calculates COGS at period-end using the formula above (use for reporting). *** ## API Workflow: Tracking Costs for COGS Calculation This section details using the StateSet API to track costs throughout the inventory lifecycle, enabling accurate COGS calculation. ### Step 1: Recording Purchase Costs Capture the cost of incoming raw materials via Purchase Orders and Inventory updates. #### A. Create a Purchase Order Record the details of a purchase, including items, quantities, and unit costs. ```javascript theme={null} /** * Creates a Purchase Order in StateSet. * @param {object} poData - Data for the new Purchase Order. * @returns {Promise} The created Purchase Order object. */ async function createPurchaseOrder(poData) { try { logger.info('Creating Purchase Order with data:', poData); const newPO = await client.purchaseorder.create({ number: poData.number, supplier: poData.supplier, order_date: poData.orderDate, // Expects ISO 8601 format string expected_delivery_date: poData.expectedDeliveryDate, // Expects ISO 8601 format string status: poData.status, // e.g., 'OPEN', 'SUBMITTED' total_amount: poData.totalAmount, // Ensure this matches line item totals currency: poData.currency, // e.g., 'USD' line_items: poData.lineItems // Array of { part_number, quantity, unit_cost } }); logger.info("Purchase Order created successfully:", newPO.id); return newPO; } catch (error) { logger.error("Error creating purchase order:", error.response ? error.response.data : error.message); throw error; // Re-throw for upstream handling } } // Example Usage: const poDetails = { number: `PO-${Date.now()}`, // Generate a unique PO number supplier: 'Supplier Inc.', orderDate: new Date().toISOString(), expectedDeliveryDate: new Date(Date.now() + 7 * 86400000).toISOString(), // 7 days from now status: 'OPEN', totalAmount: 150.00, currency: 'USD', lineItems: [ { part_number: 'RAW_MAT_A', quantity: 10, unit_cost: 5.00 }, { part_number: 'RAW_MAT_B', quantity: 5, unit_cost: 20.00 } ] }; // const purchaseOrder = await createPurchaseOrder(poDetails); ``` *Purpose:* This API call logs the purchase intent and expected costs. The `unit_cost` on line items is crucial for later inventory valuation. #### B. Receive Items and Update Inventory When goods arrive, update the PO status and record the items received into inventory, capturing their actual cost. ```javascript theme={null} /** * Records received items from a PO line into inventory. * Assumes each call represents a distinct receipt/movement. * @param {string} partNumber - The part number received. * @param {number} quantity - The quantity received. * @param {number} unitCost - The actual cost per unit from the PO/invoice. * @param {string} purchaseOrderId - Optional: Link to the source PO. * @returns {Promise} The created Inventory movement record. */ async function recordInventoryReceipt(partNumber, quantity, unitCost, purchaseOrderId = null) { try { logger.info(`Recording inventory receipt for ${partNumber}: Qty=${quantity}, Cost=${unitCost}`); const inventoryData = { part_number: partNumber, quantity: quantity, // Positive for receipts unit_cost: unitCost, source_document_id: purchaseOrderId, source_document_type: 'purchase_order', }; const newInventoryEntry = await client.inventory.create(inventoryData); logger.info(`Inventory updated for part ${partNumber}. Entry ID:`, newInventoryEntry.id); return newInventoryEntry; } catch (error) { logger.error(`Error updating inventory for part ${partNumber}:`, error.response ? error.response.data : error.message); throw error; } } /** * Marks a Purchase Order as partially or fully received. * Updates inventory based on received line items. * @param {string} poId - The ID of the Purchase Order to receive against. * @param {Array} receivedItems - Array of { part_number, quantity, unit_cost } received. * @param {string} finalStatus - The new status for the PO ('PARTIALLY_RECEIVED', 'RECEIVED'). * @returns {Promise} The updated Purchase Order object. */ async function receivePurchaseOrderItems(poId, receivedItems, finalStatus) { try { logger.info(`Receiving items for PO ID: ${poId}`); // 1. Record each received item as an inventory movement for (const item of receivedItems) { await recordInventoryReceipt(item.part_number, item.quantity, item.unit_cost, poId); } // 2. Update the Purchase Order status const updatedPO = await client.purchaseorder.update(poId, { status: finalStatus, received_date: new Date().toISOString() // Record receipt date }); logger.info(`Purchase Order ${poId} status updated to ${finalStatus}`); return updatedPO; } catch (error) { logger.error(`Error processing receipt for PO ${poId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage (assuming 'purchaseOrder' object from previous step): const itemsReceived = [ { part_number: 'RAW_MAT_A', quantity: 10, unit_cost: 5.00 }, { part_number: 'RAW_MAT_B', quantity: 5, unit_cost: 20.00 } ]; const receivedPO = await receivePurchaseOrderItems(purchaseOrder.id, itemsReceived, 'RECEIVED'); ``` *Purpose:* This workflow creates distinct `inventory` records (movements) for each receipt. Each record stores the `quantity` and `unit_cost` at that point in time. This historical cost layering is the foundation for accurate COGS methods like FIFO or Weighted Average. Updating the PO status closes the loop on the purchasing process. ### Step 2: Tracking Production Costs (Work Orders & BOMs) Track the consumption of components, addition of labor/overhead, and creation of finished goods using Work Orders. #### A. Retrieve Work Order and BOM Details Fetch completed Work Orders within a period and their associated Bills of Materials (BOMs) to understand component usage. ```javascript theme={null} /** * Fetches completed Work Orders within a given date range. * @param {string} startDateISO - ISO 8601 start date string. * @param {string} endDateISO - ISO 8601 end date string. * @returns {Promise>} List of completed Work Order objects. */ async function getCompletedWorkOrders(startDateISO, endDateISO) { try { logger.info(`Fetching completed Work Orders from ${startDateISO} to ${endDateISO}`); const workOrders = await client.workorder.list({ filter: { // Assuming status field exists and 'COMPLETED' is a valid value status: { eq: 'COMPLETED' }, // Assuming completion_date field exists for filtering completion_date: { gte: startDateISO, lte: endDateISO } }, limit: 1000 // Adjust limit as needed, handle pagination if necessary }); logger.info(`Found ${workOrders.length} completed Work Orders.`); return workOrders; } catch (error) { logger.error("Error fetching work orders:", error.response ? error.response.data : error.message); throw error; } } /** * Retrieves the Bill of Materials (BOM) associated with a Work Order. * @param {object} workOrder - The Work Order object. * @returns {Promise} The BOM object. */ async function getBOMForWorkOrder(workOrder) { try { if (!workOrder.bill_of_material_id) { throw new Error(`Work Order ${workOrder.id} does not have a linked BOM ID.`); } logger.info(`Fetching BOM ID: ${workOrder.bill_of_material_id} for Work Order ${workOrder.id}`); const bom = await client.billofmaterials.get(workOrder.bill_of_material_id); if (!bom) { throw new Error(`BOM with ID ${workOrder.bill_of_material_id} not found.`); } logger.info(`Retrieved BOM: ${bom.name}`); return bom; } catch (error) { logger.error(`Error getting BOM for Work Order ${workOrder.id}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage: const startDate = new Date(Date.UTC(2023, 11, 1)).toISOString(); // Dec 1, 2023 const endDate = new Date(Date.UTC(2023, 11, 31, 23, 59, 59, 999)).toISOString(); // Dec 31, 2023 // const completedWorkOrders = await getCompletedWorkOrders(startDate, endDate); if (completedWorkOrders.length > 0) { const firstWO = completedWorkOrders[0]; const bom = await getBOMForWorkOrder(firstWO); logger.info("BOM Components:", bom.components); } ``` *Purpose:* Identify the production activities (WOs) and the required components (BOMs) for finished goods produced in a specific period. #### B. Record Component Consumption and Add to WIP When starting or progressing a Work Order, create negative inventory movements for consumed components, assigning costs based on your method. Add labor/overhead via custom fields or separate entries. ```javascript theme={null} /** * Records consumption of a component for a Work Order using specified costing method. * @param {string} partNumber - The part number consumed. * @param {number} quantity - The quantity consumed (will be negative in movement). * @param {string} workOrderId - The linked Work Order ID. * @param {string} costingMethod - 'FIFO', 'Average', or 'Simplified'. * @returns {Promise} The created inventory movement. */ async function recordInventoryConsumption(partNumber, quantity, workOrderId, costingMethod) { let unitCost; switch (costingMethod) { case 'FIFO': unitCost = await calculateFIFOCost(partNumber, quantity) / quantity; // Total cost / qty for unit break; case 'Average': unitCost = await calculateAverageCost(partNumber); break; case 'Simplified': default: unitCost = await getComponentCost_Simplified(partNumber); break; } try { const inventoryData = { part_number: partNumber, quantity: -quantity, // Negative for consumption unit_cost: unitCost, source_document_id: workOrderId, source_document_type: 'work_order', }; const newEntry = await client.inventory.create(inventoryData); logger.info(`Consumption recorded for ${partNumber}. Entry ID: ${newEntry.id}`); return newEntry; } catch (error) { logger.error(`Error recording consumption for ${partNumber}:`, error); throw error; } } /** * Consumes components for a Work Order based on its BOM. * @param {object} workOrder - The Work Order object. * @param {string} costingMethod - The costing method to use. * @returns {Promise} */ async function consumeComponentsForWO(workOrder, costingMethod) { const bom = await getBOMForWorkOrder(workOrder); for (const component of bom.components) { await recordInventoryConsumption(component.item_id, component.quantity, workOrder.id, costingMethod); } // Add logic to update WO status or add to WIP value } ``` *Purpose:* This records cost transfers from raw materials to WIP, using the chosen costing method to assign unit\_cost. #### C. Record Production Completion and Transfer to Finished Goods Upon WO completion, calculate total cost (materials + labor + overhead) and create positive inventory for finished goods. ```javascript theme={null} /** * Records completion of a Work Order, transferring costs to Finished Goods. * Assumes labor and overhead are tracked on the WO (e.g., custom fields). * @param {object} workOrder - The Work Order object. * @param {number} totalMaterialCost - Calculated material cost. * @param {string} finishedPartNumber - The finished good's part number. * @returns {Promise} The inventory movement for FG. */ async function recordWOCompletion(workOrder, totalMaterialCost, finishedPartNumber) { const laborCost = workOrder.labor_cost || 0; // Assume field exists or fetch const overheadCost = workOrder.overhead_cost || 0; const totalCost = totalMaterialCost + laborCost + overheadCost; const quantityProduced = workOrder.quantity_produced || 0; const unitCost = quantityProduced > 0 ? totalCost / quantityProduced : 0; try { const inventoryData = { part_number: finishedPartNumber, quantity: quantityProduced, unit_cost: unitCost, source_document_id: workOrder.id, source_document_type: 'work_order', }; const newEntry = await client.inventory.create(inventoryData); logger.info(`FG recorded for ${finishedPartNumber}. Entry ID: ${newEntry.id}`); return newEntry; } catch (error) { logger.error(`Error recording WO completion:`, error); throw error; } } ``` *Purpose:* This transfers accumulated costs to finished goods inventory, representing COGM. #### D. Determine Cost of Components Consumed (Simplified Example) Calculate the cost of components used in a Work Order. **Note:** This example uses a simplified approach (fetching the *latest* cost). For accurate costing (FIFO/Average), you'd need logic to query and consume specific `inventory` cost layers based on your chosen method. Furthermore, remember to incorporate direct labor and overhead costs associated with the Work Order for a complete COGS picture. ```javascript theme={null} /** * Retrieves the cost of a specific component part. * @param {string} partNumber - The component's part number. * @returns {Promise} The unit cost of the component. */ async function getComponentCost_Simplified(partNumber) { try { // Fetch the most recent inventory entry (receipt) for this part const inventoryMovements = await client.inventory.list({ filter: { part_number: { eq: partNumber }, quantity: { gt: 0 } }, // Look for receipts sort: '-created_at', // Get the most recent first limit: 1 }); if (inventoryMovements.length === 0) { console.warn(`No recent inventory receipt found for part number: ${partNumber}. Cost assumed 0.`); // Or throw an error depending on business rules return 0; // throw new Error(`No inventory cost found for part number: ${partNumber}`); } // Using optional chaining for safety const latestCost = inventoryMovements[0]?.unit_cost; if (latestCost === undefined || latestCost === null) { console.warn(`Latest inventory entry for ${partNumber} has no unit_cost. Cost assumed 0.`); return 0; } logger.info(`Latest cost for ${partNumber}: ${latestCost}`); return latestCost; } catch (error) { logger.error(`Error getting component cost for part ${partNumber}:`, error.response ? error.response.data : error.message); // Don't re-throw here if a default/warning is acceptable return 0; // Return 0 cost if lookup fails critically, or handle differently } } /** * Calculates the estimated COGS for a single Work Order based on its BOM components. * Uses the SIMPLIFIED component costing method (latest cost). * @param {object} workOrder - The completed Work Order object. * @returns {Promise} Contains work order number, total cost, and quantity produced. */ async function calculateCOGSForWorkOrder_Simplified(workOrder) { try { const bom = await getBOMForWorkOrder(workOrder); let totalMaterialCost = 0; if (!bom.components || bom.components.length === 0) { console.warn(`BOM for Work Order ${workOrder.id} has no components.`); // Handle cases with no components (e.g., service WOs) if applicable } else { for (const component of bom.components) { // Assumes component object has item_id (part number) and quantity fields if (!component.item_id || component.quantity === undefined) { console.warn(`Skipping invalid component in BOM ${bom.id}:`, component); continue; } const componentCost = await getComponentCost_Simplified(component.item_id); totalMaterialCost += componentCost * component.quantity; } } // Extract quantity produced from the work order (adapt field name as needed) // Example: Assuming quantity is on the WO itself or summed from line items const quantityProduced = workOrder.quantity_produced || workOrder.work_order_line_items?.reduce((sum, item) => sum + item.quantity, 0) || 0; if (quantityProduced === 0) { console.warn(`Work Order ${workOrder.id} has zero quantity produced. Average cost cannot be calculated.`); } logger.info(`Calculated Material Cost for WO ${workOrder.number}: ${totalMaterialCost}`); return { workOrderNumber: workOrder.number, totalCost: totalMaterialCost, // Renaming for clarity - this is MATERIAL cost quantityProduced: quantityProduced }; } catch (error) { logger.error(`Error calculating COGS for Work Order ${workOrder.id}:`, error.message); // Return a structure indicating failure or partial data return { workOrderNumber: workOrder?.number || 'Unknown', totalCost: null, quantityProduced: null, error: error.message }; } } // Example Usage: if (completedWorkOrders.length > 0) { const cogsEstimate = await calculateCOGSForWorkOrder_Simplified(completedWorkOrders[0]); logger.info("Simplified COGS Estimate for Work Order:", cogsEstimate); } ``` *Purpose:* This step estimates the material cost of producing goods based on the BOM and component costs recorded in StateSet. **Crucially, this simplified example uses the *latest* component cost.** For accurate accounting, implement logic reflecting your chosen costing method (FIFO, Average) by querying specific `inventory` movement records. Furthermore, remember to incorporate direct labor and overhead costs associated with the Work Order for a complete COGS picture. ### Variant: COGS Calculation Using FIFO ```javascript theme={null} /** * Calculates the COGS for a single Work Order using FIFO for component costs. * @param {object} workOrder - The completed Work Order object. * @returns {Promise} Contains work order number, total cost, and quantity produced. */ async function calculateCOGSForWorkOrder_FIFO(workOrder) { try { const bom = await getBOMForWorkOrder(workOrder); let totalMaterialCost = 0; if (!bom.components || bom.components.length === 0) { console.warn(`BOM for Work Order ${workOrder.id} has no components.`); } else { for (const component of bom.components) { if (!component.item_id || component.quantity === undefined) { console.warn(`Skipping invalid component in BOM ${bom.id}:`, component); continue; } const componentCost = await calculateFIFOCost(component.item_id, component.quantity); totalMaterialCost += componentCost; } } const quantityProduced = workOrder.quantity_produced || workOrder.work_order_line_items?.reduce((sum, item) => sum + item.quantity, 0) || 0; if (quantityProduced === 0) { console.warn(`Work Order ${workOrder.id} has zero quantity produced.`); } logger.info(`Calculated Material Cost (FIFO); for WO ${workOrder.number}: ${totalMaterialCost}`); return { workOrderNumber: workOrder.number, totalCost: totalMaterialCost, quantityProduced: quantityProduced }; } catch (error) { logger.error(`Error calculating FIFO COGS for Work Order ${workOrder.id}:`, error.message); return { workOrderNumber: workOrder?.number || 'Unknown', totalCost: null, quantityProduced: null, error: error.message }; } } ``` ### Variant: COGS Calculation Using Average Cost ```javascript theme={null} /** * Calculates the COGS for a single Work Order using Average Cost for components. * @param {object} workOrder - The completed Work Order object. * @returns {Promise} Contains work order number, total cost, and quantity produced. */ async function calculateCOGSForWorkOrder_Average(workOrder) { try { const bom = await getBOMForWorkOrder(workOrder); let totalMaterialCost = 0; if (!bom.components || bom.components.length === 0) { console.warn(`BOM for Work Order ${workOrder.id} has no components.`); } else { for (const component of bom.components) { if (!component.item_id || component.quantity === undefined) { console.warn(`Skipping invalid component in BOM ${bom.id}:`, component); continue; } const unitCost = await calculateAverageCost(component.item_id); totalMaterialCost += unitCost * component.quantity; } } const quantityProduced = workOrder.quantity_produced || workOrder.work_order_line_items?.reduce((sum, item) => sum + item.quantity, 0) || 0; if (quantityProduced === 0) { console.warn(`Work Order ${workOrder.id} has zero quantity produced.`); } logger.info(`Calculated Material Cost (Average); for WO ${workOrder.number}: ${totalMaterialCost}`); return { workOrderNumber: workOrder.number, totalCost: totalMaterialCost, quantityProduced: quantityProduced }; } catch (error) { logger.error(`Error calculating Average COGS for Work Order ${workOrder.id}:`, error.message); return { workOrderNumber: workOrder?.number || 'Unknown', totalCost: null, quantityProduced: null, error: error.message }; } } ``` ### Step 3: Calculating Cost of Goods Manufactured (COGM) Aggregate costs from completed Work Orders to calculate COGM. Include adjustments for WIP changes. ```javascript theme={null} /** * Calculates COGM for a period based on completed Work Orders and WIP changes. * @param {Array} workOrders - List of completed work orders. * @param {string} costingMethod - 'Simplified', 'FIFO', or 'Average'. * @param {number} beginningWIP - Beginning WIP value. * @param {number} endingWIP - Ending WIP value. * @returns {Promise} Total COGM. */ async function calculateCOGMForPeriod(workOrders, costingMethod, beginningWIP, endingWIP) { let totalDirectMaterials = 0; let totalLabor = 0; let totalOverhead = 0; for (const workOrder of workOrders) { const woCosts = await calculateCostsForWorkOrder(workOrder, costingMethod); totalDirectMaterials += woCosts.materials; totalLabor += woCosts.labor; totalOverhead += woCosts.overhead; } const cogm = totalDirectMaterials + totalLabor + totalOverhead + beginningWIP - endingWIP; logger.info(`COGM Calculation: Materials=${totalDirectMaterials}, Labor=${totalLabor}, Overhead=${totalOverhead}, Beginning WIP=${beginningWIP}, Ending WIP=${endingWIP}`); logger.info(`Total COGM for period: ${cogm}`); return cogm; } /** * Helper function to calculate all costs for a Work Order. * @param {object} workOrder - The Work Order object. * @param {string} costingMethod - The costing method to use. * @returns {Promise} Object with materials, labor, and overhead costs. */ async function calculateCostsForWorkOrder(workOrder, costingMethod) { // Calculate material costs based on method let materialCost = 0; const bom = await getBOMForWorkOrder(workOrder); if (bom.components && bom.components.length > 0) { for (const component of bom.components) { if (!component.item_id || component.quantity === undefined) continue; let componentCost; switch (costingMethod) { case 'FIFO': componentCost = await calculateFIFOCost(component.item_id, component.quantity); break; case 'Average': const unitCost = await calculateAverageCost(component.item_id); componentCost = unitCost * component.quantity; break; default: const simpleCost = await getComponentCost_Simplified(component.item_id); componentCost = simpleCost * component.quantity; } materialCost += componentCost; } } // Get labor and overhead from WO (assuming custom fields) const laborCost = workOrder.labor_cost || 0; const overheadCost = workOrder.overhead_cost || 0; return { materials: materialCost, labor: laborCost, overhead: overheadCost }; } ``` *Purpose:* This calculates the cost added to finished goods inventory during the period, accounting for WIP changes. ### Step 4: Calculating COGS Using Inventory Data For periodic COGS, use the formula with beginning/ending FG values. For perpetual, sum costs from sales movements. ```javascript theme={null} /** * Calculates current inventory value for a part number using perpetual records. * @param {string} partNumber - The part number. * @returns {Promise<{quantity: number, value: number}>} Current stock and value. */ async function calculateCurrentInventoryValue(partNumber) { try { const movements = await client.inventory.list({ filter: { part_number: { eq: partNumber } }, limit: 10000 // Handle pagination if needed }); let quantity = 0; let value = 0; movements.forEach(m => { quantity += m.quantity; value += m.quantity * m.unit_cost; }); return { quantity, value: quantity > 0 ? value : 0 }; } catch (error) { logger.error(`Error calculating inventory value for ${partNumber}:`, error); throw error; } } /** * Calculates periodic COGS for finished goods. * @param {number} beginningFGValue - Beginning FG inventory value. * @param {number} cogm - COGM from Step 3. * @param {number} endingFGValue - Ending FG inventory value. * @returns {number} COGS. */ function calculatePeriodicCOGS(beginningFGValue, cogm, endingFGValue) { return beginningFGValue + cogm - endingFGValue; } /** * Calculates perpetual COGS by summing costs of sales movements. * @param {string} startDateISO - Start date. * @param {string} endDateISO - End date. * @param {string} fgPart - Finished good part number. * @returns {Promise} Total COGS. */ async function calculatePerpetualCOGS(startDateISO, endDateISO, fgPart) { try { const salesMovements = await client.inventory.list({ filter: { part_number: { eq: fgPart }, quantity: { lt: 0 }, // Negative for sales/consumptions created_at: { gte: startDateISO, lte: endDateISO } } }); return salesMovements.reduce((sum, m) => sum + Math.abs(m.quantity) * m.unit_cost, 0); } catch (error) { logger.error(`Error calculating perpetual COGS:`, error); throw error; } } // Example: Calculate COGS for a specific finished good async function calculateCOGSForProduct(fgPart, startDate, endDate, costingMethod) { // For periodic COGS const beginningFG = await calculateCurrentInventoryValue(fgPart); // Run at period start const endingFG = await calculateCurrentInventoryValue(fgPart); // Run at period end // Get completed WOs that produced this FG const workOrders = await getCompletedWorkOrders(startDate, endDate); const relevantWOs = workOrders.filter(wo => wo.finished_good_part === fgPart); // Calculate COGM for these WOs const cogm = await calculateCOGMForPeriod(relevantWOs, costingMethod, 0, 0); // Adjust WIP as needed // Calculate periodic COGS const periodicCOGS = calculatePeriodicCOGS(beginningFG.value, cogm, endingFG.value); // Also calculate perpetual for comparison const perpetualCOGS = await calculatePerpetualCOGS(startDate, endDate, fgPart); return { periodic: periodicCOGS, perpetual: perpetualCOGS, beginningInventory: beginningFG, endingInventory: endingFG, cogm: cogm }; } ``` *Purpose:* These methods provide accurate COGS based on inventory flows. Use perpetual for real-time insights and periodic for financial reporting. ### Step 5: Recording COGS Entries Once calculated, record COGS using StateSet's dedicated COGS Entries API. ```javascript theme={null} /** * Creates a COGS entry in StateSet. * @param {object} cogsData - Data for the COGS entry. * @returns {Promise} The created COGS entry. */ async function createCOGSEntry(cogsData) { try { const entry = await client.cogs_entries.create(cogsData); logger.info(`COGS Entry created: ${entry.id}`); return entry; } catch (error) { logger.error(`Error creating COGS entry:`, error.response ? error.response.data : error.message); throw error; } } /** * Records COGS for a sale transaction. * @param {object} saleData - Information about the sale. * @param {number} calculatedCOGS - The calculated COGS amount. * @param {string} costingMethod - The method used for calculation. * @returns {Promise} The created COGS entry. */ async function recordCOGSForSale(saleData, calculatedCOGS, costingMethod) { const cogsDetails = { period: saleData.period || new Date().toISOString().substring(0, 7), // YYYY-MM format product: saleData.product, quantity_sold: saleData.quantity, cogs: calculatedCOGS, average_cost: saleData.quantity > 0 ? calculatedCOGS / saleData.quantity : 0, ending_inventory_quantity: saleData.endingInventory?.quantity || 0, ending_inventory_value: saleData.endingInventory?.value || 0, currency: saleData.currency || 'USD', unit_selling_price: saleData.unitPrice, gross_sales: saleData.quantity * saleData.unitPrice, cogs_method: costingMethod, sale_date: saleData.saleDate || new Date().toISOString().split('T')[0] }; return await createCOGSEntry(cogsDetails); } // Example: Complete workflow for recording a sale with COGS async function processSaleWithCOGS(saleInfo, costingMethod = 'FIFO') { try { // 1. Record the inventory movement (negative for sale) const unitCost = costingMethod === 'FIFO' ? await calculateFIFOCost(saleInfo.product, saleInfo.quantity) / saleInfo.quantity : await calculateAverageCost(saleInfo.product); const inventoryMovement = await client.inventory.create({ part_number: saleInfo.product, quantity: -saleInfo.quantity, unit_cost: unitCost, source_document_id: saleInfo.orderId, source_document_type: 'sales_order' }); // 2. Calculate COGS for this sale const cogs = unitCost * saleInfo.quantity; // 3. Get ending inventory for reporting const endingInventory = await calculateCurrentInventoryValue(saleInfo.product); // 4. Record COGS entry const cogsEntry = await recordCOGSForSale({ ...saleInfo, endingInventory }, cogs, costingMethod); return { inventoryMovement, cogsEntry, cogs, grossProfit: (saleInfo.unitPrice * saleInfo.quantity) - cogs }; } catch (error) { logger.error('Error processing sale with COGS:', error); throw error; } } ``` *Purpose:* This API records COGS for accounting and reporting, supporting methods like FIFO. The COGS Entries API requires calculated values as parameters. ### Step 6: Periodic COGS Reporting Generate reports summarizing COGS for analysis and financial reporting, incorporating both perpetual and periodic calculations. ```javascript theme={null} /** * Generates a detailed COGS report for a specified period. * @param {string} startDateISO - ISO 8601 start date. * @param {string} endDateISO - ISO 8601 end date. * @param {string} costingMethod - 'Simplified', 'FIFO', or 'Average'. * @param {string} system - 'periodic' or 'perpetual'. * @returns {Promise} A structured COGS report. */ async function generateCOGSReport(startDateISO, endDateISO, costingMethod = 'Simplified', system = 'periodic') { try { logger.info(`Generating COGS Report from ${startDateISO} to ${endDateISO} using ${costingMethod} (${system} system);`); // Get all finished goods parts (you might want to filter this) const fgParts = ['FINISHED_GOOD_X', 'FINISHED_GOOD_Y']; // Example list const reportData = { period: `${startDateISO.split('T')[0]} to ${endDateISO.split('T')[0]}`, costingMethod: costingMethod, system: system, products: [] }; let totalCOGS = 0; let totalCOGM = 0; let totalSales = 0; for (const fgPart of fgParts) { // Calculate beginning and ending inventory const beginningFG = await calculateCurrentInventoryValue(fgPart); const endingFG = await calculateCurrentInventoryValue(fgPart); // Get WOs that produced this FG const workOrders = await getCompletedWorkOrders(startDateISO, endDateISO); const relevantWOs = workOrders.filter(wo => wo.finished_good_part === fgPart); // Calculate COGM for this product const cogm = await calculateCOGMForPeriod(relevantWOs, costingMethod, 0, 0); // Adjust WIP as needed totalCOGM += cogm; // Calculate COGS based on system type let productCOGS; if (system === 'periodic') { productCOGS = calculatePeriodicCOGS(beginningFG.value, cogm, endingFG.value); } else { productCOGS = await calculatePerpetualCOGS(startDateISO, endDateISO, fgPart); } totalCOGS += productCOGS; // Get sales data for gross profit calculation const salesMovements = await client.inventory.list({ filter: { part_number: { eq: fgPart }, quantity: { lt: 0 }, created_at: { gte: startDateISO, lte: endDateISO } } }); const quantitySold = Math.abs(salesMovements.reduce((sum, m) => sum + m.quantity, 0)); const averageCOGS = quantitySold > 0 ? productCOGS / quantitySold : 0; reportData.products.push({ partNumber: fgPart, beginningInventory: beginningFG, endingInventory: endingFG, cogm: cogm, cogs: productCOGS, quantitySold: quantitySold, averageCOGSPerUnit: averageCOGS, workOrderCount: relevantWOs.length }); } reportData.summary = { totalCOGM: totalCOGM, totalCOGS: totalCOGS, inventoryChange: reportData.products.reduce((sum, p) => sum + (p.endingInventory.value - p.beginningInventory.value), 0) }; logger.info("COGS Report Generated Successfully."); return reportData; } catch (error) { logger.error("Error generating COGS Report:", error.message); throw error; } } /** * Generates a summary COGS report with key metrics. * @param {string} period - The reporting period (e.g., '2025-Q1'). * @param {object} reportData - The detailed report data. * @returns {object} Summary metrics. */ function generateCOGSSummary(period, reportData) { const summary = { period: period, keyMetrics: { totalCOGS: reportData.summary.totalCOGS, totalCOGM: reportData.summary.totalCOGM, inventoryTurnover: reportData.products.reduce((sum, p) => { const avgInventory = (p.beginningInventory.value + p.endingInventory.value) / 2; return sum + (avgInventory > 0 ? p.cogs / avgInventory : 0); }, 0) / reportData.products.length, grossMarginImpact: 'Calculate based on sales data' }, recommendations: [] }; // Add recommendations based on metrics if (summary.keyMetrics.inventoryTurnover < 4) { summary.recommendations.push('Low inventory turnover detected. Consider reducing safety stock or improving demand forecasting.'); } return summary; } // Example Usage: const startDateReport = '2025-01-01T00:00:00.000Z'; const endDateReport = '2025-03-31T23:59:59.999Z'; const report = await generateCOGSReport(startDateReport, endDateReport, 'FIFO', 'periodic'); logger.info("Generated COGS Report:", JSON.stringify(report, null, 2);); const summary = generateCOGSSummary('2025-Q1', report); logger.info("COGS Summary:", summary); ``` *Purpose:* Consolidate calculated COGS data into a structured format for review, analysis, and integration with financial systems. This enhanced report supports both periodic and perpetual systems and includes COGM calculations. *** ## Costing Methodologies As highlighted in the examples, the `calculateCOGSForWorkOrder_Simplified` function used the latest component cost. This is often insufficient for formal accounting. StateSet's `inventory` resource, by tracking individual movements with `unit_cost`, provides the necessary data foundation to implement standard costing methods: * **Average Cost:** Requires calculating a running average cost for each part number based on all receipts and their costs over time. When components are consumed, this average cost is used. * **Weighted Average Cost:** Requires recalculating the average cost *after each purchase*. Query `inventory` movements, apply the weighted average formula, and use this cost for subsequent consumptions until the next purchase. * **FIFO/LIFO:** Requires querying `inventory` movements sorted by `created_at` (or another relevant date field). Consume the oldest (FIFO) or newest (LIFO) cost layers first, tracking remaining quantities in each layer. Implementing these methods involves more complex query logic against the `inventory` resource data than shown in the simplified examples. You would typically fetch relevant inventory movements for a component, sort them appropriately, and apply the chosen costing logic to determine the value of consumed items. ### Example: Implementing FIFO Costing Here's a simplified example of calculating the cost for consuming a certain quantity of a component using FIFO. This assumes that receipt quantities represent available layers and doesn't account for prior partial consumptions. In a full system, you'd track remaining quantities per receipt. ```javascript theme={null} /** * Calculates the FIFO cost for consuming a specified quantity of a part. * @param {string} partNumber - The part number. * @param {number} quantityToConsume - The quantity to consume. * @returns {Promise} The total cost for the consumed quantity. */ async function calculateFIFOCost(partNumber, quantityToConsume) { try { // Fetch all positive inventory movements (receipts) sorted by created_at ascending (oldest first) const receipts = await client.inventory.list({ filter: { part_number: { eq: partNumber }, quantity: { gt: 0 } // Receipts have positive quantity }, sort: 'created_at', // Ascending for FIFO limit: 1000 // Adjust as needed }); let remaining = quantityToConsume; let totalCost = 0; for (const receipt of receipts) { const available = receipt.quantity; // Simplified; track remaining in real systems const consume = Math.min(available, remaining); totalCost += consume * receipt.unit_cost; remaining -= consume; if (remaining <= 0) break; } if (remaining > 0) { throw new Error(`Insufficient inventory for ${partNumber} using FIFO.`); } return totalCost; } catch (error) { logger.error(`Error calculating FIFO cost for ${partNumber}:`, error.message); throw error; } } // Usage in COGS calculation: // const componentCost = await calculateFIFOCost(component.item_id, component.quantity); // totalMaterialCost += componentCost; ``` ### Example: Implementing Average Costing Here's an example for simple average cost based on all historical receipts. ```javascript theme={null} /** * Calculates the simple average cost for a part based on all receipts. * @param {string} partNumber - The part number. * @returns {Promise} The average unit cost. */ async function calculateAverageCost(partNumber) { try { const receipts = await client.inventory.list({ filter: { part_number: { eq: partNumber }, quantity: { gt: 0 } }, limit: 1000 }); if (receipts.length === 0) return 0; const totalQuantity = receipts.reduce((sum, r) => sum + r.quantity, 0); const totalCost = receipts.reduce((sum, r) => sum + (r.quantity * r.unit_cost), 0); return totalCost / totalQuantity; } catch (error) { logger.error(`Error calculating average cost for ${partNumber}:`, error.message); throw error; } } // Usage: // const unitCost = await calculateAverageCost(component.item_id); // totalMaterialCost += unitCost * component.quantity; ``` For Weighted Average, you would recalculate the average after each new receipt and use that until the next update. *** ## Advanced COGS Considerations * **Direct Labor and Overhead:** Use custom fields on Work Orders or integrate with time-tracking systems to capture these. Allocate overhead based on machine hours, labor hours, or activity-based costing. ```javascript theme={null} // Example: Adding labor and overhead to Work Orders async function addLaborAndOverheadToWO(workOrderId, laborHours, hourlyRate, overheadRate) { const laborCost = laborHours * hourlyRate; const overheadCost = laborCost * overheadRate; // e.g., 150% of labor return await client.workorder.update(workOrderId, { labor_hours: laborHours, labor_cost: laborCost, overhead_cost: overheadCost, total_cost: laborCost + overheadCost // Plus materials from BOM }); } ``` * **Inventory Adjustments:** Record adjustments as inventory movements with costs (e.g., at average cost). ```javascript theme={null} async function recordInventoryAdjustment(partNumber, adjustmentQty, reason) { const avgCost = await calculateAverageCost(partNumber); return await client.inventory.create({ part_number: partNumber, quantity: adjustmentQty, // Positive for found, negative for loss unit_cost: avgCost, source_document_type: 'adjustment', notes: reason }); } ``` * **Standard Costing:** Store standard costs on items; calculate variances by comparing to actuals from POs/WOs. ```javascript theme={null} async function calculateCostVariance(partNumber, actualCost, standardCost) { const variance = actualCost - standardCost; const variancePercentage = (variance / standardCost) * 100; // Record variance for analysis return { partNumber, standardCost, actualCost, variance, variancePercentage, favorable: variance < 0 }; } ``` * **Perpetual Inventory Enhancements:** Use webhooks for real-time COGS updates on sales events. ```javascript theme={null} // Webhook handler for real-time COGS async function handleSaleWebhook(saleEvent) { const result = await processSaleWithCOGS({ product: saleEvent.product, quantity: saleEvent.quantity, unitPrice: saleEvent.price, orderId: saleEvent.order_id, saleDate: saleEvent.date }, 'FIFO'); // Update accounting system await updateAccountingSystem(result); } ``` * **Multi-Currency and Regulations:** Handle exchange rates via API; ensure compliance (e.g., no LIFO under IFRS). ```javascript theme={null} async function convertCurrencyForCOGS(amount, fromCurrency, toCurrency, date) { // Fetch exchange rate from API or stored rates const rate = await getExchangeRate(fromCurrency, toCurrency, date); return amount * rate; } ``` * **Integrations:** Sync COGS entries with accounting software (e.g., QuickBooks, NetSuite) via StateSet webhooks. ```javascript theme={null} async function syncCOGSToAccounting(cogsEntry) { // Example: Push to QuickBooks const journalEntry = { date: cogsEntry.sale_date, entries: [ { account: 'Cost of Goods Sold', debit: cogsEntry.cogs, description: `COGS for ${cogsEntry.product}` }, { account: 'Inventory', credit: cogsEntry.cogs, description: `Inventory reduction for ${cogsEntry.product}` } ] }; // Send to accounting system API await accountingAPI.createJournalEntry(journalEntry); } ``` *** ## Error Handling Best Practices Robust error handling is critical for accurate financial calculations. * **Specific Error Catching:** Use `try...catch` blocks around all API calls. Inspect the `error` object. StateSet SDK errors often have `error.response.data` containing details from the API. * **Input Validation:** Validate data *before* sending it to the API (e.g., check for required fields, correct data types, sensible values). * **Retry Mechanisms:** Implement exponential backoff retries for transient network errors or rate limiting (e.g., HTTP 429, 503). Avoid retrying non-transient errors (e.g., HTTP 400 Bad Request, 404 Not Found) without correcting the request. * **Idempotency:** When creating resources that shouldn't be duplicated (like POs), consider using idempotency keys if the API supports them, or implement checks to prevent duplicate creation. * **Centralized Logging:** Log detailed error information (timestamp, operation, input data summary, error message, stack trace, API response) to a centralized logging system for easier debugging and monitoring. * **Alerting:** Set up alerts for critical failures in the COGS calculation process. ```javascript theme={null} // Enhanced Error Handling Wrapper Example async function safeApiOperation(operation, description) { try { logger.info(`Attempting operation: ${description}`); const result = await operation(); logger.info(`Operation successful: ${description}`); return result; } catch (error) { const timestamp = new Date().toISOString(); let errorDetails = { message: error.message, stack: error.stack, description: description, timestamp: timestamp }; if (error.response) { // Capture API error details errorDetails.apiStatus = error.response.status; errorDetails.apiResponse = error.response.data; } logger.error(`Error during operation: ${description}`, errorDetails); // Log to external system (replace console.error) // externalLogger.error('COGS Process Error', errorDetails); // Notify relevant personnel (placeholder) // notifyTeam(`Critical error in ${description}: ${error.message}`); // Re-throw or return an error indicator based on desired flow throw new Error(`Operation failed: ${description}. Details: ${errorDetails.message}`); } } // Usage Example: const poDetails = { /* ... */ }; try { const purchaseOrder = await safeApiOperation( () => createPurchaseOrder(poDetails), `Create PO ${poDetails.number}` ); // ... continue workflow } catch (finalError) { logger.error("Workflow halted due to critical error:", finalError.message); // Handle the halt appropriately } ``` *** ## Troubleshooting Common Issues * **Authentication Errors (401/403):** * **Solution:** Verify `STATESET_API_KEY` is correct, loaded properly into the environment, and hasn't expired or been revoked. Check API key permissions. * **Validation Errors (400 Bad Request):** * **Solution:** Check the `error.response.data` for specific field errors. Ensure all required fields are provided, data types are correct (e.g., numbers vs. strings, ISO dates), and values are valid (e.g., status codes). * **Resource Not Found Errors (404):** * **Solution:** Double-check the IDs being used in `get`, `update`, or `delete` calls (e.g., `poId`, `bomId`). Ensure the resource actually exists. * **Incorrect Inventory Values:** * **Solution:** Ensure all movements (positive/negative) are recorded consistently. Audit aggregations by running: ```javascript theme={null} async function auditInventoryValue(partNumber) { const movements = await client.inventory.list({ filter: { part_number: { eq: partNumber } }, sort: 'created_at', limit: 10000 }); let runningQty = 0; let runningValue = 0; movements.forEach(m => { logger.info(`${m.created_at}: Qty=${m.quantity}, Cost=${m.unit_cost}, Running Qty=${runningQty + m.quantity}`); runningQty += m.quantity; runningValue += m.quantity * m.unit_cost; }); return { finalQty: runningQty, finalValue: runningValue }; } ``` * **COGS Mismatches:** * **Solution:** * Verify costing method consistency across consumptions and sales. Check for unrecorded labor/overhead. * Ensure BOMs are accurate with correct components and quantities. * Validate Work Order quantities match actual production. * Cross-check perpetual vs periodic calculations: ```javascript theme={null} async function validateCOGS(product, period) { const perpetual = await calculatePerpetualCOGS(period.start, period.end, product); const periodic = await calculateCOGSForProduct(product, period.start, period.end, 'FIFO'); const difference = Math.abs(perpetual - periodic.periodic); if (difference > 0.01) { console.warn(`COGS mismatch for ${product}: Perpetual=${perpetual}, Periodic=${periodic.periodic}`); } } ``` * **API Errors for COGS Entries:** * **Solution:** Ensure all required parameters (e.g., `cogs_method`) are provided correctly. Valid methods include 'FIFO', 'LIFO', 'AVERAGE'. Check that numeric fields are numbers, not strings. * **Data Inconsistencies:** * **Solution:** Implement regular data audits. Compare StateSet inventory levels/values with physical counts or accounting records. Ensure workflows correctly record all movements (receipts, consumptions, adjustments, shipments). ```javascript theme={null} async function performDataAudit() { const products = ['FINISHED_GOOD_X', 'RAW_MAT_A']; const auditResults = []; for (const product of products) { const StateSetValue = await calculateCurrentInventoryValue(product); // Compare with external system or physical count auditResults.push({ product, StateSetQty: StateSetValue.quantity, StateSetValue: StateSetValue.value, // externalQty: getFromExternalSystem(product), // variance: calculateVariance() }); } return auditResults; } ``` *** ## Support Resources For further assistance, refer to the official StateSet resources: * **API Documentation:** [https://docs.StateSet.com/api-reference](https://docs.StateSet.com/api-reference) * **Developer Community:** [https://StateSet.com/community](https://StateSet.com/community) * **Support Contact:** [support@StateSet.com](mailto:support@StateSet.com) * **Tutorials & Guides:** [https://docs.StateSet.com/guides](https://docs.StateSet.com/guides) *** ## Conclusion This enhanced guide demonstrates how to utilize the StateSet API for a complete, accurate COGS workflow—from tracking costs in production (COGM) to calculating and recording COGS based on sales and inventory changes. By distinguishing key concepts like COGM vs. COGS, incorporating dedicated API endpoints for COGS entries, and supporting both perpetual and periodic inventory systems, you can achieve precise financial insights. Key improvements covered in this guide include: * Clear distinction between Cost of Goods Manufactured (COGM) and Cost of Goods Sold (COGS) * Support for both perpetual and periodic inventory systems * Complete workflow from purchase orders through production to sales * Integration with StateSet's COGS Entries API for proper accounting records * Implementation of multiple costing methods (FIFO, LIFO, Average Cost) * Tracking of direct labor and manufacturing overhead * Comprehensive error handling and troubleshooting guidance * Advanced considerations for multi-currency, standard costing, and system integrations Remember to adapt the logic to your specific business needs and consult accounting professionals for compliance with relevant regulations (GAAP/IFRS). Leveraging StateSet effectively empowers data-driven decisions, enhances cost control, and ultimately contributes to improved business performance. *** # Comprehensive Testing Guide Source: https://docs.stateset.com/guides/comprehensive-testing-guide Complete guide to testing StateSet API integrations including unit tests, integration tests, and end-to-end testing strategies # Comprehensive Testing Guide Testing is crucial for building reliable StateSet integrations. This guide covers testing strategies from unit tests to end-to-end scenarios, helping you build confidence in your integration. ## Testing Overview Test individual functions and components in isolation Test interactions between your code and StateSet APIs Test complete workflows from start to finish ## Test Environment Setup ### Testing Pyramid Strategy ```mermaid theme={null} graph TD A[E2E Tests] --> B[Integration Tests] B --> C[Unit Tests] style A fill:#ff6b6b style B fill:#feca57 style C fill:#48dbfb ``` ### Environment Configuration ```javascript theme={null} // jest.config.js module.exports = { testEnvironment: 'node', setupFilesAfterEnv: ['/tests/setup.js'], testMatch: [ '**/__tests__/**/*.test.js', '**/*.test.js' ], collectCoverageFrom: [ 'src/**/*.js', '!src/**/*.test.js', '!src/index.js' ], coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: 80 } }, testTimeout: 30000 }; // tests/setup.js import dotenv from 'dotenv'; import { jest } from '@jest/globals'; // Load test environment variables dotenv.config({ path: '.env.test' }); // Global test setup beforeAll(() => { // Mock console methods in tests global.console = { ...console, log: jest.fn(), error: jest.fn(), warn: jest.fn(), }; }); afterAll(() => { // Cleanup after all tests jest.restoreAllMocks(); }); ``` ```python theme={null} # pytest.ini [tool:pytest] minversion = 6.0 addopts = -ra --strict-markers --strict-config --cov=src --cov-report=term-missing --cov-report=html --cov-fail-under=80 testpaths = tests python_files = test_*.py python_classes = Test* python_functions = test_* # conftest.py import pytest import os from unittest.mock import Mock from StateSet import StateSetClient @pytest.fixture(scope="session") def test_config(): """Test configuration fixture.""" return { 'api_key': os.getenv('STATESET_TEST_API_KEY', 'sk_test_fake_key'), 'base_url': 'https://api.sandbox.StateSet.com', 'timeout': 30 } @pytest.fixture def mock_client(): """Mock StateSet client for unit tests.""" return Mock(spec=StateSetClient) @pytest.fixture def real_client(test_config): """Real StateSet client for integration tests.""" return StateSetClient(**test_config) @pytest.fixture(autouse=True) def cleanup_test_data(): """Cleanup test data after each test.""" yield # Add cleanup logic here pass ``` ```ruby theme={null} # spec/spec_helper.rb require 'bundler/setup' require 'StateSet' require 'webmock/rspec' require 'vcr' # Configure VCR for HTTP recording VCR.configure do |config| config.cassette_library_dir = 'spec/vcr_cassettes' config.hook_into :webmock config.configure_rspec_metadata! config.filter_sensitive_data('') { ENV['STATESET_API_KEY'] } end RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end config.shared_context_metadata_behavior = :apply_to_host_groups # Test environment setup config.before(:suite) do StateSet.configure do |StateSet_config| StateSet_config.api_key = ENV['STATESET_TEST_API_KEY'] || 'sk_test_fake' StateSet_config.environment = 'test' end end end ``` ## Unit Testing ### Testing Individual Functions ```javascript theme={null} // src/orderProcessor.js import { StateSetClient } from 'StateSet-node'; import winston from 'winston'; export class OrderProcessor { constructor(client, logger = winston.createLogger()) { this.client = client; this.logger = logger; } async processOrder(orderData) { try { // Validate order data const validation = this.validateOrder(orderData); if (!validation.isValid) { throw new Error(`Validation failed: ${validation.errors.join(', ')}`); } // Create order const order = await this.client.orders.create(orderData); this.logger.info('Order processed successfully', { orderId: order.id }); return order; } catch (error) { this.logger.error('Order processing failed', { error: error.message }); throw error; } } validateOrder(orderData) { const errors = []; if (!orderData.customer_email) { errors.push('Customer email is required'); } if (!orderData.items || orderData.items.length === 0) { errors.push('Order must contain at least one item'); } if (orderData.items) { orderData.items.forEach((item, index) => { if (!item.sku) errors.push(`Item ${index}: SKU is required`); if (!item.quantity || item.quantity <= 0) { errors.push(`Item ${index}: Quantity must be positive`); } }); } return { isValid: errors.length === 0, errors }; } } // __tests__/orderProcessor.test.js import { OrderProcessor } from '../src/orderProcessor.js'; import { jest } from '@jest/globals'; describe('OrderProcessor', () => { let orderProcessor; let mockClient; let mockLogger; beforeEach(() => { mockClient = { orders: { create: jest.fn() } }; mockLogger = { info: jest.fn(), error: jest.fn() }; orderProcessor = new OrderProcessor(mockClient, mockLogger); }); describe('validateOrder', () => { it('should return valid for correct order data', () => { const orderData = { customer_email: 'test@example.com', items: [ { sku: 'ITEM-001', quantity: 2 } ] }; const result = orderProcessor.validateOrder(orderData); expect(result.isValid).toBe(true); expect(result.errors).toHaveLength(0); }); it('should return invalid for missing email', () => { const orderData = { items: [{ sku: 'ITEM-001', quantity: 2 }] }; const result = orderProcessor.validateOrder(orderData); expect(result.isValid).toBe(false); expect(result.errors).toContain('Customer email is required'); }); it('should return invalid for empty items', () => { const orderData = { customer_email: 'test@example.com', items: [] }; const result = orderProcessor.validateOrder(orderData); expect(result.isValid).toBe(false); expect(result.errors).toContain('Order must contain at least one item'); }); it('should validate individual items', () => { const orderData = { customer_email: 'test@example.com', items: [ { sku: 'ITEM-001', quantity: 2 }, { quantity: 1 }, // Missing SKU { sku: 'ITEM-003', quantity: -1 } // Invalid quantity ] }; const result = orderProcessor.validateOrder(orderData); expect(result.isValid).toBe(false); expect(result.errors).toContain('Item 1: SKU is required'); expect(result.errors).toContain('Item 2: Quantity must be positive'); }); }); describe('processOrder', () => { it('should create order successfully', async () => { const orderData = { customer_email: 'test@example.com', items: [{ sku: 'ITEM-001', quantity: 2 }] }; const expectedOrder = { id: 'order_123', ...orderData }; mockClient.orders.create.mockResolvedValue(expectedOrder); const result = await orderProcessor.processOrder(orderData); expect(mockClient.orders.create).toHaveBeenCalledWith(orderData); expect(mockLogger.info).toHaveBeenCalledWith( 'Order processed successfully', { orderId: 'order_123' } ); expect(result).toEqual(expectedOrder); }); it('should throw error for invalid order data', async () => { const orderData = { items: [] }; // Invalid data await expect(orderProcessor.processOrder(orderData)).rejects.toThrow( 'Validation failed' ); expect(mockClient.orders.create).not.toHaveBeenCalled(); expect(mockLogger.error).toHaveBeenCalled(); }); it('should handle API errors', async () => { const orderData = { customer_email: 'test@example.com', items: [{ sku: 'ITEM-001', quantity: 2 }] }; const apiError = new Error('API Error'); mockClient.orders.create.mockRejectedValue(apiError); await expect(orderProcessor.processOrder(orderData)).rejects.toThrow('API Error'); expect(mockLogger.error).toHaveBeenCalledWith( 'Order processing failed', { error: 'API Error' } ); }); }); }); ``` ```python theme={null} # src/order_processor.py import logging from typing import Dict, List, Any from StateSet import StateSetClient class OrderProcessor: def __init__(self, client: StateSetClient, logger=None): self.client = client self.logger = logger or logging.getLogger(__name__) async def process_order(self, order_data: Dict[str, Any]) -> Dict[str, Any]: try: # Validate order data validation = self.validate_order(order_data) if not validation['is_valid']: raise ValueError(f"Validation failed: {', '.join(validation['errors'])}") # Create order order = await self.client.orders.create(order_data) self.logger.info(f'Order processed successfully: {order["id"]}') return order except Exception as error: self.logger.error(f'Order processing failed: {str(error)}') raise def validate_order(self, order_data: Dict[str, Any]) -> Dict[str, Any]: errors = [] if not order_data.get('customer_email'): errors.append('Customer email is required') items = order_data.get('items', []) if not items: errors.append('Order must contain at least one item') for index, item in enumerate(items): if not item.get('sku'): errors.append(f'Item {index}: SKU is required') if not item.get('quantity') or item.get('quantity') <= 0: errors.append(f'Item {index}: Quantity must be positive') return { 'is_valid': len(errors) == 0, 'errors': errors } # tests/test_order_processor.py import pytest from unittest.mock import AsyncMock, Mock from src.order_processor import OrderProcessor class TestOrderProcessor: @pytest.fixture def mock_client(self): client = Mock() client.orders = Mock() client.orders.create = AsyncMock() return client @pytest.fixture def mock_logger(self): return Mock() @pytest.fixture def order_processor(self, mock_client, mock_logger): return OrderProcessor(mock_client, mock_logger) def test_validate_order_valid_data(self, order_processor): order_data = { 'customer_email': 'test@example.com', 'items': [{'sku': 'ITEM-001', 'quantity': 2}] } result = order_processor.validate_order(order_data) assert result['is_valid'] is True assert len(result['errors']) == 0 def test_validate_order_missing_email(self, order_processor): order_data = { 'items': [{'sku': 'ITEM-001', 'quantity': 2}] } result = order_processor.validate_order(order_data) assert result['is_valid'] is False assert 'Customer email is required' in result['errors'] def test_validate_order_empty_items(self, order_processor): order_data = { 'customer_email': 'test@example.com', 'items': [] } result = order_processor.validate_order(order_data) assert result['is_valid'] is False assert 'Order must contain at least one item' in result['errors'] def test_validate_order_invalid_items(self, order_processor): order_data = { 'customer_email': 'test@example.com', 'items': [ {'sku': 'ITEM-001', 'quantity': 2}, {'quantity': 1}, # Missing SKU {'sku': 'ITEM-003', 'quantity': -1} # Invalid quantity ] } result = order_processor.validate_order(order_data) assert result['is_valid'] is False assert 'Item 1: SKU is required' in result['errors'] assert 'Item 2: Quantity must be positive' in result['errors'] @pytest.mark.asyncio async def test_process_order_success(self, order_processor, mock_client, mock_logger): order_data = { 'customer_email': 'test@example.com', 'items': [{'sku': 'ITEM-001', 'quantity': 2}] } expected_order = {'id': 'order_123', **order_data} mock_client.orders.create.return_value = expected_order result = await order_processor.process_order(order_data) mock_client.orders.create.assert_called_once_with(order_data) mock_logger.info.assert_called_once_with('Order processed successfully: order_123') assert result == expected_order @pytest.mark.asyncio async def test_process_order_validation_error(self, order_processor, mock_client): order_data = {'items': []} # Invalid data with pytest.raises(ValueError, match='Validation failed'): await order_processor.process_order(order_data) mock_client.orders.create.assert_not_called() @pytest.mark.asyncio async def test_process_order_api_error(self, order_processor, mock_client, mock_logger): order_data = { 'customer_email': 'test@example.com', 'items': [{'sku': 'ITEM-001', 'quantity': 2}] } mock_client.orders.create.side_effect = Exception('API Error') with pytest.raises(Exception, match='API Error'): await order_processor.process_order(order_data) mock_logger.error.assert_called_once_with('Order processing failed: API Error') ``` ## Integration Testing ### Testing API Interactions ```javascript theme={null} // __tests__/integration/orders.integration.test.js import { StateSetClient } from 'StateSet-node'; import { OrderProcessor } from '../../src/orderProcessor.js'; describe('Orders Integration Tests', () => { let client; let orderProcessor; let createdOrderIds = []; beforeAll(() => { client = new StateSetClient({ apiKey: process.env.STATESET_TEST_API_KEY, environment: 'sandbox' }); orderProcessor = new OrderProcessor(client); }); afterAll(async () => { // Cleanup created orders for (const orderId of createdOrderIds) { try { await client.orders.delete(orderId); } catch (error) { console.warn(`Failed to cleanup order ${orderId}:`, error.message); } } }); it('should create and retrieve an order', async () => { const orderData = { customer_email: 'integration-test@example.com', items: [ { sku: 'TEST-ITEM-001', quantity: 2, price: 1999 } ], shipping_address: { line1: '123 Test Street', city: 'Test City', state: 'CA', postal_code: '90210', country: 'US' } }; // Create order const createdOrder = await orderProcessor.processOrder(orderData); createdOrderIds.push(createdOrder.id); expect(createdOrder.id).toBeDefined(); expect(createdOrder.customer_email).toBe(orderData.customer_email); expect(createdOrder.status).toBe('pending'); // Retrieve order const retrievedOrder = await client.orders.get(createdOrder.id); expect(retrievedOrder.id).toBe(createdOrder.id); expect(retrievedOrder.customer_email).toBe(orderData.customer_email); }); it('should handle order status updates', async () => { const orderData = { customer_email: 'status-test@example.com', items: [{ sku: 'TEST-ITEM-002', quantity: 1, price: 999 }], shipping_address: { line1: '456 Status Street', city: 'Status City', state: 'NY', postal_code: '10001', country: 'US' } }; const order = await orderProcessor.processOrder(orderData); createdOrderIds.push(order.id); // Update order status const updatedOrder = await client.orders.update(order.id, { status: 'confirmed' }); expect(updatedOrder.status).toBe('confirmed'); // Verify status change const retrievedOrder = await client.orders.get(order.id); expect(retrievedOrder.status).toBe('confirmed'); }); it('should handle order cancellation', async () => { const orderData = { customer_email: 'cancel-test@example.com', items: [{ sku: 'TEST-ITEM-003', quantity: 1, price: 1500 }], shipping_address: { line1: '789 Cancel Street', city: 'Cancel City', state: 'TX', postal_code: '75001', country: 'US' } }; const order = await orderProcessor.processOrder(orderData); createdOrderIds.push(order.id); // Cancel order const cancelledOrder = await client.orders.cancel(order.id, { reason: 'Customer requested cancellation' }); expect(cancelledOrder.status).toBe('cancelled'); expect(cancelledOrder.cancellation_reason).toBe('Customer requested cancellation'); }); it('should handle API errors gracefully', async () => { const invalidOrderData = { customer_email: 'invalid-test@example.com', items: [ { sku: 'INVALID-SKU-THAT-DOES-NOT-EXIST', quantity: 1, price: 999 } ] }; await expect(orderProcessor.processOrder(invalidOrderData)).rejects.toThrow(); }); it('should handle rate limiting', async () => { const requests = []; // Make multiple concurrent requests to test rate limiting for (let i = 0; i < 10; i++) { requests.push( client.orders.list({ limit: 1 }) ); } const results = await Promise.allSettled(requests); // At least some requests should succeed const successful = results.filter(r => r.status === 'fulfilled'); expect(successful.length).toBeGreaterThan(0); // Check if any were rate limited const rateLimited = results.filter( r => r.status === 'rejected' && r.reason.status === 429 ); if (rateLimited.length > 0) { logger.info(`${rateLimited.length} requests were rate limited (expected behavior);`); } }); }); ``` ```python theme={null} # tests/integration/test_orders_integration.py import pytest import asyncio from StateSet import StateSetClient from src.order_processor import OrderProcessor @pytest.mark.integration class TestOrdersIntegration: @pytest.fixture(scope="class") async def client(self): return StateSetClient( api_key=os.getenv('STATESET_TEST_API_KEY'), environment='sandbox' ) @pytest.fixture(scope="class") async def order_processor(self, client): return OrderProcessor(client) @pytest.fixture def order_data(self): return { 'customer_email': 'integration-test@example.com', 'items': [ { 'sku': 'TEST-ITEM-001', 'quantity': 2, 'price': 1999 } ], 'shipping_address': { 'line1': '123 Test Street', 'city': 'Test City', 'state': 'CA', 'postal_code': '90210', 'country': 'US' } } @pytest.mark.asyncio async def test_create_and_retrieve_order(self, order_processor, client, order_data): # Create order created_order = await order_processor.process_order(order_data) assert created_order['id'] is not None assert created_order['customer_email'] == order_data['customer_email'] assert created_order['status'] == 'pending' # Retrieve order retrieved_order = await client.orders.get(created_order['id']) assert retrieved_order['id'] == created_order['id'] assert retrieved_order['customer_email'] == order_data['customer_email'] # Cleanup await client.orders.delete(created_order['id']) @pytest.mark.asyncio async def test_order_status_updates(self, order_processor, client, order_data): order_data['customer_email'] = 'status-test@example.com' order = await order_processor.process_order(order_data) # Update order status updated_order = await client.orders.update(order['id'], { 'status': 'confirmed' }) assert updated_order['status'] == 'confirmed' # Verify status change retrieved_order = await client.orders.get(order['id']) assert retrieved_order['status'] == 'confirmed' # Cleanup await client.orders.delete(order['id']) @pytest.mark.asyncio async def test_rate_limiting_handling(self, client): # Make multiple concurrent requests tasks = [client.orders.list(limit=1) for _ in range(10)] results = await asyncio.gather(*tasks, return_exceptions=True) # At least some should succeed successful = [r for r in results if not isinstance(r, Exception)] assert len(successful) > 0 # Check for rate limiting rate_limited = [r for r in results if isinstance(r, Exception) and getattr(r, 'status', None) == 429] if rate_limited: print(f"{len(rate_limited)} requests were rate limited (expected)") ``` ## End-to-End Testing ### Complete Workflow Testing ```javascript theme={null} // tests/e2e/order-workflow.e2e.test.js import { test, expect } from '@playwright/test'; import { StateSetClient } from 'StateSet-node'; test.describe('Complete Order Workflow', () => { let client; let testOrderId; test.beforeAll(async () => { client = new StateSetClient({ apiKey: process.env.STATESET_TEST_API_KEY, environment: 'sandbox' }); }); test.afterAll(async () => { // Cleanup if (testOrderId) { try { await client.orders.delete(testOrderId); } catch (error) { console.warn('Failed to cleanup test order:', error.message); } } }); test('should complete full order lifecycle', async ({ page }) => { // 1. Create order via API const orderData = { customer_email: 'e2e-test@example.com', items: [ { sku: 'E2E-TEST-ITEM', quantity: 1, price: 2999, name: 'E2E Test Product' } ], shipping_address: { line1: '123 E2E Street', city: 'Test City', state: 'CA', postal_code: '90210', country: 'US' } }; const order = await client.orders.create(orderData); testOrderId = order.id; expect(order.status).toBe('pending'); // 2. Navigate to order management dashboard await page.goto(`${process.env.DASHBOARD_URL}/orders/${order.id}`); // 3. Verify order details in UI await expect(page.locator('[data-testid="order-id"]')).toContainText(order.id); await expect(page.locator('[data-testid="customer-email"]')).toContainText('e2e-test@example.com'); await expect(page.locator('[data-testid="order-status"]')).toContainText('pending'); // 4. Process order through UI await page.click('[data-testid="confirm-order-btn"]'); await page.waitForSelector('[data-testid="order-status"]:has-text("confirmed")'); // 5. Verify status change via API const updatedOrder = await client.orders.get(order.id); expect(updatedOrder.status).toBe('confirmed'); // 6. Ship order await page.click('[data-testid="ship-order-btn"]'); await page.fill('[data-testid="tracking-number"]', 'TEST-TRACKING-123'); await page.click('[data-testid="confirm-shipment-btn"]'); await page.waitForSelector('[data-testid="order-status"]:has-text("shipped")'); // 7. Verify final status const shippedOrder = await client.orders.get(order.id); expect(shippedOrder.status).toBe('shipped'); expect(shippedOrder.tracking_number).toBe('TEST-TRACKING-123'); // 8. Check customer notification const notifications = await client.notifications.list({ order_id: order.id, type: 'shipment' }); expect(notifications.data.length).toBeGreaterThan(0); expect(notifications.data[0].recipient_email).toBe('e2e-test@example.com'); }); test('should handle order cancellation workflow', async ({ page }) => { // Create order const orderData = { customer_email: 'cancel-e2e-test@example.com', items: [{ sku: 'CANCEL-TEST-ITEM', quantity: 1, price: 1999 }], shipping_address: { line1: '456 Cancel Street', city: 'Cancel City', state: 'NY', postal_code: '10001', country: 'US' } }; const order = await client.orders.create(orderData); testOrderId = order.id; // Navigate to order await page.goto(`${process.env.DASHBOARD_URL}/orders/${order.id}`); // Cancel order through UI await page.click('[data-testid="cancel-order-btn"]'); await page.fill('[data-testid="cancellation-reason"]', 'Customer requested cancellation'); await page.click('[data-testid="confirm-cancellation-btn"]'); // Wait for status update await page.waitForSelector('[data-testid="order-status"]:has-text("cancelled")'); // Verify via API const cancelledOrder = await client.orders.get(order.id); expect(cancelledOrder.status).toBe('cancelled'); expect(cancelledOrder.cancellation_reason).toBe('Customer requested cancellation'); }); }); ``` ```javascript theme={null} // cypress/e2e/order-management.cy.js describe('Order Management E2E', () => { let testOrderId; beforeEach(() => { // Login to dashboard cy.login(); }); afterEach(() => { // Cleanup test orders if (testOrderId) { cy.cleanupOrder(testOrderId); } }); it('should create and manage order through complete lifecycle', () => { // Create order via API cy.createTestOrder().then((order) => { testOrderId = order.id; // Visit order details page cy.visit(`/orders/${order.id}`); // Verify order details cy.get('[data-cy="order-id"]').should('contain', order.id); cy.get('[data-cy="order-status"]').should('contain', 'pending'); cy.get('[data-cy="customer-email"]').should('contain', order.customer_email); // Confirm order cy.get('[data-cy="confirm-order"]').click(); cy.get('[data-cy="order-status"]').should('contain', 'confirmed'); // Add shipping information cy.get('[data-cy="add-shipping"]').click(); cy.get('[data-cy="tracking-number"]').type('CY-TEST-123'); cy.get('[data-cy="carrier"]').select('UPS'); cy.get('[data-cy="submit-shipping"]').click(); // Verify shipping status cy.get('[data-cy="order-status"]').should('contain', 'shipped'); cy.get('[data-cy="tracking-number"]').should('contain', 'CY-TEST-123'); // Verify API state cy.verifyOrderStatus(order.id, 'shipped'); }); }); it('should handle order search and filtering', () => { // Create multiple test orders cy.createMultipleTestOrders(5).then((orders) => { orders.forEach(order => testOrderId = order.id); // Keep last for cleanup cy.visit('/orders'); // Test search functionality cy.get('[data-cy="order-search"]').type(orders[0].customer_email); cy.get('[data-cy="search-results"]').should('contain', orders[0].id); // Test status filtering cy.get('[data-cy="status-filter"]').select('pending'); cy.get('[data-cy="order-list"] tr').should('have.length.at.least', 1); // Test date range filtering cy.get('[data-cy="date-from"]').type('2023-01-01'); cy.get('[data-cy="date-to"]').type('2023-12-31'); cy.get('[data-cy="apply-filters"]').click(); cy.get('[data-cy="order-list"]').should('be.visible'); }); }); }); // cypress/support/commands.js Cypress.Commands.add('login', () => { cy.session('login', () => { cy.visit('/login'); cy.get('[data-cy="email"]').type(Cypress.env('TEST_USER_EMAIL')); cy.get('[data-cy="password"]').type(Cypress.env('TEST_USER_PASSWORD')); cy.get('[data-cy="login-button"]').click(); cy.url().should('include', '/dashboard'); }); }); Cypress.Commands.add('createTestOrder', () => { return cy.request({ method: 'POST', url: `${Cypress.env('API_BASE_URL')}/orders`, headers: { 'Authorization': `Bearer ${Cypress.env('STATESET_API_KEY')}`, 'Content-Type': 'application/json' }, body: { customer_email: 'cypress-test@example.com', items: [ { sku: 'CY-TEST-ITEM', quantity: 1, price: 2999 } ], shipping_address: { line1: '123 Cypress Street', city: 'Test City', state: 'CA', postal_code: '90210', country: 'US' } } }).then((response) => response.body); }); Cypress.Commands.add('verifyOrderStatus', (orderId, expectedStatus) => { cy.request({ method: 'GET', url: `${Cypress.env('API_BASE_URL')}/orders/${orderId}`, headers: { 'Authorization': `Bearer ${Cypress.env('STATESET_API_KEY')}` } }).then((response) => { expect(response.body.status).to.equal(expectedStatus); }); }); Cypress.Commands.add('cleanupOrder', (orderId) => { cy.request({ method: 'DELETE', url: `${Cypress.env('API_BASE_URL')}/orders/${orderId}`, headers: { 'Authorization': `Bearer ${Cypress.env('STATESET_API_KEY')}` }, failOnStatusCode: false }); }); ``` ## Performance Testing ### Load Testing with Artillery ```yaml theme={null} # artillery-config.yml config: target: 'https://api.sandbox.StateSet.com' phases: - duration: 60 arrivalRate: 5 name: "Warm up" - duration: 120 arrivalRate: 10 name: "Load test" - duration: 60 arrivalRate: 20 name: "Stress test" variables: api_key: "{{ $env.STATESET_TEST_API_KEY }}" processor: "./test-helpers.js" scenarios: - name: "Order Management" weight: 70 flow: - post: url: "/v1/orders" headers: Authorization: "Bearer {{ api_key }}" Content-Type: "application/json" json: customer_email: "load-test-{{ $randomString() }}@example.com" items: - sku: "LOAD-TEST-ITEM" quantity: "{{ $randomInt(1, 5) }}" price: 1999 shipping_address: line1: "123 Load Test St" city: "Test City" state: "CA" postal_code: "90210" country: "US" capture: - json: "$.id" as: "orderId" - get: url: "/v1/orders/{{ orderId }}" headers: Authorization: "Bearer {{ api_key }}" - put: url: "/v1/orders/{{ orderId }}" headers: Authorization: "Bearer {{ api_key }}" Content-Type: "application/json" json: status: "confirmed" - name: "Order Listing" weight: 30 flow: - get: url: "/v1/orders" qs: limit: "{{ $randomInt(10, 50) }}" status: "pending" headers: Authorization: "Bearer {{ api_key }}" ``` ### Stress Testing ```javascript theme={null} // stress-test.js import { StateSetClient } from 'StateSet-node'; import { performance } from 'perf_hooks'; class StressTest { constructor() { this.client = new StateSetClient({ apiKey: process.env.STATESET_TEST_API_KEY, environment: 'sandbox' }); this.metrics = { requests: 0, errors: 0, latencies: [] }; } async runConcurrentOrders(concurrency = 10, duration = 60000) { logger.info(`Starting stress test: ${concurrency} concurrent users for ${duration}ms`); const startTime = Date.now(); const workers = []; // Start concurrent workers for (let i = 0; i < concurrency; i++) { workers.push(this.orderWorker(startTime + duration)); } // Wait for all workers to complete await Promise.all(workers); // Calculate results const totalDuration = Date.now() - startTime; const avgLatency = this.metrics.latencies.reduce((a, b) => a + b, 0) / this.metrics.latencies.length; const errorRate = (this.metrics.errors / this.metrics.requests) * 100; const throughput = this.metrics.requests / (totalDuration / 1000); logger.info('Stress Test Results:'); logger.info(`Total Requests: ${this.metrics.requests}`); logger.info(`Errors: ${this.metrics.errors} (${errorRate.toFixed(2);}%)`); logger.info(`Average Latency: ${avgLatency.toFixed(2);}ms`); logger.info(`Throughput: ${throughput.toFixed(2);} req/sec`); return { requests: this.metrics.requests, errors: this.metrics.errors, errorRate, avgLatency, throughput }; } async orderWorker(endTime) { while (Date.now() < endTime) { const start = performance.now(); try { await this.createTestOrder(); this.metrics.requests++; this.metrics.latencies.push(performance.now() - start); } catch (error) { this.metrics.errors++; logger.error('Order creation failed:', error.message); } // Small delay to prevent overwhelming await new Promise(resolve => setTimeout(resolve, 100)); } } async createTestOrder() { const orderData = { customer_email: `stress-test-${Date.now()}@example.com`, items: [ { sku: 'STRESS-TEST-ITEM', quantity: Math.floor(Math.random() * 5) + 1, price: Math.floor(Math.random() * 5000) + 1000 } ], shipping_address: { line1: '123 Stress Test Street', city: 'Test City', state: 'CA', postal_code: '90210', country: 'US' } }; return this.client.orders.create(orderData); } } // Run stress test const stressTest = new StressTest(); stressTest.runConcurrentOrders(20, 120000) // 20 concurrent users for 2 minutes .then(results => { logger.info('Stress test completed successfully'); process.exit(0); }) .catch(error => { logger.error('Stress test failed:', error); process.exit(1); }); ``` ## Testing Best Practices * Separate unit, integration, and E2E tests * Use descriptive test names * Group related tests together * Follow AAA pattern (Arrange, Act, Assert) * Use factories for test data generation * Clean up test data after tests * Use isolated test environments * Mock external dependencies * Run tests on every commit * Separate fast and slow test suites * Use parallel test execution * Generate coverage reports * Monitor test execution times * Alert on test failures * Track test coverage trends * Performance regression detection ## Continuous Integration Setup ```yaml theme={null} # .github/workflows/test.yml name: Test Suite on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - run: npm ci - run: npm run test:unit env: STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }} - name: Upload coverage reports uses: codecov/codecov-action@v3 integration-tests: runs-on: ubuntu-latest needs: unit-tests steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - run: npm ci - run: npm run test:integration env: STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }} e2e-tests: runs-on: ubuntu-latest needs: integration-tests steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - run: npm ci - run: npx playwright install - run: npm run test:e2e env: STATESET_TEST_API_KEY: ${{ secrets.STATESET_TEST_API_KEY }} DASHBOARD_URL: ${{ secrets.DASHBOARD_URL }} ``` ## Next Steps After implementing comprehensive testing: 1. **Monitor Test Metrics**: Track coverage, execution time, and flakiness 2. **Expand Test Scenarios**: Add edge cases and error conditions 3. **Performance Baselines**: Establish performance benchmarks 4. **Test Automation**: Integrate with deployment pipelines For more testing strategies, see: * [Error Handling Best Practices](/guides/error-handling-best-practices) * [Performance Optimization](/guides/performance-optimization) * [API Rate Limiting](/guides/api-rate-limiting) # Subscriptions Quickstart Source: https://docs.stateset.com/guides/customers-quickstart Getting started with the Customers and Subscriptions API ## Prerequisites Before you begin managing customers and subscriptions, ensure you have: * A StateSet account ([Sign up here](https://StateSet.com/sign-up)) * API credentials from the [StateSet Dashboard](https://app.StateSet.com/settings/api-keys) * Subscription management enabled in your workspace * Stripe account and API keys (for payment processing) * Understanding of subscription billing models * PCI compliance considerations (if handling payment data) * Node.js 16+ installed * Basic understanding of REST APIs and JavaScript * Familiarity with GraphQL (optional but recommended) * Access to your existing customer database (if migrating) * Customer data mapped to StateSet schema * Data validation and cleanup completed ## Overview StateSet One provides a REST and GraphQL API for Subscription Lifecycle Management. These objects typically encompass: * Customers * Subscription * Subscription Items ### Customer Management Overview The Customer Management API provides a set of endpoints for managing customers. These endpoints allow you to create, update, and delete customers. You can also retrieve information about customers and their subscriptions. ### Customer Management Challenges Customer Management is a complex process that requires a lot of time and effort. It involves managing customer data, subscriptions, and payments. The process is often manual and error-prone, which can lead to customer dissatisfaction and lost revenue. ### StateSet's Customer Management Solutions StateSet's Customer Management solutions are designed to help you manage your customers more efficiently. Our solutions include: * Customer Data Management * Subscription Lifecycle Management * Recurring Billing Processing via Stripe ### Quickstart Guide 1. Setup your company's StateSet One instance by signing up at StateSet.com/sign-up 2. Create a new API key in the StateSet Cloud Console cloud.StateSet.com/api-keys 3. Install the StateSet-node SDK in your project: ```jsx theme={null} npm install StateSet-node ``` 4. Create a new Customer ```jsx javascript theme={null} import { StateSet } from 'StateSet-node'('API_KEY'); const customer = await StateSet.customers.create({ customer: { email: 'customer@gmail.com' first_name: 'John', last_name: 'Doe', phone: '555-555-5555', stripe_customer_id: null, address: { line1: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94111', country: 'US' } } }); ``` 5. Create a new Subscription in Stripe and Update the StateSet Customer Record with the Stripe Customer Id ```jsx javascript theme={null} import { stripe } from 'stripe-node'('API_KEY'); import { StateSet } from 'StateSet-node'('API_KEY'); const subscription = await stripe.subscriptions.create({ subscription: { customer_id: customer.id, plan_id: 'plan_123', payment_method_id: 'pm_123' } }); // If the User doesn't already Exist in Stripe if (!existing_customer) { // Create the Stripe Customer var name = ''; if (customer.firstName != null) { name = customer.firstName; }; if (customer.lastName != null) { if (name != '') { name = name + ' ' + customer.lastName; } else { name = customer.lastName; } }; if (name.trim() == '') { name = '-'; }; const stripe_customer = await stripe.customers.create({ name: name, email: customer.email, metadata: { "sso": sso_id } // Adding sso to metadata }); // Update Customer const StateSet_customer = await StateSet.customers.update({ sso_id: sso_id, customer: { stripe_customer_id: stripe_customer.id, temporary_subscription_plan: null } }); } ``` ### UCP The Unified Customer Profile (UCP) is a powerful system developed by StateSet that allows Direct-to-Consumer (DTC) brands to manage customer data and integrate it with various systems of record, including Stripe. By leveraging customer records and Stripe customer IDs, StateSet enables seamless integration and synchronization between systems using Remote Data Joins. UCP provides functionality to create unique customer profiles, eliminate duplicate profiles, and update customer information. This documentation provides an overview of the key features and capabilities of UCP, along with instructions on how to use it effectively. 1. Customer Profile Management UCP enables the creation and management of unique customer profiles across multiple systems of record. By utilizing a single UUID, StateSet ensures that customer data remains consistent and synchronized throughout different platforms. 2. Stripe Integration UCP integrates with Stripe, a popular payment processing platform, allowing brands to leverage its capabilities for subscription management. The integration is achieved through Remote Data Joins, enabling seamless data exchange and synchronization between StateSet and Stripe. 3. Duplicate Profile Detection and Elimination StateSet's UCP includes built-in functionality to identify and eliminate duplicate customer profiles. This feature ensures data integrity and prevents redundant records within the system. 4. Automated Actions Based on User Existence UCP has the ability to check for the existence of users in other systems of record and perform automated actions based on the results. For instance, if a user does not exist in the system, UCP can create the user in Stripe, assign a Stripe Customer ID, and use the StateSet SDK to update the user's information. ### StateSet and Stripe StateSet provides a Stripe GraphQL server for remote data joins with Hasura. This allows you to query Stripe data directly from your GraphQL API. ```jsx graphql theme={null} query getCustomer($sso_id: uuid!) { customers: customers_by_pk(sso_id: $sso_id) { sso_id firstName lastName email stripe_customer_id activationDate delinquency_date plan_change_date returns { id action_needed amount condition created_date description issue reason_category refunded_date } warranties { id action_needed amount condition created_date description issue reason_category } stripe_data { id metadata subscriptions { data { id metadata status created cancelAt currentPeriodStart currentPeriodEnd plan { id metadata nickname created } items { data { id metadata price { id nickname unitAmount recurring { aggregateUsage usageType } } } } } } } } } ``` ### Unified Customer Profile UCP empowers DTC brands by providing a unified and streamlined approach to managing customer profiles. Through integration with Stripe and the use of Remote Data Joins, UCP ensures data consistency, eliminates duplicate profiles, and enables efficient customer data management. By following the documentation and guidelines provided by StateSet, you can effectively leverage UCP's features. ### Subscriptions Support If you have any questions or need help, please contact us at: [support@StateSet.com](mailto:support@StateSet.com) # Ecommerce Agent Workflows Guide Source: https://docs.stateset.com/guides/ecommerce-agent-workflows-guide Build a multi-agent order-to-cash pipeline with Shopify, NetSuite & DCL using StateSet's Agent & Workflow Frameworks. # Ecommerce Agent Workflows This guide shows how to orchestrate **Shopify → NetSuite → DCL** operations with *multiple autonomous AI Agents* powered by StateSet's **Agent Framework**, **Workflow Framework**, and **Agentic OS Connector**. CTOs, Solutions Architects, and DevOps engineers building a resilient, observable, and fully-automated order-to-cash pipeline. StateSet One platform orchestrates complex order operations by connecting various e-commerce and backend systems. This automation streamlines processes from order capture to fulfillment, inventory management, and customer service. Key benefits include: * **Automated Order Flow:** Seamlessly move order data from Shopify to NetSuite and then to DCL for fulfillment. * **Real-time Fulfillment Updates:** Keep Shopify and NetSuite synchronized with shipment and tracking information from DCL. * **Inventory Accuracy:** Maintain consistent inventory levels between NetSuite, DCL, and Shopify. * **Efficient Inbound Logistics:** Automate PO/ASN communication with DCL and item receipt processing in NetSuite. * **Agentic Customer Service:** Enhance Gorgias with AI-powered responses and actions via integrations with Recharge and Shopify. * **Centralized Orchestration:** Utilize StateSet for robust, observable, and scalable workflow management. This guide focuses on the API-driven interactions orchestrated by the workflows defined in `workflows.js` and activities in `activities.js`. *** ## 1. Architectural Primer | Layer | Purpose | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Agent Framework** | Runs containerised agents that each own one business capability. Triggers → Preconditions → Actions → Post-conditions ensure deterministic, idempotent runs. | | **Workflow Framework** | Declarative, version-controlled sequences of API calls with rollback, retries, and logging baked in. Every Agent owns a single Workflow implementation. | | **Agentic OS Connector** | A thin HTTP/gRPC façade that pushes normalised events into the Agent bus, manages secrets, schedules retries, and renders the cross-system **Work-Graph UI**. | *** ## 2. Catalog of Agents & Workflows ### Order Processing Tier | # | Agent / Workflow | Trigger | Purpose | | - | --------------------------- | -------------- | ----------------------------------------------------------------------------------- | | 1 | `shopifyToNetsuiteWorkflow` | Shopify Agent | Convert Shopify Order → NetSuite Sales Order (SO); tag order `SENT_TO_NS`. | | 2 | `netsuiteToDCLWorkflow` | NetSuite Agent | Transform SO and POST to DCL; set `custbody_sent_to_3pl = T`. | | 3 | `dclTrackingUpdateWorkflow` | DCL Agent | Create Item Fulfillment & optional Cash Sale in NetSuite; push tracking to Shopify. | ### Inventory Management Tier | # | Agent / Workflow | Trigger | Purpose | | - | ------------------------------ | --------------------------------------- | -------------------------------------------------------------- | | 4 | `dclPoNotificationWorkflow` | NetSuite PO/TO status `Pending Receipt` | Send ASN (Advance Ship Notice) to DCL. | | 5 | `dclPoReceiptWorkflow` | DCL Agent | Create Item Receipt, reconcile quantity, close PO if complete. | | 6 | `inventorySyncWorkflow` | Cron (\*/15 min) | Pull inventory from NetSuite, bulk update Shopify. | | 7 | `inventoryBundlesSyncWorkflow` | Cron (\*/15 min +10 sec) | Compute bundle availability and update Shopify bundles. | ### Financial Processing Tier | # | Agent / Workflow | Trigger | Purpose | | - | --------------------- | ----------------------------------- | ------------------------------------------------ | | 8 | `netsuiteInvoiceFlow` | SO status `Pending Billing` | Create Invoice, tag SO `INVOICED`. | | 9 | `netsuitePaymentFlow` | Invoice `Open` + payment settlement | Record payment, apply to Invoice, close Invoice. | *** ## 3. End-to-End Pipeline Walkthrough ```mermaid theme={null} sequenceDiagram autonumber Shopify->>Agent 1: Order Created Agent 1->>NetSuite: Create Sales Order NetSuite-->>Shopify: SO ID & Tag NetSuite->>Agent 2: SO Approved Agent 2->>DCL: (Pick Pack Ship) DCL-->>Agent 3: Fulfillment + Tracking Agent 3->>NetSuite: Item Fulfillment / Cash Sale Agent 3->>Shopify: Fulfillment & Tracking NetSuite->>Agent 8: SO Pending Billing Agent 8->>NetSuite: Create Invoice Payment Gateway-->>Agent 9: Settlement File Agent 9->>NetSuite: Create & Apply Payment ``` *** ## 4. Deployment & Operations 1. **Packaging** – Each Agent ships as a container invoking `agent run`. 2. **Versioning** – Semantic versions; upgrades spin a shadow copy replaying last 24 h of events before cut-over. 3. **Observability** – Logs & metrics stream to Grafana/Prometheus; Work-Graph UI renders lineage and retries. 4. **Error Handling** – Automatic exponential retries for idempotent calls; compensation jobs registered per Agent; Slack/E-mail hooks after N failures. *** ## 5. FAQ **Q: Do I need all nine agents on day one?**\ No. Start with the Shopify→NetSuite workflow, then gradually enable the others as your operational maturity grows. **Q: How are bundle quantities computed?**\ `inventoryBundlesSyncWorkflow` requests BOM data from NetSuite, then calculates `bundle_qty = MIN(component_qty[])`. **Q: Can I extend this to Amazon or WooCommerce?**\ Yes—write a new Agent that maps their order schema to the canonical `OrderCreated` event expected by `shopifyToNetsuiteWorkflow`. *** ## 6. Triggering Workflows from the CLI Once your Agents are deployed you can kick-off any workflow on demand via the **StateSet CLI** (a lightweight Node binary). • **Single command** – `StateSet run --connector ` posts a JSON payload to the Agentic OS Connector REST endpoint. • **Stateless** – The CLI simply packages your payload and returns the `workflow_id`; orchestration, retries and logging are handled by the platform. • **Environment-driven** – Point to *prod*, *staging* or *local dev-tunnels* by changing the `STATESET_ENDPOINT` env variable or passing `--endpoint`. • **CI/CD ready** – Works in GitHub Actions, CircleCI, or any shell, enabling synthetic orders during pipeline builds or bulk-replay of historical events. • **Security** – Uses the same API tokens as the dashboard; no secrets are stored locally. Use the CLI for *backfills, migrations, on-demand tests or bulk operations.* Use webhooks or schedules for real-time and recurring automation. *** ## Next Steps 1. Read the Agents Quickstart to understand core Agent APIs. 2. Explore Order Operations for advanced order-management patterns. Happy automating! 🚀 # Error Handling Best Practices Source: https://docs.stateset.com/guides/error-handling-best-practices Comprehensive guide to handling errors gracefully in StateSet API integrations # Error Handling Best Practices Robust error handling is critical for production applications. This guide covers comprehensive strategies for handling StateSet API errors gracefully, implementing retry logic, and maintaining application reliability. ## Understanding StateSet Error Responses ### Error Response Structure All StateSet API errors follow a consistent structure: ```json theme={null} { "error": { "type": "invalid_request_error", "code": "INVALID_PARAMETER", "message": "The 'email' parameter is required", "param": "email", "request_id": "req_abc123", "documentation_url": "https://docs.StateSet.com/api-reference/errors#invalid-parameter" }, "timestamp": "2024-01-15T10:30:00Z" } ``` ### Error Categories **Errors in your request** * Authentication failures * Invalid parameters * Rate limiting * Resource not found **Temporary service issues** * Internal server errors * Service unavailable * Gateway timeouts * Maintenance mode ## Common Error Codes ### Authentication Errors **Cause**: Invalid or missing API key ```javascript theme={null} // ❌ Common mistake const client = new StateSetClient({ apiKey: 'wrong_key_format' }); // ✅ Proper handling const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); if (!process.env.STATESET_API_KEY) { throw new Error('STATESET_API_KEY environment variable is required'); } try { const customers = await client.customers.list(); } catch (error) { if (error.code === 'UNAUTHORIZED') { logger.error('Authentication failed - check API key', { requestId: error.request_id, documentation: error.documentation_url }); // Notify operations team await notifyAuthenticationFailure(error); } throw error; } ``` **Cause**: API key lacks required permissions ```javascript theme={null} try { const customer = await client.customers.delete(customerId); } catch (error) { if (error.code === 'FORBIDDEN') { logger.warn('Insufficient permissions for operation', { operation: 'customer.delete', customerId, requiredPermission: 'customers:write', requestId: error.request_id }); // Fallback to read-only operation const customer = await client.customers.get(customerId); return { customer, canDelete: false }; } throw error; } ``` ### Validation Errors ```javascript theme={null} // ✅ Comprehensive validation error handling async function createCustomerSafely(customerData) { try { const customer = await client.customers.create(customerData); logger.info('Customer created successfully', { customerId: customer.id }); return customer; } catch (error) { if (error.code === 'INVALID_PARAMETER') { const validationErrors = error.details?.validation_errors || []; logger.warn('Customer creation failed - validation errors', { errors: validationErrors, requestId: error.request_id, inputData: sanitizeForLogging(customerData) }); // Return user-friendly error messages return { success: false, errors: validationErrors.map(err => ({ field: err.param, message: err.message, code: err.code })) }; } if (error.code === 'DUPLICATE_RESOURCE') { logger.info('Customer already exists', { email: customerData.email, existingId: error.details?.existing_resource_id }); // Return existing customer return await client.customers.get(error.details.existing_resource_id); } throw error; // Re-throw unexpected errors } } // Helper function to sanitize sensitive data function sanitizeForLogging(data) { const sanitized = { ...data }; if (sanitized.email) sanitized.email = maskEmail(sanitized.email); if (sanitized.phone) sanitized.phone = maskPhone(sanitized.phone); return sanitized; } ``` ### Rate Limiting ```javascript theme={null} // ✅ Intelligent rate limit handling with exponential backoff class RateLimitHandler { constructor(options = {}) { this.maxRetries = options.maxRetries || 3; this.baseDelay = options.baseDelay || 1000; this.maxDelay = options.maxDelay || 30000; this.jitterFactor = options.jitterFactor || 0.1; } async executeWithRetry(operation, context = {}) { let lastError; for (let attempt = 0; attempt <= this.maxRetries; attempt++) { try { return await operation(); } catch (error) { lastError = error; if (error.code !== 'RATE_LIMIT_EXCEEDED') { throw error; // Not a rate limit error } if (attempt === this.maxRetries) { logger.error('Max retries exceeded for rate limited request', { attempts: attempt + 1, context, requestId: error.request_id }); throw error; } const delay = this.calculateDelay(attempt, error); logger.warn('Rate limited - retrying request', { attempt: attempt + 1, delayMs: delay, retryAfter: error.headers?.['retry-after'], context, requestId: error.request_id }); await this.sleep(delay); } } throw lastError; } calculateDelay(attempt, error) { // Use server-provided retry-after if available const retryAfter = error.headers?.['retry-after']; if (retryAfter) { return Math.min(parseInt(retryAfter) * 1000, this.maxDelay); } // Exponential backoff with jitter const exponentialDelay = this.baseDelay * Math.pow(2, attempt); const jitter = exponentialDelay * this.jitterFactor * Math.random(); return Math.min(exponentialDelay + jitter, this.maxDelay); } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Usage example const rateLimitHandler = new RateLimitHandler({ maxRetries: 5, baseDelay: 1000, maxDelay: 60000 }); async function createCustomerWithRetry(customerData) { return await rateLimitHandler.executeWithRetry( () => client.customers.create(customerData), { operation: 'customer.create', email: customerData.email } ); } ``` ## Advanced Error Handling Patterns ### Circuit Breaker Pattern ```javascript theme={null} // ✅ Circuit breaker to prevent cascading failures class CircuitBreaker { constructor(options = {}) { this.failureThreshold = options.failureThreshold || 5; this.timeout = options.timeout || 60000; this.monitoringPeriod = options.monitoringPeriod || 10000; this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN this.failureCount = 0; this.lastFailureTime = null; this.nextAttempt = null; } async execute(operation, fallback = null) { if (this.state === 'OPEN') { if (Date.now() < this.nextAttempt) { logger.warn('Circuit breaker is OPEN - using fallback', { nextAttempt: new Date(this.nextAttempt).toISOString(), failureCount: this.failureCount }); if (fallback) return await fallback(); throw new Error('Circuit breaker is OPEN - service unavailable'); } this.state = 'HALF_OPEN'; logger.info('Circuit breaker entering HALF_OPEN state'); } try { const result = await operation(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { this.failureCount = 0; this.state = 'CLOSED'; logger.info('Circuit breaker reset to CLOSED state'); } onFailure() { this.failureCount++; this.lastFailureTime = Date.now(); if (this.failureCount >= this.failureThreshold) { this.state = 'OPEN'; this.nextAttempt = Date.now() + this.timeout; logger.error('Circuit breaker opened due to failures', { failureCount: this.failureCount, nextAttempt: new Date(this.nextAttempt).toISOString() }); } } } // Usage with StateSet API const circuitBreaker = new CircuitBreaker({ failureThreshold: 3, timeout: 30000 }); async function getCustomerWithFallback(customerId) { return await circuitBreaker.execute( () => client.customers.get(customerId), () => getCachedCustomer(customerId) // Fallback to cache ); } ``` ### Batch Operations Error Handling ```javascript theme={null} // ✅ Robust batch processing with partial failure handling class BatchProcessor { constructor(options = {}) { this.batchSize = options.batchSize || 100; this.maxConcurrency = options.maxConcurrency || 5; this.retryFailures = options.retryFailures !== false; } async processBatch(items, processor) { const batches = this.createBatches(items); const results = []; const failures = []; for (const batch of batches) { try { const batchResults = await this.processBatchConcurrently(batch, processor); results.push(...batchResults.successes); failures.push(...batchResults.failures); } catch (error) { logger.error('Batch processing failed completely', { batchSize: batch.length, error: error.message }); // Add all items in failed batch to failures failures.push(...batch.map(item => ({ item, error: error.message, retryable: this.isRetryableError(error) }))); } } // Retry failures if enabled if (this.retryFailures && failures.length > 0) { const retryableFailures = failures.filter(f => f.retryable); if (retryableFailures.length > 0) { logger.info('Retrying failed batch items', { retryCount: retryableFailures.length, totalFailures: failures.length }); const retryResults = await this.retryFailures(retryableFailures, processor); results.push(...retryResults.successes); // Update failures list with remaining failures const remainingFailures = failures.filter(f => !f.retryable); remainingFailures.push(...retryResults.failures); } } return { successes: results, failures, summary: { total: items.length, succeeded: results.length, failed: failures.length, successRate: (results.length / items.length) * 100 } }; } createBatches(items) { const batches = []; for (let i = 0; i < items.length; i += this.batchSize) { batches.push(items.slice(i, i + this.batchSize)); } return batches; } async processBatchConcurrently(batch, processor) { const semaphore = new Semaphore(this.maxConcurrency); const successes = []; const failures = []; const promises = batch.map(async (item, index) => { await semaphore.acquire(); try { const result = await processor(item, index); successes.push({ item, result }); } catch (error) { failures.push({ item, error: error.message, code: error.code, retryable: this.isRetryableError(error) }); } finally { semaphore.release(); } }); await Promise.all(promises); return { successes, failures }; } isRetryableError(error) { const retryableCodes = [ 'RATE_LIMIT_EXCEEDED', 'INTERNAL_SERVER_ERROR', 'SERVICE_UNAVAILABLE', 'GATEWAY_TIMEOUT' ]; return retryableCodes.includes(error.code); } } // Simple semaphore implementation class Semaphore { constructor(limit) { this.limit = limit; this.current = 0; this.queue = []; } async acquire() { return new Promise((resolve) => { if (this.current < this.limit) { this.current++; resolve(); } else { this.queue.push(resolve); } }); } release() { this.current--; if (this.queue.length > 0) { const next = this.queue.shift(); this.current++; next(); } } } // Usage example const batchProcessor = new BatchProcessor({ batchSize: 50, maxConcurrency: 3 }); async function createCustomersBatch(customerDataList) { return await batchProcessor.processBatch( customerDataList, async (customerData) => { return await client.customers.create(customerData); } ); } ``` ## Production Monitoring & Alerting ### Error Tracking ```javascript theme={null} // ✅ Comprehensive error tracking and metrics class ErrorTracker { constructor() { this.errorCounts = new Map(); this.errorRates = new Map(); this.alertThresholds = { errorRate: 0.05, // 5% error rate consecutiveErrors: 10, criticalErrors: ['UNAUTHORIZED', 'FORBIDDEN'] }; } trackError(error, context = {}) { const errorKey = `${error.code}_${context.operation || 'unknown'}`; // Update error counts this.errorCounts.set(errorKey, (this.errorCounts.get(errorKey) || 0) + 1); // Log error with context logger.error('StateSet API error tracked', { code: error.code, message: error.message, operation: context.operation, requestId: error.request_id, timestamp: new Date().toISOString(), ...context }); // Check for critical errors if (this.alertThresholds.criticalErrors.includes(error.code)) { this.sendCriticalAlert(error, context); } // Check error rate thresholds this.checkErrorRateThreshold(errorKey, context); } trackSuccess(context = {}) { const operationKey = context.operation || 'unknown'; this.updateSuccessRate(operationKey); } sendCriticalAlert(error, context) { // Integration with alerting system (PagerDuty, Slack, etc.) const alert = { severity: 'critical', title: `StateSet API Critical Error: ${error.code}`, description: error.message, context, timestamp: new Date().toISOString(), requestId: error.request_id }; // Send alert to monitoring system this.sendAlert(alert); } async sendAlert(alert) { try { // Example: Send to Slack webhook await fetch(process.env.SLACK_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: `🚨 ${alert.title}`, attachments: [{ color: alert.severity === 'critical' ? 'danger' : 'warning', fields: [ { title: 'Description', value: alert.description, short: false }, { title: 'Request ID', value: alert.requestId, short: true }, { title: 'Context', value: JSON.stringify(alert.context), short: true } ] }] }) }); } catch (alertError) { logger.error('Failed to send alert', { originalAlert: alert, alertError: alertError.message }); } } } // Global error tracker instance const errorTracker = new ErrorTracker(); // Enhanced API client with error tracking class TrackedStateSetClient { constructor(options) { this.client = new StateSetClient(options); this.errorTracker = errorTracker; } async makeRequest(operation, requestFn) { try { const result = await requestFn(); this.errorTracker.trackSuccess({ operation }); return result; } catch (error) { this.errorTracker.trackError(error, { operation }); throw error; } } // Wrap all client methods get customers() { return { create: (data) => this.makeRequest('customers.create', () => this.client.customers.create(data) ), get: (id) => this.makeRequest('customers.get', () => this.client.customers.get(id) ), list: (params) => this.makeRequest('customers.list', () => this.client.customers.list(params) ) // ... other methods }; } } ``` ## Testing Error Scenarios ```javascript theme={null} // ✅ Comprehensive error scenario testing describe('StateSet API Error Handling', () => { let client; beforeEach(() => { client = new TrackedStateSetClient({ apiKey: process.env.STATESET_TEST_API_KEY }); }); describe('Authentication Errors', () => { test('handles invalid API key gracefully', async () => { const invalidClient = new StateSetClient({ apiKey: 'invalid_key' }); await expect(invalidClient.customers.list()).rejects.toMatchObject({ code: 'UNAUTHORIZED', message: expect.stringContaining('Invalid API key') }); }); test('handles missing API key', async () => { expect(() => new StateSetClient({})).toThrow('API key is required'); }); }); describe('Rate Limiting', () => { test('handles rate limit with retry', async () => { const rateLimitHandler = new RateLimitHandler({ maxRetries: 2 }); // Mock rate limited responses const mockOperation = jest.fn() .mockRejectedValueOnce({ code: 'RATE_LIMIT_EXCEEDED', headers: { 'retry-after': '1' } }) .mockResolvedValueOnce({ id: 'cust_123' }); const result = await rateLimitHandler.executeWithRetry(mockOperation); expect(mockOperation).toHaveBeenCalledTimes(2); expect(result).toEqual({ id: 'cust_123' }); }); }); describe('Circuit Breaker', () => { test('opens circuit after threshold failures', async () => { const circuitBreaker = new CircuitBreaker({ failureThreshold: 2, timeout: 1000 }); const failingOperation = jest.fn().mockRejectedValue(new Error('Service error')); const fallback = jest.fn().mockResolvedValue({ cached: true }); // Trigger circuit breaker await expect(circuitBreaker.execute(failingOperation)).rejects.toThrow(); await expect(circuitBreaker.execute(failingOperation)).rejects.toThrow(); // Circuit should now be open const result = await circuitBreaker.execute(failingOperation, fallback); expect(result).toEqual({ cached: true }); expect(fallback).toHaveBeenCalled(); }); }); }); ``` ## Error Handling Checklist **Before deploying to production, ensure you have:** ✅ **Proper error categorization** - Handle different error types appropriately\ ✅ **Retry logic** - Implement exponential backoff for retryable errors\ ✅ **Circuit breakers** - Prevent cascading failures in distributed systems\ ✅ **Fallback mechanisms** - Graceful degradation when APIs are unavailable\ ✅ **Comprehensive logging** - Log errors with sufficient context for debugging\ ✅ **Monitoring & alerting** - Set up alerts for critical error conditions\ ✅ **Error testing** - Test all error scenarios in your test suite\ ✅ **Documentation** - Document error handling strategies for your team ## Best Practices Summary 1. **Always use environment variables** for API keys and secrets 2. **Implement proper logging** instead of console.log statements 3. **Handle rate limiting** with intelligent retry mechanisms 4. **Use circuit breakers** for external API calls 5. **Track error metrics** and set up appropriate alerts 6. **Test error scenarios** comprehensively 7. **Provide meaningful fallbacks** when possible 8. **Never log sensitive information** in error messages *** **Need Help?** If you encounter persistent errors or need assistance with error handling strategies, our support team is here to help. Contact us at [support@StateSet.com](mailto:support@StateSet.com) with your request ID for faster resolution. # Evaluations Guide Source: https://docs.stateset.com/guides/evaluations-guide Create and manage evaluations to improve AI response quality and train custom models ## Overview The Evaluations system enables you to assess, track, and improve the quality of AI-generated responses. By creating evaluations, you can build datasets for fine-tuning models, monitor performance trends, and ensure consistent high-quality customer interactions. * **Quality Assurance**: Monitor and improve response quality * **Model Training**: Export evaluations as JSONL for fine-tuning * **Performance Tracking**: Analyze trends and identify areas for improvement * **Team Insights**: Understand response patterns across different support types ## Evaluation Status Types Each evaluation is assigned a status that reflects the quality of the response: Exceptional responses that exceed expectations. These serve as gold-standard examples for training. Good responses that meet quality standards and properly address customer needs. Responses requiring additional assessment or minor improvements before final classification. Responses with significant issues that don't meet quality standards. Critical failures requiring immediate attention and remediation. ## Creating Evaluations ### Manual Evaluation Creation To create a new evaluation manually: 1. Navigate to the Evaluations Dashboard 2. Click "Create New Evaluation" 3. Fill in the evaluation details: ```json theme={null} { "eval_name": "Customer Refund Request Handling", "eval_type": "Customer Service", "user_message": "I want to return my order #12345. It arrived damaged.", "preferred_output": "I'm sorry to hear your order arrived damaged. I'll help you with the return right away. I've initiated a return for order #12345 and you'll receive a prepaid shipping label via email within 24 hours. Once we receive the item, your refund will be processed within 3-5 business days.", "non_preferred_output": "You need to go to our website and fill out the return form.", "eval_status": "Outstanding", "description": "Exemplary handling of damaged product return with empathy and clear next steps" } ``` ### Evaluation Types Choose the appropriate type for your evaluation: * **Customer Service**: General customer inquiries and support * **Technical Support**: Technical issues and troubleshooting * **Sales**: Sales-related interactions and inquiries * **Product Support**: Product-specific questions and guidance * **General**: Other types of interactions ### Building Effective Test Sets To create robust evaluations, build test sets that represent real-world scenarios: * **Golden Test Sets**: Curate 50-100 high-quality examples with expected responses. * **Diverse Scenarios**: Include in-scope queries, out-of-scope small talk, and adversarial questions. * **Synthetic Data**: Generate variations using LLMs to expand coverage, including edge cases and bias tests. * **Iteration**: Continuously update based on production data and user feedback. Use these test sets to ensure comprehensive evaluation coverage. ## Managing Evaluations ### Dashboard Features The Evaluations Dashboard provides comprehensive tools for management: * **Smart Search**: Search by name, type, ticket ID, or description * **Type Filter**: Filter by evaluation type (Customer Service, Technical Support, etc.) * **Status Filter**: View evaluations by their quality status * **Date Range**: Filter by creation date (Last 7/30/90 days or all time) * **Sorting**: Sort by date, name, status, or type in ascending/descending order * **Select Multiple**: Use checkboxes to select multiple evaluations * **Bulk Export**: Export selected evaluations to JSONL format * **Bulk Delete**: Remove multiple evaluations at once * **Select All**: Quickly select all visible evaluations * **Table View**: Traditional table layout for efficient scanning * **Card View**: Visual card layout for detailed preview * **Analytics View**: Coming soon - detailed insights and trends ### Types of Evaluation Methods Enhance your evaluation process using different methods: * Direct feedback from users or experts * Best for nuanced quality assessment * Example: Rate response empathy on a 1-5 scale * Use another AI to evaluate outputs * Scalable for large datasets * Example: Prompt an LLM to score factual accuracy * Programmatic checks for specific criteria * Ideal for objective metrics * Example: Verify response format or keyword presence Combine these methods for comprehensive quality assurance. ### Performance Statistics Monitor your evaluation metrics through dashboard cards: * **Total Evaluations**: Overall count of all evaluations * **Outstanding**: Count of exceptional responses * **Needs Review**: Evaluations requiring further assessment * **This Week**: Recent evaluation activity Each metric includes trend indicators showing performance changes over time. ## Exporting for Model Training ### JSONL Export Format Evaluations can be exported in JSONL format for model fine-tuning: ```json theme={null} { "input": { "messages": [ { "role": "user", "content": "I want to return my order #12345. It arrived damaged." } ], "tools": [], "parallel_tool_calls": true }, "preferred_output": [ { "role": "assistant", "content": "I'm sorry to hear your order arrived damaged..." } ], "non_preferred_output": [ { "role": "assistant", "content": "You need to go to our website and fill out the return form." } ] } ``` ### Export Methods 1. Navigate to the Export tab in the dashboard 2. Select "Create New" mode 3. Enter the evaluation details: * User Message * Preferred Output * Non-Preferred Output * Tools (optional, for function calling) 4. Click "Export to JSONL" 1. Navigate to the Export tab 2. Select "From Existing Evals" mode 3. Choose evaluations to export: * Use checkboxes to select specific evaluations * Click "Select All" to export all evaluations 4. Click "Export X Evaluations" ### Advanced Export Options For evaluations involving tool use or function calling: ```json theme={null} { "tools": [ { "type": "function", "function": { "name": "process_return", "description": "Process a product return request", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "The order ID to process return for" }, "reason": { "type": "string", "description": "Reason for the return" } }, "required": ["order_id", "reason"] } } } ] } ``` ## Best Practices ### Creating High-Quality Evaluations Use descriptive names that indicate the scenario being evaluated ``` ✅ "Damaged Product Return - Empathetic Response" ❌ "Eval 1" ``` Base evaluations on actual customer interactions and common use cases Include both ideal responses and common mistakes to avoid Apply evaluation criteria consistently across similar interaction types Periodically review and update evaluations to maintain relevance ### Evaluation Criteria When assessing responses, consider: * Correct information provided * Proper understanding of the issue * Appropriate solution offered * Professional and friendly tone * Empathy for customer situation * Appropriate level of formality * All questions answered * Clear next steps provided * No missing information * Concise yet comprehensive * Direct problem resolution * Minimal back-and-forth needed ## Advanced Evaluation Metrics To further refine your evaluations, consider these advanced metrics tailored for AI-generated customer service responses: * How well the response addresses the specific query * Avoidance of unnecessary information * Alignment with customer needs * Logical flow of information * Consistent language and structure * Easy to follow reasoning * Enables customer action * Provides value beyond basic information * Anticipates follow-up needs * Absence of harmful content * Fair and unbiased responses * Compliance with ethical guidelines Incorporate these metrics into your evaluation rubrics for more comprehensive assessments. ## Use Cases ### Model Fine-Tuning Export evaluations to create training datasets: 1. **Collect Examples**: Build a corpus of high-quality evaluations 2. **Export to JSONL**: Use the bulk export feature 3. **Prepare Dataset**: Format according to your model's requirements 4. **Fine-Tune**: Use the dataset to improve model performance ### Quality Monitoring Track response quality over time: * Monitor status distribution (Outstanding vs. Unsatisfactory) * Identify patterns in problematic responses * Track improvement after training or process changes ### Team Training Use evaluations for human agent training: * Share examples of outstanding responses * Highlight common mistakes to avoid * Create training materials from real scenarios ## Troubleshooting * Ensure you're logged into the correct organization * Check filters aren't hiding evaluations * Refresh the dashboard * Verify all required fields are filled * Check for valid JSON in tools field * Ensure evaluations have required data * Use filters to reduce displayed evaluations * Export in smaller batches * Clear browser cache if needed ## Next Steps Start building your evaluation dataset Deep dive into evaluation strategies # Examples Quickstart Source: https://docs.stateset.com/guides/examples-quickstart Learn how to use Examples to train and improve your AI agents with real-world conversations ## Prerequisites Before creating training examples, ensure you have: * StateSet account with API access * At least one agent created and configured * API credentials from the [StateSet Dashboard](https://app.StateSet.com/settings/api-keys) * Node.js 16+ installed (for SDK examples) * Basic understanding of REST APIs and JavaScript * Text editor for JSON/code editing * Collection of real customer conversations for training data * Access to your customer support team for example validation * Understanding of your brand voice and service standards * Familiarity with machine learning concepts (helpful) * Understanding of conversational AI training principles * Knowledge of your customer service workflows and scenarios Code examples focus on core API calls. For production-ready patterns (structured logging, retries, and error handling), see [Error Handling Best Practices](/guides/error-handling-best-practices). ## Introduction Examples are the cornerstone of training effective AI agents in StateSet ResponseCX. By providing real conversation examples, you teach your agents how to handle various scenarios, maintain consistent tone, and deliver accurate responses. This guide will show you how to create, manage, and optimize examples for maximum agent performance. ## What are Examples? Examples are curated conversation snippets that demonstrate ideal agent behavior. They consist of: * **User Input**: The customer's question or statement * **Agent Response**: The ideal response from your agent * **Context**: Metadata about the scenario (tags, categories, sentiment) * **Annotations**: Notes about why this response is effective ## Why Examples Matter Ensure uniform responses across all agents and channels Reduce hallucinations and improve factual correctness Maintain your unique brand personality in every interaction ## Getting Started ```bash theme={null} npm install StateSet-node ``` ```javascript theme={null} const { StateSetClient } = require('StateSet-node'); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); ``` ```javascript theme={null} const example = await client.examples.create({ category: 'order_status', user_input: 'Where is my order? I placed it 3 days ago.', agent_response: `I'd be happy to help you track your order! To locate it quickly, could you please provide your order number or the email address used for the purchase? Once I have that information, I'll check the current status and expected delivery date for you right away.`, tags: ['order_tracking', 'polite_request', 'information_gathering'], sentiment: 'neutral', effectiveness_score: 0.95 }); ``` ## Example Categories ### 1. Customer Service Scenarios #### Order Inquiries ```javascript theme={null} const orderExample = await client.examples.create({ category: 'order_status', user_input: 'My order #12345 hasn\'t arrived yet', agent_response: `I understand your concern about order #12345. Let me check that for you right away. I can see your order was shipped on [date] via [carrier] with tracking number [tracking]. According to the latest update, it's currently in [location] and expected to arrive by [date]. If it doesn't arrive by then, please let me know and I'll be happy to help resolve this for you, including exploring replacement or refund options.`, tags: ['order_tracking', 'proactive_solution', 'empathy'], metadata: { requires_data: ['order_number', 'shipping_info'], tone: 'empathetic_professional' } }); ``` #### Product Questions ```javascript theme={null} const productExample = await client.examples.create({ category: 'product_inquiry', user_input: 'What\'s the difference between the Pro and Standard versions?', agent_response: `Great question! Let me break down the key differences between our Pro and Standard versions: **Standard Version:** - Core features for everyday use - 5GB storage - Email support - Perfect for individuals **Pro Version:** - All Standard features PLUS: - Unlimited storage - Priority 24/7 support - Advanced analytics - Team collaboration tools - API access The Pro version is ideal if you need team features or extensive storage. Would you like me to help you choose which one best fits your needs?`, tags: ['product_comparison', 'structured_response', 'upsell_opportunity'], effectiveness_score: 0.92 }); ``` ### 2. Technical Support Examples #### Troubleshooting ```javascript theme={null} const troubleshootingExample = await client.examples.create({ category: 'technical_support', user_input: 'The app keeps crashing when I try to upload photos', agent_response: `I'm sorry you're experiencing crashes with photo uploads. Let's troubleshoot this together: 1. **Quick Fix** - Try these first: - Force close the app and restart it - Check if you have at least 500MB free storage - Ensure you're on WiFi (large uploads can fail on cellular) 2. **If still crashing:** - Update to the latest app version (Settings > About > Check Updates) - Clear app cache (Settings > Storage > Clear Cache) 3. **Still having issues?** - What device and OS version are you using? - What's the file size of the photos? - Does it crash with all photos or specific ones? Let me know what happens, and I'll help you get this resolved!`, tags: ['troubleshooting', 'step_by_step', 'diagnostic_questions'], metadata: { escalation_point: 'step_3', requires_follow_up: true } }); ``` ### 3. Sales and Upsell Examples #### Subscription Upgrade ```javascript theme={null} const upsellExample = await client.examples.create({ category: 'sales_upsell', user_input: 'I\'m running out of storage space', agent_response: `I see you're getting close to your storage limit! You're currently using 4.8GB of your 5GB Standard plan. Here are your options: **Immediate Solution:** - Free up space by removing old files (I can help identify large files) **Long-term Solution - Upgrade to Pro:** - Unlimited storage (never worry about limits again) - Only $10/month more than your current plan - Includes bonus features like priority support and advanced analytics - **Special offer**: Upgrade today and get the first month 50% off! Would you like me to help free up space now, or shall I tell you more about the Pro benefits?`, tags: ['upsell', 'problem_solving', 'value_proposition', 'urgency'], conversion_rate: 0.34 }); ``` ### 4. Complaint Resolution #### Refund Request ```javascript theme={null} const complaintExample = await client.examples.create({ category: 'complaint_resolution', user_input: 'This product is terrible! I want a full refund immediately!', agent_response: `I sincerely apologize that our product hasn't met your expectations. Your satisfaction is extremely important to us, and I want to make this right. I can absolutely help you with a refund. To process this quickly: 1. I'll initiate a full refund to your original payment method 2. You'll receive a confirmation email within the next hour 3. The refund will appear in your account within 3-5 business days Additionally, I'd love to understand what went wrong so we can improve. Would you mind sharing what specific issues you experienced? This helps us serve customers better in the future. Is there anything else I can help resolve for you today?`, tags: ['de-escalation', 'refund_process', 'feedback_request', 'empathy'], sentiment: 'negative', resolution_score: 0.89 }); ``` ## Best Practices ### 1. Example Quality Guidelines ```javascript theme={null} // ❌ Poor Example - Too brief, no personality { user_input: "Where's my order?", agent_response: "Check your email for tracking info." } // ✅ Good Example - Helpful, branded, actionable { user_input: "Where's my order?", agent_response: `I'd be happy to help locate your order! To find it quickly, I'll need either: - Your order number (starts with #) - The email address used for purchase Once you share that, I'll pull up the tracking details and expected delivery date immediately.` } ``` ### 2. Organizing Examples Create a structured taxonomy: ```javascript theme={null} // Create examples with consistent categorization const exampleCategories = [ 'order_management', 'product_support', 'billing_inquiries', 'technical_issues', 'account_management', 'complaints', 'general_questions' ]; // Tag examples for easy retrieval const tags = [ 'requires_authentication', 'sensitive_data', 'escalation_candidate', 'positive_feedback', 'negative_feedback' ]; ``` ### 3. Regular Updates ```javascript theme={null} // Track example performance async function analyzeExampleEffectiveness(exampleId) { const metrics = await client.examples.getMetrics(exampleId); if (metrics.usage_count > 100 && metrics.satisfaction_score < 0.7) { // Flag for review await client.examples.update(exampleId, { needs_review: true, review_reason: 'Low satisfaction score' }); } } // Batch update examples based on feedback async function improveExamples() { const underperforming = await client.examples.list({ filter: { satisfaction_score: { $lt: 0.7 } }, limit: 50 }); for (const example of underperforming) { // Analyze common issues and update const improved = await improveResponseWithAI(example); await client.examples.update(example.id, improved); } } ``` ## Advanced Techniques ### Dynamic Example Generation ```javascript theme={null} // Generate examples from real conversations async function createExampleFromConversation(conversationId, messageId) { const conversation = await client.conversations.get(conversationId); const message = conversation.messages.find(m => m.id === messageId); if (message.satisfaction_score >= 0.9) { const example = await client.examples.create({ user_input: message.user_input, agent_response: message.agent_response, category: detectCategory(message), tags: extractTags(message), source: 'real_conversation', conversation_id: conversationId }); return example; } } ``` ### Multi-turn Examples ```javascript theme={null} // Create examples for complex, multi-turn conversations const multiTurnExample = await client.examples.create({ category: 'complex_support', conversation_flow: [ { turn: 1, user: "I can't log into my account", agent: "I'd be happy to help you regain access. Are you receiving any error messages?" }, { turn: 2, user: "Yes, it says 'Invalid credentials'", agent: "Thanks for that information. Let's verify your account. What email address are you using to log in?" }, { turn: 3, user: "john@example.com", agent: "I found your account. For security, I'll send a password reset link to jo***@example.com. You should receive it within 5 minutes. Would you like me to send it now?" } ], tags: ['multi_turn', 'account_recovery', 'security_conscious'] }); ``` ### A/B Testing Examples ```javascript theme={null} // Test different response styles async function abTestResponses(category) { const variantA = await client.examples.create({ category, variant: 'A', user_input: 'How long is shipping?', agent_response: 'Standard shipping takes 5-7 business days.', style: 'concise' }); const variantB = await client.examples.create({ category, variant: 'B', user_input: 'How long is shipping?', agent_response: `Great question! Here are our shipping options: 📦 Standard (5-7 days): Free on orders over $50 🚀 Express (2-3 days): $9.99 ⚡ Next Day: $19.99 Which would work best for you?`, style: 'detailed' }); // Monitor performance setTimeout(async () => { const performanceA = await client.examples.getMetrics(variantA.id); const performanceB = await client.examples.getMetrics(variantB.id); // Use the better performing variant const winner = performanceA.satisfaction > performanceB.satisfaction ? variantA : variantB; await client.examples.setAsDefault(winner.id, category); }, 7 * 24 * 60 * 60 * 1000); // Check after 1 week } ``` ## Monitoring & Optimization ### Performance Dashboard ```javascript theme={null} // Get insights on example usage and effectiveness async function getExamplesDashboard() { const stats = await client.examples.getStats(); return { totalExamples: stats.total, categoryCoverage: stats.categories, averageEffectiveness: stats.avg_effectiveness, mostUsed: stats.top_examples, needsAttention: stats.low_performing, recentlyAdded: stats.recent, coverageGaps: identifyCoverageGaps(stats) }; } ``` ## Integration with Other Features ### Connect with Rules ```javascript theme={null} // Link examples to specific rules const rule = await client.rules.create({ name: 'Use refund examples for complaints', condition: 'sentiment == "negative" AND intent == "refund"', action: 'use_examples', example_category: 'complaint_resolution' }); ``` ### Enhance with Attributes ```javascript theme={null} // Add context with attributes const attribute = await client.attributes.create({ name: 'customer_tier', values: ['standard', 'premium', 'vip'] }); // Create tier-specific examples const vipExample = await client.examples.create({ category: 'vip_support', required_attributes: { customer_tier: 'vip' }, user_input: 'I need help with my account', agent_response: 'Hello! As a VIP member, I\'m prioritizing your request...' }); ``` ## Next Steps Download our examples template to jumpstart your library Learn how to train agents with your examples # Agent Functions Quickstart Source: https://docs.stateset.com/guides/functions-quickstart Empower your AI agents to take real actions by integrating with external APIs and services ## Introduction Functions transform your StateSet agents from conversationalists into action-takers. By connecting to external APIs and services, your agents can perform real tasks—from canceling orders to updating inventory, processing refunds to scheduling appointments. This guide will show you how to create, manage, and optimize functions for maximum impact. ## What are Agent Functions? Agent Functions are the bridge between conversation and action. When a customer asks your agent to do something, functions enable the agent to: * **Understand Intent**: Recognize what action needs to be taken * **Extract Parameters**: Gather necessary information from the conversation * **Execute Actions**: Call external APIs to perform the task * **Handle Results**: Process responses and communicate outcomes ```mermaid theme={null} sequenceDiagram participant Customer participant Agent participant Function participant External API Customer->>Agent: "Cancel my order #12345" Agent->>Agent: Detect intent & extract parameters Agent->>Function: Execute cancel_order(order_id: "12345") Function->>External API: POST /orders/12345/cancel External API-->>Function: { success: true, status: "cancelled" } Function-->>Agent: Return result Agent->>Customer: "I've successfully cancelled order #12345" ``` ## Why Functions Matter Handle thousands of requests simultaneously without human intervention Complete actions in seconds that would take humans minutes or hours Eliminate manual errors with validated, tested automation ## Getting Started ### Prerequisites 1. StateSet account with API access 2. Agent created and configured 3. External API endpoints ready to integrate 4. API authentication credentials ### Installation ```bash npm theme={null} npm install StateSet-node ``` ```bash yarn theme={null} yarn add StateSet-node ``` ```bash pip theme={null} pip install StateSet ``` ## Creating Functions ### Basic Function Structure Every function needs: * **Name**: Unique identifier for the function * **Description**: Clear explanation for the agent to understand usage * **Endpoint**: The API URL to call * **Parameters**: Information to extract from conversations * **Authentication**: How to authenticate with the external API ### Example: Order Cancellation Function Let's create a comprehensive order cancellation function: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); async function createOrderCancellationFunction(agentId) { try { const cancelOrderFunction = await client.functions.create({ agent_id: agentId, name: 'cancel_order', description: 'Cancels a customer order and processes any necessary refunds', endpoint: 'https://api.yourstore.com/v1/orders/{order_id}/cancel', method: 'POST', parameters: [ { name: 'order_id', type: 'string', description: 'The unique order identifier', required: true, validation: { pattern: '^ORD-[0-9]{6,}$', example: 'ORD-123456' } }, { name: 'reason', type: 'string', description: 'Reason for cancellation', required: true, enum: [ 'customer_request', 'out_of_stock', 'pricing_error', 'duplicate_order', 'other' ] }, { name: 'refund_amount', type: 'number', description: 'Amount to refund (if different from order total)', required: false } ], authentication: { type: 'bearer', token_env_var: 'STORE_API_TOKEN' }, headers: { 'Content-Type': 'application/json', 'X-API-Version': '2024-01' }, request_transform: { body: { order_id: '{{order_id}}', cancellation_reason: '{{reason}}', refund: { amount: '{{refund_amount || order_total}}', method: 'original_payment_method' }, notify_customer: true } }, response_handling: { success_condition: 'status_code == 200', error_message_path: 'error.message', result_mapping: { success: 'data.cancelled', order_status: 'data.status', refund_id: 'data.refund.id', estimated_refund_date: 'data.refund.estimated_date' } }, retry_config: { max_attempts: 3, backoff: 'exponential', retry_on: [502, 503, 504] }, timeout: 30000, // 30 seconds rate_limit: { requests_per_minute: 60 } }); logger.info('Order cancellation function created:', cancelOrderFunction.id); return cancelOrderFunction; } catch (error) { logger.error('Failed to create function:', error); throw error; } } ``` ### Advanced Example: Multi-Step Function Some operations require multiple API calls. Here's a function that handles complex return processing: ```javascript theme={null} async function createReturnProcessingFunction(agentId) { const returnFunction = await client.functions.create({ agent_id: agentId, name: 'process_return', description: 'Processes a product return including validation, label generation, and refund initiation', type: 'workflow', // Indicates multi-step function steps: [ { name: 'validate_order', endpoint: 'https://api.yourstore.com/v1/orders/{order_id}', method: 'GET', output: 'order_data' }, { name: 'check_return_eligibility', endpoint: 'https://api.yourstore.com/v1/returns/check-eligibility', method: 'POST', condition: 'order_data.status == "delivered"', body: { order_id: '{{order_id}}', items: '{{return_items}}', order_date: '{{order_data.created_at}}' }, output: 'eligibility' }, { name: 'create_return_label', endpoint: 'https://api.shipping.com/v2/labels', method: 'POST', condition: 'eligibility.eligible == true', body: { from_address: '{{order_data.shipping_address}}', to_address: '{{warehouse_address}}', weight: '{{calculated_weight}}', service: 'ground' }, output: 'shipping_label' }, { name: 'create_return_record', endpoint: 'https://api.yourstore.com/v1/returns', method: 'POST', body: { order_id: '{{order_id}}', items: '{{return_items}}', reason: '{{return_reason}}', shipping_label: '{{shipping_label.tracking_number}}', expected_refund: '{{eligibility.refund_amount}}' }, output: 'return_record' } ], final_response: { success: '{{return_record.id != null}}', return_id: '{{return_record.id}}', tracking_number: '{{shipping_label.tracking_number}}', label_url: '{{shipping_label.url}}', estimated_refund: '{{eligibility.refund_amount}}', instructions: 'Please print the label and drop off the package at any {{shipping_label.carrier}} location.' } }); return returnFunction; } ``` ## Function Parameters ### Parameter Types and Validation StateSet supports comprehensive parameter validation: ```javascript theme={null} const advancedFunction = await client.functions.create({ agent_id: agentId, name: 'update_subscription', parameters: [ { name: 'customer_email', type: 'string', required: true, validation: { format: 'email', example: 'customer@example.com' } }, { name: 'subscription_plan', type: 'string', required: true, enum: ['starter', 'pro', 'enterprise'], description: 'The plan to switch to' }, { name: 'billing_period', type: 'string', required: false, default: 'monthly', enum: ['monthly', 'yearly'] }, { name: 'apply_credit', type: 'number', required: false, validation: { min: 0, max: 1000, precision: 2 } }, { name: 'effective_date', type: 'date', required: false, validation: { format: 'YYYY-MM-DD', min: 'today', max: 'today+90d' } }, { name: 'addons', type: 'array', required: false, items: { type: 'string', enum: ['extra_users', 'priority_support', 'api_access'] } } ] }); ``` ### Dynamic Parameter Extraction Configure how your agent extracts parameters from conversations: ```javascript theme={null} const smartFunction = await client.functions.create({ agent_id: agentId, name: 'smart_order_lookup', parameters: [ { name: 'identifier', type: 'string', required: true, extraction_hints: [ 'order number', 'order ID', 'confirmation number', 'reference number' ], extraction_patterns: [ 'ORD-[0-9]{6,}', '#[0-9]{8}', '[A-Z]{2}-[0-9]{8}' ] } ], parameter_resolution: { strategy: 'interactive', // or 'automatic' missing_parameter_prompt: 'I need your order number to look that up. It usually starts with ORD- or # followed by numbers.', confirmation_required: true, confirmation_prompt: 'I found order {{identifier}}. Is this the one you\'re asking about?' } }); ``` ## Authentication Methods ### API key Authentication ```javascript theme={null} const apiKeyFunction = await client.functions.create({ agent_id: agentId, name: 'inventory_check', endpoint: 'https://api.inventory.com/v1/products/{sku}/availability', authentication: { type: 'api_key', key_env_var: 'INVENTORY_API_KEY', header_name: 'X-API-Key' } }); ``` ### OAuth 2.0 Authentication ```javascript theme={null} const oauthFunction = await client.functions.create({ agent_id: agentId, name: 'calendar_booking', endpoint: 'https://api.calendar.com/v2/events', authentication: { type: 'oauth2', client_id_env_var: 'CALENDAR_CLIENT_ID', client_secret_env_var: 'CALENDAR_CLIENT_SECRET', token_url: 'https://api.calendar.com/oauth/token', scope: 'events.write', refresh_token_env_var: 'CALENDAR_REFRESH_TOKEN' } }); ``` ### Custom Authentication ```javascript theme={null} const customAuthFunction = await client.functions.create({ agent_id: agentId, name: 'legacy_system_query', endpoint: 'https://legacy.company.com/api/query', authentication: { type: 'custom', headers: { 'X-Company-ID': '{{COMPANY_ID}}', 'X-Timestamp': '{{CURRENT_TIMESTAMP}}', 'X-Signature': '{{HMAC_SHA256(COMPANY_SECRET, COMPANY_ID + CURRENT_TIMESTAMP)}}' } } }); ``` ## Error Handling ### Comprehensive Error Configuration ```javascript theme={null} const robustFunction = await client.functions.create({ agent_id: agentId, name: 'payment_processing', endpoint: 'https://api.payments.com/v1/charge', error_handling: { strategies: { 'insufficient_funds': { retry: false, message: 'The payment was declined due to insufficient funds. Would you like to try a different payment method?', suggest_actions: ['use_different_card', 'split_payment'] }, 'card_expired': { retry: false, message: 'This card has expired. Please provide a valid payment method.', suggest_actions: ['update_card'] }, 'network_error': { retry: true, max_retries: 3, message: 'I\'m having trouble processing your payment right now. Let me try again...' }, 'rate_limit': { retry: true, backoff: 'exponential', message: 'Our payment system is busy. I\'ll try again in a moment.' } }, default_strategy: { retry: true, max_retries: 2, message: 'I encountered an issue processing your request. Let me try once more.' }, fallback_action: 'escalate_to_human' } }); ``` ### Error Recovery Workflows ```javascript theme={null} const recoveryFunction = await client.functions.create({ agent_id: agentId, name: 'order_with_recovery', endpoint: 'https://api.store.com/v1/orders', error_recovery: { on_timeout: { action: 'check_status', endpoint: 'https://api.store.com/v1/orders/status/{request_id}', message: 'This is taking longer than expected. Let me check the status...' }, on_partial_success: { action: 'complete_remaining', message: 'I\'ve partially processed your order. Working on the remaining items...' }, on_failure: { actions: [ { condition: 'status_code == 500', action: 'create_support_ticket', message: 'I\'ve encountered a system issue and created a support ticket for you.' }, { condition: 'status_code == 400', action: 'request_clarification', message: 'I need to clarify some information to complete your request.' } ] } } }); ``` ## Testing Functions ### Test Mode Configuration ```javascript theme={null} const testableFunction = await client.functions.create({ agent_id: agentId, name: 'refund_processor', endpoint: 'https://api.payments.com/v1/refunds', test_mode: { enabled: true, test_endpoint: 'https://sandbox.payments.com/v1/refunds', test_credentials_env_var: 'PAYMENTS_SANDBOX_KEY', test_scenarios: [ { name: 'successful_refund', input: { amount: 100, order_id: 'TEST-001' }, expected_output: { success: true, refund_id: 'REF-TEST-001' } }, { name: 'partial_refund', input: { amount: 50, order_id: 'TEST-002' }, expected_output: { success: true, refund_id: 'REF-TEST-002', type: 'partial' } }, { name: 'failed_refund', input: { amount: 100, order_id: 'TEST-FAIL' }, expected_output: { success: false, error: 'insufficient_funds' } } ] } }); // Run tests const testResults = await client.functions.test(testableFunction.id); logger.info('Test results:', testResults); ``` ## Monitoring & Analytics ### Function Performance Tracking ```javascript theme={null} // Get function analytics const analytics = await client.functions.getAnalytics(functionId, { timeframe: '7d', metrics: ['execution_count', 'success_rate', 'avg_duration', 'error_breakdown'] }); logger.info(`Function performance: - Executions: ${analytics.execution_count} - Success Rate: ${analytics.success_rate}% - Avg Duration: ${analytics.avg_duration}ms - Most Common Error: ${analytics.error_breakdown[0]?.type} `); // Set up alerts await client.functions.createAlert({ function_id: functionId, conditions: [ { metric: 'success_rate', operator: 'less_than', threshold: 95, window: '5m' }, { metric: 'avg_duration', operator: 'greater_than', threshold: 5000, // 5 seconds window: '15m' } ], notification_channels: ['email', 'slack'] }); ``` ## Best Practices ### 1. Design for Conversation ```javascript theme={null} // Good: Natural parameter extraction const goodFunction = await client.functions.create({ name: 'track_package', description: 'Tracks a package using various identifier types', parameters: [{ name: 'tracking_info', extraction_hints: [ 'tracking number', 'order number', 'reference code' ] }] }); // Bad: Rigid parameter requirements const badFunction = await client.functions.create({ name: 'track_package', description: 'Enter the 18-digit UPS tracking number', parameters: [{ name: 'ups_tracking_number', validation: { pattern: '^1Z[0-9]{16}$' } }] }); ``` ### 2. Implement Graceful Degradation ```javascript theme={null} const resilientFunction = await client.functions.create({ name: 'product_recommendations', endpoint: 'https://api.recommendations.com/v1/suggest', fallback_behavior: { on_error: 'use_static_recommendations', static_response: { recommendations: [ { id: 'BESTSELLER-001', name: 'Our Most Popular Item' }, { id: 'BESTSELLER-002', name: 'Customer Favorite' } ], message: 'Here are some of our popular items you might like:' } } }); ``` ### 3. Security First ```javascript theme={null} const secureFunction = await client.functions.create({ name: 'user_data_update', endpoint: 'https://api.secure.com/v1/users/{user_id}', security: { require_authentication: true, allowed_roles: ['admin', 'user_self'], rate_limit: { per_user: 10, window: '1h' }, input_sanitization: true, pii_handling: { mask_in_logs: ['ssn', 'credit_card'], encrypt_in_transit: true } } }); ``` ## Advanced Patterns ### Conditional Execution ```javascript theme={null} const conditionalFunction = await client.functions.create({ name: 'smart_discount_application', execution_conditions: [ { condition: 'customer.lifetime_value > 1000', endpoint: 'https://api.store.com/v1/vip-discount' }, { condition: 'cart.total > 100 && customer.first_purchase', endpoint: 'https://api.store.com/v1/welcome-discount' }, { condition: 'cart.abandoned_duration > 3600', endpoint: 'https://api.store.com/v1/recovery-discount' } ], default_endpoint: 'https://api.store.com/v1/standard-pricing' }); ``` ### Function Chaining ```javascript theme={null} // Define a chain of functions await client.functions.createChain({ agent_id: agentId, name: 'complete_purchase_flow', description: 'Handles the entire purchase process from cart to confirmation', steps: [ { function: 'validate_cart', on_success: 'apply_discounts', on_failure: 'request_cart_update' }, { function: 'apply_discounts', on_success: 'calculate_shipping', pass_output: true }, { function: 'calculate_shipping', on_success: 'process_payment', pass_output: true }, { function: 'process_payment', on_success: 'create_order', on_failure: 'handle_payment_failure' }, { function: 'create_order', on_success: 'send_confirmation', store_result: 'order_details' } ] }); ``` ## Troubleshooting ### Common Issues and Solutions 1. **Function Not Executing** * Verify agent has permission to use the function * Check parameter extraction rules * Review execution conditions 2. **Authentication Failures** * Confirm environment variables are set * Validate token expiration * Check API credential permissions 3. **Timeout Errors** * Increase timeout configuration * Implement async processing for long operations * Add status checking endpoints 4. **Parameter Extraction Issues** * Add more extraction hints * Provide parameter examples * Enable confirmation prompts ## Next Steps Set up webhooks to trigger functions based on external events Build complex multi-step processes with conditional logic *** **Pro Tip**: Start with simple functions and gradually add complexity. Monitor performance metrics to identify optimization opportunities. For more examples and support, visit our [GitHub repository](https://github.com/StateSet/function-examples) or contact [support@StateSet.com](mailto:support@StateSet.com). # Gorgias Ticket Quickstart Source: https://docs.stateset.com/guides/gorgias-quickstart Getting started with Gorgias Ticket Embeddings ## Prerequisites Before setting up Gorgias integration, ensure you have: * Active Gorgias account with API access * Gorgias API credentials (client ID, client secret, refresh token) * Admin permissions to install integrations * Pinecone account and API key for vector storage * Pinecone index created with appropriate dimensions * Understanding of vector embeddings concepts * OpenAI API key for embeddings generation * Understanding of similarity search principles * Familiarity with RAG (Retrieval Augmented Generation) * Node.js 16+ installed * Basic understanding of REST APIs and JavaScript * Access to your Gorgias ticket data for testing ### Quickstart Guide This is a quickstart guide to get you up and running with the Gorgias Ticket Embeddings. This guide will walk you through the steps to get your Gorgias ticket data into Pinecone and create embeddings for each ticket. ### Authentication ### Gorgias Ticket Embeddings Once you have installed the app we can create embeddings and store your Gorgias ticket data in Pinecone, you can create embeddings for each ticket. Embeddings are vector representations of your ticket data. You can use these embeddings to find similar tickets or to create a recommendation system. Loop Through Gorgias Ticket Data Create embeddings for each ticket and message, and store in Pinecone Store the vector representation of the ticket data in Pinecone and associated metadata with the ticket data ```javascript theme={null} // Main function to create tickets feed const createTicketFeed = async (req, res) => { logger.info('Creating Ticket Feed'); var pinecone_index = ""; var pinecone_api_key = ""; var pinecone_namespace = ""; var shop = ""; var shopify_access_token = ""; var account = ""; try { var client_id = "" var client_secret = "" async function refreshToken(account, clientId, clientSecret, refreshToken) { const data = new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, }).toString(); const config = { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`, }, }; return axios.post(`https://${account}.gorgias.com/oauth/token`, `grant_type=refresh_token&refresh_token=${refreshToken}`, config) .then((response) => { logger.info('Refresh Token Response:', response.data.access_token); return response.data; }) .catch((error) => { logger.error(error); }); }; const token = await refreshToken(account, client_id, client_secret, gorgiasRefreshToken); const limit = 5; const maxPage = 1000; const requestOptions = { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token.access_token}`, }, }; const viewId = 525587 const response = await fetch(`https://${account}.gorgias.com/api/tickets?limit=${limit}&viewId=${viewId}`, requestOptions); // Get Ticket and the next cursor from response from axios call const next_j = await response.json(); var next_token_j = next_j.meta.next_cursor; logger.info('cursor', next_token_j); await getGorgiasTickets(next_token_j, account, limit, maxPage, token.access_token, pinecone_index, pinecone_api_key, pinecone_namespace); } catch (error) { logger.info('Error: ', error); return res.status(503).send({ success: false, error: error.stack, }); } }; let page = 1; // Get Shopify Products async function getGorgiasTickets(nextPageToken, account, limit, maxPage, access_token, pinecone_index, pinecone_api_key, pinecone_namespace) { logger.info('Getting Next Tokens'); if (page <= maxPage) { const gorgiasRequestOptions = { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${access_token}`, }, }; logger.info('access_token: ', access_token); const response = await fetch(`https://${account}.gorgias.com/api/tickets?limit=5&cursor=${nextPageToken}`, gorgiasRequestOptions); const tickets_data = await response.json(); const tickets = tickets_data.data; var next_token = tickets_data.meta.next_cursor; const documents = []; for (const item of tickets) { try { const id = item.id || null; const assignee_user = item.assignee_user || null; const channel = item.channel || null; const closed_datetime = item.closed_datetime || null; const created_datetime = item.created_datetime || null; const external_id = item.external_id || null; const language = item.language || null; const last_message_datetime = item.last_message_datetime || null; const last_received_message_datetime = item.last_received_message_datetime || null; const opened_datetime = item.opened_datetime || null; const snooze_datetime = item.snooze_datetime || null; const status = item.status || null; const update_datetime = item.update_datetime || null; const via = item.via || null; const uri = item.uri || null; const customer_id = item.customer.id || null; const email = item.customer.email || null; const name = item.customer.name || null; const firstname = item.customer.firstname || null; const lastname = item.customer.lastname || null; const gorgiasMessagesRequestOptions = { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${access_token}`, }, }; const messages_responses = await fetch(`https://${account}.gorgias.com/api/messages?ticket_id=${id}&limit=10`, gorgiasMessagesRequestOptions); const messages_data = await messages_responses.json(); logger.info('messages_data: ', messages_data); const messages = messages_data.data; if (messages.length > 0) { for (const message of messages) { let body_text = message.body_text || null; const max_length = 1000; // Check if the body text exceeds the maximum length if (body_text && body_text.length > max_length) { // Shorten the text and assign it back to body_text body_text = body_text.substring(0, max_length); // Log the shortened text logger.info("Shortened text:", body_text); } const message_id = message.id || null; const channel = message.channel || null; const created_datetime = message.created_datetime || null; const from_agent = message.from_agent || null; const receiver = message.receiver.name || null; const sender = message.sender.name || null; const subject = message.subject || null; const ticket_id = message.ticket_id || null; const via = message.via || null; let metadata = { id, assignee_user, channel, closed_datetime, created_datetime, external_id, language, last_message_datetime, last_received_message_datetime, opened_datetime, snooze_datetime, status, update_datetime, via, uri, email, customer_id, name, firstname, lastname, message_id, body_text, from_agent, receiver, sender, subject, ticket_id }; const document = { id: uuid(), id, metadata, }; documents.push(document); } } } catch (error) { logger.info(`Error processing item: ${JSON.stringify(item);}`); logger.info(error); } for (let i = 0; i < documents.length; i += DOCUMENT_UPSERT_BATCH_SIZE) { // Split documents into batches var batchDocuments = documents.slice(i, i + DOCUMENT_UPSERT_BATCH_SIZE); logger.info(batchDocuments); // Convert batchDocuments to string var batchDocumentString = JSON.stringify(batchDocuments) // Remove commas from string logger.info(batchDocumentString); // Create Embeddings logger.info('Looping through documents...'); const user_id = "domsteil"; // OpenAI Request Body var raw = JSON.stringify({ "input": batchDocumentString, "model": "text-embedding-3-large", "user": user_id }); // OpenAI Request Options var openaiRequestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': '' }, body: raw, redirect: 'follow' }; // Make Callout to OpenAI to get Embeddings logger.info('Creating Embedding...'); // Make Callout to OpenAI let embeddings_response = await fetch("https://api.openai.com/v1/embeddings", openaiRequestOptions) // Create Pinecone Request Body const vectors_embeddings = await embeddings_response.json(); logger.info(vectors_embeddings); // Create Pinecone Request Body var vectors_object = { id: uuid(), values: vectors_embeddings.data[0].embedding, metadata: { "text": batchDocumentString, "user": user_id } }; logger.info(vectors_object); var raw = JSON.stringify({ "vectors": vectors_object, "namespace": pinecone_namespace }); var pineconeRequestOptions = { method: "POST", headers: { "Content-Type": "application/json", "Host": pinecone_index, "Content-Length": 60, "Api-Key": pinecone_api_key, }, body: raw, redirect: "follow", }; // Make Callout to Pinecone // Pinecone Upsert logger.info('Upserting Pinecone...'); let pinecone_query_response = await fetch(`/vectors/upsert`, pineconeRequestOptions) .then(response => response.text()) .then(json => { logger.info(json); }) .catch(error => { logger.error(error); }); } } page += 1; logger.info(`On page ${page}, processing next page...`); return getGorgiasTickets(next_token, account, limit, maxPage, access_token, pinecone_index, pinecone_api_key, pinecone_namespace); } else { return } }; ``` ### Conclusion In this guide, we walked through the steps to get your Gorgias ticket data into Pinecone and create embeddings for each ticket. You can now use these embeddings to find similar tickets or to create a recommendation system. If you have any questions or need help, please feel free to reach out to us at [support@StateSet.com](mailto:support@StateSet.com) # GRPO Agent Framework Source: https://docs.stateset.com/guides/grpo-agent-framework Train sophisticated multi-turn conversational AI agents with Group Relative Policy Optimization ## Introduction The GRPO Agent Framework is a production-ready library for training multi-turn conversational AI agents using **Group Relative Policy Optimization (GRPO)**. This framework transforms advanced reinforcement learning techniques into an accessible platform for building sophisticated conversational agents that can handle complex, extended dialogues. ## Why GRPO? GRPO provides more stable training than traditional RL methods Native support for extended conversations with context preservation Built for real-world deployment with monitoring and serving capabilities ## Quick Start ### Installation ```bash npm theme={null} npm install grpo-agent-framework ``` ```bash pip theme={null} pip install grpo-agent-framework ``` ```bash poetry theme={null} poetry add grpo-agent-framework ``` ### Your First Agent in 5 Minutes ```python theme={null} import asyncio from grpo_agent_framework import MultiTurnAgent, ConversationEnvironment, train async def main(): # 1. Create an agent agent = MultiTurnAgent.from_model("microsoft/DialoGPT-medium") # 2. Define conversation scenarios scenarios = [ {"user_responses": ["Hi!", "How are you?", "Thanks!"]}, {"user_responses": ["I need help", "My order is late", "When will it arrive?"]} ] env = ConversationEnvironment(scenarios=scenarios) # 3. Train with GRPO trained_agent = await train( agent=agent, environment=env, num_episodes=1000, profile="balanced" # Auto-optimized settings ) # 4. Use the trained agent response = await trained_agent.generate_response([ {"role": "user", "content": "Hello! I have a question."} ]) print(f"Agent: {response}") asyncio.run(main()) ``` ## Core Concepts ### 1. Agents Agents are the conversational entities that learn through GRPO training: ```python theme={null} class MultiTurnAgent(Agent): """Specialized for extended conversations""" async def process_turn(self, history, user_input, context): # Manages conversation state # Preserves context across turns # Generates contextually appropriate responses pass ``` **Use for**: Customer service, tutoring, general assistants ```python theme={null} class ToolAgent(MultiTurnAgent): """Can use external tools and functions""" def __init__(self, config, tools): super().__init__(config) self.tools = tools async def execute_tool(self, tool_name, params): # Executes external functions # Integrates results into conversation pass ``` **Use for**: Task automation, API integration, complex workflows ```python theme={null} class CustomAgent(MultiTurnAgent): """Your specialized implementation""" def __init__(self, domain_knowledge): super().__init__(config) self.knowledge = domain_knowledge async def process_turn(self, history, user_input, context): # Add custom logic enhanced_context = self.apply_domain_knowledge(context) return await super().process_turn( history, user_input, enhanced_context ) ``` **Use for**: Domain-specific applications ### 2. Environments Environments simulate conversation scenarios for training: ```python theme={null} # Built-in environments from grpo_agent_framework import ( ConversationEnvironment, # Open-ended conversations TaskEnvironment, # Goal-oriented interactions SimulatedEnvironment # Uses external simulators ) # Custom environment example class CustomerServiceEnvironment(Environment): def __init__(self, ticket_database): self.tickets = ticket_database async def step(self, state, action): # Simulate customer interactions customer_response = await self.simulate_customer(state, action) # Calculate rewards based on resolution reward = self.calculate_service_quality(state, action, customer_response) # Check if ticket is resolved done = self.is_ticket_resolved(state) return new_state, customer_response, reward, done ``` ### 3. Reward Functions Reward functions guide agent learning by scoring conversation quality: ```python theme={null} from grpo_agent_framework.rewards import ( HelpfulnessReward, SafetyReward, CorrectnessReward, EngagementReward ) # Combine multiple rewards composite = CompositeReward([ HelpfulnessReward(weight=0.4), SafetyReward(weight=0.3), CorrectnessReward(weight=0.2), EngagementReward(weight=0.1) ]) ``` ```python theme={null} @reward_function(weight=0.5) async def domain_specific_reward(turns, context): score = 0.0 # Custom evaluation logic if resolved_issue(turns): score += 0.5 if maintained_professionalism(turns): score += 0.3 if under_time_limit(turns): score += 0.2 return score ``` ## Training Pipeline ### Basic Training ```python theme={null} from grpo_agent_framework import train, TrainingConfig # Simple training with defaults trained_agent = await train( agent=agent, environment=environment, num_episodes=2000 ) # Advanced training with custom config config = TrainingConfig( num_episodes=5000, batch_size=32, learning_rate=1e-4, gamma=0.95, clip_range=0.2, value_coefficient=0.5, entropy_coefficient=0.01, max_grad_norm=0.5, profile="aggressive", # or "balanced", "conservative" auto_adjust=True, # Automatic hyperparameter tuning checkpoint_interval=500, early_stopping_patience=10 ) trained_agent = await train( agent=agent, environment=environment, reward_fn=custom_reward, config=config, callbacks=[wandb_callback, checkpoint_callback] ) ``` ### Training Profiles The framework includes pre-tuned profiles based on extensive research: ```python theme={null} # Maximum stability, slower convergence profile="conservative" # Characteristics: # - Lower learning rate (5e-5) # - Smaller clip range (0.1) # - Higher value coefficient (1.0) # - More gradient clipping # Best for: # - Safety-critical applications # - Initial experiments # - Sensitive domains ``` ```python theme={null} # Good stability + performance profile="balanced" # Characteristics: # - Moderate learning rate (1e-4) # - Standard clip range (0.2) # - Balanced coefficients # - Adaptive adjustments # Best for: # - Most applications # - Production deployments # - General purpose agents ``` ```python theme={null} # Maximum performance, less stable profile="aggressive" # Characteristics: # - Higher learning rate (3e-4) # - Larger clip range (0.3) # - Lower value coefficient (0.5) # - Less gradient clipping # Best for: # - Rapid prototyping # - Non-critical applications # - Experienced users ``` ### Automatic Optimization The framework includes intelligent auto-tuning: ```python theme={null} from grpo_agent_framework import AutoTrainer # Automatic configuration based on task analysis auto_trainer = AutoTrainer( auto_adjust=True, target_metrics={ 'success_rate': 0.95, 'avg_turns': 5, 'user_satisfaction': 0.9 } ) # Analyzes task complexity and adjusts accordingly trained_agent = await auto_trainer.train( agent=agent, environment=environment, max_time_hours=24 ) # Monitor auto-adjustments print(f"Final config: {auto_trainer.final_config}") print(f"Adjustments made: {auto_trainer.adjustment_history}") ``` ## Advanced Features ### 1. Tool Integration Enable agents to use external tools and APIs: ```python theme={null} from grpo_agent_framework import ToolAgent, Tool # Define available tools tools = [ Tool( name="calculator", description="Performs mathematical calculations", function=calculate, parameters={ "expression": {"type": "string", "description": "Math expression"} } ), Tool( name="search", description="Searches the web for information", function=web_search, parameters={ "query": {"type": "string", "description": "Search query"} } ), Tool( name="database", description="Queries customer database", function=query_database, parameters={ "sql": {"type": "string", "description": "SQL query"} } ) ] # Create tool-enabled agent tool_agent = ToolAgent( model_name="gpt-3.5-turbo", tools=tools, tool_selection_strategy="adaptive" # or "always", "conservative" ) # Tools are automatically used during conversations response = await tool_agent.process_turn( history=[{"role": "user", "content": "What's 37 * 48?"}], user_input="Can you calculate that for me?", context={} ) # Agent uses calculator tool and responds with result ``` ### 2. Multi-GPU Training Scale training across multiple GPUs: ```python theme={null} from grpo_agent_framework import DistributedTrainer # Distributed training setup trainer = DistributedTrainer( num_gpus=4, strategy="ddp", # or "deepspeed", "fsdp" mixed_precision=True ) # Automatically handles distribution trained_agent = await trainer.train( agent=agent, environment=environment, config=config ) # Monitor GPU utilization print(f"GPU efficiency: {trainer.gpu_efficiency}") print(f"Training speedup: {trainer.speedup}x") ``` ### 3. Real-time Monitoring Track training health and performance: ```python theme={null} from grpo_agent_framework import DiagnosticsMonitor # Setup monitoring monitor = DiagnosticsMonitor( metrics=['reward_mean', 'reward_std', 'episode_length', 'loss'], alert_thresholds={ 'reward_std': 2.0, # Alert if too high 'loss_spike': 10.0 # Alert on sudden loss increases } ) # Training with monitoring trained_agent = await train( agent=agent, environment=environment, monitor=monitor ) # Access diagnostics health_report = monitor.get_health_report() if health_report.status == "unhealthy": print(f"Issues detected: {health_report.issues}") print(f"Recommendations: {health_report.recommendations}") ``` ### 4. Conversation Analytics Analyze conversation patterns and quality: ```python theme={null} from grpo_agent_framework import ConversationAnalyzer analyzer = ConversationAnalyzer() # Analyze training conversations analysis = analyzer.analyze_trajectories(training_data) print(f"Average turns: {analysis.avg_turns}") print(f"Success rate: {analysis.success_rate}") print(f"Common patterns: {analysis.frequent_patterns}") print(f"Failure modes: {analysis.failure_analysis}") # Visualize conversation flow analyzer.plot_conversation_graph(save_path="conversation_flow.png") ``` ## Production Deployment ### REST API Serving Deploy trained agents as REST APIs: ```python theme={null} from grpo_agent_framework import serve_agent # Basic serving serve_agent( agent_path="./checkpoints/my_agent", host="0.0.0.0", port=8000 ) # Advanced serving with authentication from grpo_agent_framework.serving import APIServer, AuthMiddleware server = APIServer( agent_path="./checkpoints/my_agent", middleware=[ AuthMiddleware(token="your-secret-token"), RateLimitMiddleware(requests_per_minute=100), LoggingMiddleware(log_file="conversations.log") ] ) # Custom endpoints @server.post("/custom-chat") async def custom_chat(request: ChatRequest): # Custom processing logic response = await server.agent.generate_response( request.messages, temperature=request.temperature, max_tokens=request.max_tokens ) return {"response": response, "metadata": {...}} server.run(host="0.0.0.0", port=8000) ``` ### Client Integration ```javascript theme={null} // JavaScript client example const response = await fetch('https://yourapp.com:8000/chat', { method: 'POST', headers: { 'Authorization': 'Bearer your-secret-token', 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: [ { role: 'user', content: 'Hello!' } ], temperature: 0.7 }) }); const data = await response.json(); logger.info('Agent response:', data.response); ``` ### Health Monitoring ```python theme={null} # Health check endpoint GET /health # Response { "status": "healthy", "model": "my_agent_v1", "uptime": "2h 34m", "requests_served": 1523, "avg_response_time": "234ms", "memory_usage": "2.3GB" } ``` ## Command Line Interface ### Training Commands ```bash theme={null} # Basic training grpo-train --config configs/my_agent.yaml # Advanced training with monitoring grpo-train \ --model microsoft/DialoGPT-medium \ --env customer_service \ --num-episodes 5000 \ --profile aggressive \ --auto-adjust \ --wandb-project grpo-experiments \ --checkpoint-dir ./checkpoints # Resume training grpo-train \ --resume-from ./checkpoints/epoch_50 \ --num-episodes 2000 ``` ### Evaluation Commands ```bash theme={null} # Evaluate agent performance grpo-evaluate ./checkpoints/my_agent \ --test-scenarios ./data/test_scenarios.json \ --metrics all \ --output results.json # A/B testing grpo-compare \ ./checkpoints/agent_v1 \ ./checkpoints/agent_v2 \ --scenarios ./data/ab_test.json \ --significance-level 0.05 ``` ### Deployment Commands ```bash theme={null} # Serve agent grpo-serve ./checkpoints/my_agent \ --host 0.0.0.0 \ --port 8000 \ --workers 4 \ --auth-token $API_TOKEN # Export for different platforms grpo-export ./checkpoints/my_agent \ --format onnx \ --optimize-for inference \ --output ./exports/my_agent.onnx ``` ## Best Practices ### 1. Scenario Design ```python theme={null} # Good: Diverse, realistic scenarios scenarios = [ { "context": "Customer upset about late delivery", "user_responses": [ "My order is 3 days late!", "This is unacceptable", "I want a refund" ], "success_criteria": ["apologize", "offer_solution", "retain_customer"] }, { "context": "Technical support inquiry", "user_responses": [ "My device won't turn on", "I already tried that", "It's still not working" ], "success_criteria": ["diagnose", "provide_steps", "escalate_if_needed"] } ] # Bad: Repetitive, unrealistic scenarios scenarios = [ {"user_responses": ["Hi", "Bye"]}, {"user_responses": ["Hello", "Goodbye"]}, {"user_responses": ["Hey", "See ya"]} ] ``` ### 2. Reward Function Design ```python theme={null} # Good: Balanced, measurable rewards @reward_function(weight=1.0) async def balanced_reward(turns, context): components = { 'task_completion': check_task_completed(turns, context), 'efficiency': min(1.0, 5.0 / len(turns)), # Prefer shorter conversations 'sentiment': analyze_sentiment_progression(turns), 'safety': check_safety_violations(turns) } # Weighted combination weights = {'task_completion': 0.4, 'efficiency': 0.2, 'sentiment': 0.2, 'safety': 0.2} score = sum(components[k] * weights[k] for k in components) return RewardResult( score=score, breakdown=components, explanation=generate_explanation(components) ) # Bad: Single-metric reward def bad_reward(turns, context): return 1.0 if len(turns) < 10 else 0.0 # Too simplistic ``` ### 3. Training Configuration ```python theme={null} # Good: Adaptive configuration config = TrainingConfig( # Start conservative learning_rate=5e-5, clip_range=0.1, # Enable auto-adjustment auto_adjust=True, adjustment_patience=100, # Safety checks max_grad_norm=0.5, gradient_accumulation_steps=4, # Monitoring log_interval=10, eval_interval=100, checkpoint_interval=500 ) # Bad: Static, aggressive configuration config = TrainingConfig( learning_rate=1e-3, # Too high clip_range=0.5, # Too large auto_adjust=False # No adaptation ) ``` ## Troubleshooting ### Common Issues **Symptoms**: Reward variance > 2.0, loss spikes **Solutions**: ```python theme={null} # Use conservative profile config.profile = "conservative" # Enable gradient clipping config.max_grad_norm = 0.5 # Reduce learning rate config.learning_rate *= 0.5 ``` **Symptoms**: Flat reward curve, no improvement **Solutions**: ```python theme={null} # Increase diversity in scenarios env.add_scenarios(diverse_scenarios) # Adjust reward function reward_fn.increase_granularity() # Try aggressive profile config.profile = "aggressive" ``` **Symptoms**: OOM errors, training crashes **Solutions**: ```python theme={null} # Reduce batch size config.batch_size = 16 # Enable gradient accumulation config.gradient_accumulation_steps = 8 # Use gradient checkpointing config.gradient_checkpointing = True ``` **Symptoms**: Repetitive responses, off-topic **Solutions**: ```python theme={null} # Increase entropy coefficient config.entropy_coefficient = 0.02 # Add diversity reward reward_fn.add_component(DiversityReward(0.1)) # Expand training scenarios env.randomize_scenarios = True ``` ## Performance Optimization ### Memory Optimization ```python theme={null} # Enable memory-efficient training from grpo_agent_framework import MemoryEfficientTrainer trainer = MemoryEfficientTrainer( gradient_checkpointing=True, mixed_precision="fp16", offload_to_cpu=True, max_memory_gb=8 ) # Automatically manages memory trained_agent = await trainer.train(agent, environment) ``` ### Speed Optimization ```python theme={null} # Optimize for training speed from grpo_agent_framework import SpeedOptimizedConfig config = SpeedOptimizedConfig( compile_model=True, # PyTorch 2.0 compilation use_flash_attention=True, # Flash Attention 2 dataloader_workers=8, # Parallel data loading prefetch_batches=2, # Prefetch next batches pin_memory=True # Pin memory for GPU transfer ) ``` ### Inference Optimization ```python theme={null} # Optimize trained model for deployment from grpo_agent_framework import optimize_for_inference optimized_agent = optimize_for_inference( trained_agent, quantization="int8", # 8-bit quantization compile_mode="max-autotune", # Maximum optimization batch_size=1, # Single request optimization use_cache=True # KV-cache optimization ) # 3-5x faster inference response_time = await optimized_agent.benchmark() print(f"Average response time: {response_time}ms") ``` ## Integration Examples ### With LangChain ```python theme={null} from langchain.agents import AgentExecutor from grpo_agent_framework import GRPOAgentWrapper # Wrap GRPO agent for LangChain grpo_wrapper = GRPOAgentWrapper(trained_agent) # Use in LangChain pipeline executor = AgentExecutor( agent=grpo_wrapper, tools=langchain_tools, memory=conversation_memory ) ``` ### With Hugging Face ```python theme={null} from transformers import pipeline from grpo_agent_framework import export_to_hf # Export to Hugging Face format hf_model = export_to_hf( trained_agent, model_name="my-org/grpo-agent", push_to_hub=True ) # Use with transformers pipe = pipeline("conversational", model=hf_model) ``` ### With OpenAI API ```python theme={null} from grpo_agent_framework.serving import OpenAICompatibleServer # Serve with OpenAI-compatible API server = OpenAICompatibleServer( agent=trained_agent, model_name="grpo-agent-v1" ) # Use with OpenAI client import openai openai.api_base = "https://yourapp.com:8000/v1" response = openai.ChatCompletion.create( model="grpo-agent-v1", messages=[{"role": "user", "content": "Hello!"}] ) ``` ## Extending the Framework ### Custom Agent Types ```python theme={null} from grpo_agent_framework import Agent, register_agent @register_agent("specialist") class SpecialistAgent(Agent): """Domain-specific agent with special capabilities""" def __init__(self, config, knowledge_base): super().__init__(config) self.kb = knowledge_base async def process_turn(self, history, user_input, context): # Enhance with domain knowledge facts = self.kb.retrieve(user_input) context["relevant_facts"] = facts # Generate specialized response response = await self.generate_with_facts( history, user_input, context ) return response async def generate_with_facts(self, history, user_input, context): # Custom generation logic pass ``` ### Custom Environments ```python theme={null} from grpo_agent_framework import Environment, register_environment @register_environment("simulation") class SimulationEnvironment(Environment): """Uses external simulation for realistic interactions""" def __init__(self, simulator_config): self.simulator = ExternalSimulator(simulator_config) async def reset(self): self.state = await self.simulator.reset() return self.state async def step(self, action): # Run simulation result = await self.simulator.execute(self.state, action) # Extract GRPO components next_state = result.state response = result.observation reward = self.calculate_reward(result) done = result.terminated return next_state, response, reward, done ``` ### Custom Reward Functions ```python theme={null} from grpo_agent_framework import RewardFunction, register_reward @register_reward("business_metric") class BusinessMetricReward(RewardFunction): """Rewards based on business KPIs""" def __init__(self, kpi_weights): self.kpi_weights = kpi_weights async def compute_reward(self, trajectory, context): kpis = { 'conversion': self.check_conversion(trajectory), 'satisfaction': self.measure_satisfaction(trajectory), 'efficiency': self.calculate_efficiency(trajectory), 'retention': self.predict_retention(trajectory) } # Weighted combination score = sum( kpis[k] * self.kpi_weights.get(k, 0) for k in kpis ) return RewardResult( score=score, components=kpis, metadata={'business_impact': self.estimate_impact(kpis)} ) ``` ## Research Foundation The GRPO Agent Framework is built on cutting-edge research: ### Key Papers 1. **Group Relative Policy Optimization** - The core algorithm 2. **Multi-Turn RL for Dialogue** - Conversation-specific techniques 3. **Reward Modeling at Scale** - Efficient reward function design ### Empirical Findings * **30% more stable** than standard PPO for dialogue tasks * **2.5x faster convergence** with auto-tuned hyperparameters * **45% higher user satisfaction** in A/B tests vs baseline ### Benchmarks ```python theme={null} # Run standard benchmarks from grpo_agent_framework.benchmarks import run_benchmarks results = run_benchmarks( agent=trained_agent, benchmarks=["commonsense_qa", "empathetic_dialogues", "wizard_of_wikipedia"], metrics=["perplexity", "coherence", "engagement", "safety"] ) print(f"Benchmark results: {results.summary()}") ``` ## Community & Support ### Resources * **Documentation**: [docs.grpo-framework.ai](https://docs.grpo-framework.ai) * **Examples**: [github.com/grpo-framework/examples](https://github.com/grpo-framework/examples) * **Discord**: [discord.gg/grpo](https://discord.gg/grpo) * **Papers**: [arxiv.org/grpo](https://arxiv.org/grpo) ### Contributing ```bash theme={null} # Clone the repository git clone https://github.com/grpo-framework/grpo-agent-framework # Install in development mode pip install -e ".[dev]" # Run tests pytest tests/ # Submit PR git checkout -b feature/my-feature git commit -m "Add amazing feature" git push origin feature/my-feature ``` ## Next Steps Build your first agent in 10 minutes Master GRPO techniques Deploy agents at scale *** **Pro Tip**: Start with the "balanced" profile and let auto-adjustment optimize your training. Monitor reward diversity - if it's too high (>2.0), switch to "conservative" profile. The GRPO Agent Framework transforms state-of-the-art research into practical tools for building sophisticated conversational AI. Whether you're creating customer service agents, educational tutors, or task-oriented assistants, this framework provides the foundation for success. For support, contact [support@grpo-framework.ai](mailto:support@grpo-framework.ai) or join our [Discord community](https://discord.gg/grpo). # Inventory Source: https://docs.stateset.com/guides/inventory-quickstart Master inventory management with real-world scenarios - from stock tracking to demand forecasting # Inventory Management Quickstart Guide Learn how to build a sophisticated inventory management system using the StateSet API. This guide covers everything from basic stock tracking to advanced demand forecasting and multi-location inventory optimization. ## Table of Contents 1. [Introduction](#introduction) 2. [Core Concepts](#core-concepts) 3. [Setting Up Your Environment](#setting-up-your-environment) 4. [Advanced API Usage](#advanced-api-usage) 5. [Inventory Optimization Strategies](#inventory-optimization-strategies) 6. [Error Handling and Logging](#error-handling-and-logging) 7. [Webhooks and Real-time Updates](#webhooks-and-real-time-updates) 8. [Performance Optimization](#performance-optimization) 9. [Security Best Practices](#security-best-practices) 10. [Troubleshooting](#troubleshooting) ## Introduction StateSet One provides a powerful REST and GraphQL API for advanced Inventory Management. This guide will dive deep into the intricacies of the Inventory module, exploring advanced features and best practices for efficient inventory management. ### Key Objects in the Inventory Module: * Inventory Items * Packing Lists * Packing List Items * Shipments * Orders ## Core Concepts Before we dive into the implementation, let's review some core concepts and challenges in inventory management: ### Inventory Management Processes: 1. Receiving Inventory 2. Picking Inventory 3. Shipping Inventory 4. Adjusting Inventory 5. Cycle Counting 6. Inventory Forecasting ### Common Challenges: * Multi-warehouse management * Just-in-time (JIT) inventory * Demand forecasting * Stock-out prevention * Overstock mitigation * Inventory shrinkage * Supplier management ### StateSet's Solutions: * Real-time inventory tracking * Multi-location support * Advanced forecasting algorithms * Automated reorder points * Supplier performance metrics * Integration with ERP and e-commerce platforms ## Prerequisites Before you begin, ensure you have: * A StateSet account ([Sign up here](https://StateSet.com/sign-up)) * API credentials from [StateSet Cloud Console](https://cloud.StateSet.com/api-keys) * Node.js 16+ installed * Basic understanding of inventory management concepts * Access to your warehouse/fulfillment systems (if integrating) ## Setting Up Your Environment ```bash theme={null} npm install @stateset/embedded ``` ## Advanced API Usage ### Creating and Managing Inventory Items ```javascript theme={null} // Create a new Inventory Item const newItem = await client.inventoryitems.create({ upc: '123456789012', sku: 'WIDGET-001', name: 'Super Widget', description: 'A high-quality widget', category: 'Electronics', subcategory: 'Gadgets', price: 29.99, cost: 15.00, weight: 0.5, dimensions: { length: 5, width: 3, height: 2 }, reorder_point: 100, lead_time: 14 // days }); // Update an Inventory Item const updatedItem = await client.inventoryitems.update('ii_ODkRWQtx9NVsRX', { price: 34.99, reorder_point: 150 }); // Get Inventory Item details const itemDetails = await client.inventoryitems.get('ii_ODkRWQtx9NVsRX'); // List Inventory Items with pagination and filtering const inventoryList = await client.inventoryitems.list({ limit: 100, offset: 0, category: 'Electronics', in_stock: true }); ``` ### Managing Packing Lists and Items ```javascript theme={null} // Create a Packing List const packingList = await client.packinglists.create({ supplier_id: 'sup_123456', expected_delivery_date: '2024-10-01', status: 'pending' }); // Add items to the Packing List const packingListItem = await client.packinglistitems.create({ packing_list_id: packingList.id, inventory_item_id: 'ii_ODkRWQtx9NVsRX', quantity: 500 }); // Update Packing List status const updatedPackingList = await client.packinglists.update(packingList.id, { status: 'in_transit' }); // Process arrived Packing List async function processArrivedPackingList(packingListId) { const packingList = await client.packinglists.get(packingListId); const items = await client.packinglistitems.list({ packing_list_id: packingListId }); for (const item of items) { await updateInventoryCounts(item); } await client.packinglists.update(packingListId, { status: 'received' }); } async function updateInventoryCounts(packingListItem) { const inventoryItem = await client.inventoryitems.get(packingListItem.inventory_item_id); const updatedInventory = await client.inventoryitems.update(inventoryItem.id, { incoming: inventoryItem.incoming - packingListItem.quantity, available: inventoryItem.available + packingListItem.quantity, warehouse: inventoryItem.warehouse + packingListItem.quantity }); await client.packinglistitems.update(packingListItem.id, { arrived: true }); } ``` ## Inventory Optimization Strategies 1. Implement ABC Analysis: Categorize inventory items based on their value and turnover rate. ```javascript theme={null} async function performABCAnalysis() { const items = await client.inventoryitems.list({ limit: 1000 }); const totalValue = items.reduce((sum, item) => sum + item.price * item.available, 0); const categorizedItems = items.map(item => ({ ...item, value: item.price * item.available, percentageOfTotal: (item.price * item.available) / totalValue * 100 })).sort((a, b) => b.value - a.value); let cumulativePercentage = 0; const abcCategories = categorizedItems.map(item => { cumulativePercentage += item.percentageOfTotal; if (cumulativePercentage <= 80) return { ...item, category: 'A' }; if (cumulativePercentage <= 95) return { ...item, category: 'B' }; return { ...item, category: 'C' }; }); // Update items with their ABC category for (const item of abcCategories) { await client.inventoryitems.update(item.id, { abc_category: item.category }); } } ``` 2. Implement Economic Order Quantity (EOQ): Calculate the optimal order quantity to minimize total inventory costs. ```javascript theme={null} function calculateEOQ(demand, orderCost, holdingCost) { return Math.sqrt((2 * demand * orderCost) / holdingCost); } async function updateEOQForItems() { const items = await client.inventoryitems.list({ limit: 1000 }); for (const item of items) { const annualDemand = await getAnnualDemand(item.id); const orderCost = 50; // Assume $50 per order const holdingCost = item.price * 0.2; // Assume 20% of item price as annual holding cost const eoq = calculateEOQ(annualDemand, orderCost, holdingCost); await client.inventoryitems.update(item.id, { economic_order_quantity: Math.round(eoq) }); } } ``` ## Error Handling and Logging Implement robust error handling and logging to ensure smooth operation of your inventory management system. ```javascript theme={null} async function safeInventoryOperation(operation) { try { const result = await operation(); await logToExternalService({ level: 'info', message: 'Operation successful', data: result, timestamp: new Date().toISOString() }); return result; } catch (error) { await logToExternalService({ level: 'error', message: error.message, stack: error.stack, timestamp: new Date().toISOString() }); throw error; } } // Usage const newItem = await safeInventoryOperation(() => client.inventoryitems.create({ upc: '123456789012', name: 'Super Widget' }) ); ``` ## Webhooks and Real-time Updates Configure webhooks to receive real-time updates about inventory changes. 1. Set up a webhook endpoint in your application. 2. Register the webhook in the StateSet Console. 3. Process incoming webhook events: ```javascript theme={null} import express from 'express'; const app = express(); app.post('/webhook/inventory', express.json(), (req, res) => { const event = req.body; switch (event.type) { case 'inventory.updated': handleInventoryUpdate(event.data); break; case 'packing_list.received': handlePackingListReceived(event.data); break; // Handle other event types } res.sendStatus(200); }); function handleInventoryUpdate(data) { // Update local cache, notify relevant systems, etc. } function handlePackingListReceived(data) { // Trigger inventory count updates, notify warehouse staff, etc. } ``` ## Performance Optimization 1. Implement caching for frequently accessed inventory data. 2. Use bulk operations for updating multiple items. 3. Implement pagination for large data sets. ```javascript theme={null} import NodeCache from 'node-cache'; const cache = new NodeCache({ stdTTL: 600 }); // Cache for 10 minutes async function getInventoryItem(id) { const cachedItem = cache.get(id); if (cachedItem) return cachedItem; const item = await client.inventoryitems.get(id); cache.set(id, item); return item; } async function bulkUpdateInventory(updates) { const bulkOperations = updates.map(update => ({ id: update.id, changes: { quantity: update.newQuantity } })); return await client.inventoryitems.bulkUpdate(bulkOperations); } ``` ## Security Best Practices 1. Use environment variables for API keys. 2. Implement API request signing for added security. 3. Use HTTPS for all API communications. 4. Implement proper access controls and user permissions in your application. ## Real-World Inventory Scenarios ### Scenario 1: Multi-Location Inventory Management Manage inventory across multiple warehouses and retail locations: ```javascript theme={null} class MultiLocationInventoryManager extends InventoryManager { constructor(apiKey) { super(apiKey); this.locations = new Map(); } async setupLocations() { const locations = await this.client.locations.list(); locations.forEach(location => { this.locations.set(location.id, { ...location, inventory: new Map(), reorderRules: new Map() }); }); } /** * Real-time inventory allocation across locations */ async allocateInventoryOptimally(orderItems, customerLocation) { const allocations = []; for (const item of orderItems) { const allocation = await this.findBestAllocation(item, customerLocation); allocations.push(allocation); } return allocations; } async findBestAllocation(item, customerLocation) { // Get inventory levels across all locations const inventoryLevels = await this.getInventoryLevels(item.sku); // Calculate shipping costs and delivery times const locationScores = await Promise.all( Array.from(this.locations.keys()).map(async (locationId) => { const available = inventoryLevels.get(locationId) || 0; if (available < item.quantity) { return { locationId, score: 0, available: 0 }; } const shippingCost = await this.calculateShippingCost(locationId, customerLocation); const deliveryTime = await this.estimateDeliveryTime(locationId, customerLocation); const distanceScore = this.calculateDistanceScore(locationId, customerLocation); // Weighted scoring: 40% cost, 40% speed, 20% distance const score = ( (1 - shippingCost / 100) * 0.4 + (1 - deliveryTime / 7) * 0.4 + distanceScore * 0.2 ); return { locationId, score, available, shippingCost, deliveryTime }; }) ); // Select the best location const bestLocation = locationScores .filter(loc => loc.available >= item.quantity) .sort((a, b) => b.score - a.score)[0]; if (!bestLocation) { // Try split allocation return await this.attemptSplitAllocation(item, locationScores); } // Reserve inventory await this.reserveInventory(bestLocation.locationId, item.sku, item.quantity); return { sku: item.sku, quantity: item.quantity, location: bestLocation.locationId, estimated_cost: bestLocation.shippingCost, estimated_delivery: bestLocation.deliveryTime }; } async attemptSplitAllocation(item, locationScores) { const allocations = []; let remainingQuantity = item.quantity; // Sort by score and try to fulfill from multiple locations const sortedLocations = locationScores .filter(loc => loc.available > 0) .sort((a, b) => b.score - a.score); for (const location of sortedLocations) { if (remainingQuantity <= 0) break; const allocateQuantity = Math.min(remainingQuantity, location.available); await this.reserveInventory(location.locationId, item.sku, allocateQuantity); allocations.push({ sku: item.sku, quantity: allocateQuantity, location: location.locationId, estimated_cost: location.shippingCost, estimated_delivery: location.deliveryTime }); remainingQuantity -= allocateQuantity; } if (remainingQuantity > 0) { throw new Error(`Insufficient inventory for ${item.sku}. Need ${remainingQuantity} more units.`); } return allocations; } } ``` ### Scenario 2: Demand Forecasting & Auto-Replenishment Implement intelligent demand forecasting and automated reordering: ```javascript theme={null} class DemandForecastingManager { constructor(inventoryManager) { this.inventory = inventoryManager; this.historicalData = new Map(); this.forecastModels = new Map(); } /** * Machine learning-based demand forecasting */ async generateDemandForecast(sku, forecastPeriodDays = 30) { // Collect historical sales data const salesHistory = await this.getSalesHistory(sku, 365); // Last year const seasonalFactors = await this.calculateSeasonalFactors(sku); const trendAnalysis = this.analyzeTrend(salesHistory); // Apply different forecasting models const forecasts = { movingAverage: this.calculateMovingAverage(salesHistory, 30), exponentialSmoothing: this.calculateExponentialSmoothing(salesHistory), linearRegression: this.calculateLinearRegression(salesHistory), seasonal: this.calculateSeasonalForecast(salesHistory, seasonalFactors) }; // Ensemble forecast (weighted average of models) const weights = { movingAverage: 0.2, exponentialSmoothing: 0.3, linearRegression: 0.25, seasonal: 0.25 }; const ensembleForecast = Object.keys(forecasts).reduce((total, model) => { return total + (forecasts[model] * weights[model]); }, 0); // Apply trend and seasonal adjustments const adjustedForecast = ensembleForecast * trendAnalysis.factor * seasonalFactors.current; // Calculate forecast confidence interval const confidence = this.calculateConfidenceInterval(salesHistory, adjustedForecast); return { sku, forecastPeriodDays, predictedDemand: Math.round(adjustedForecast), confidence, models: forecasts, trend: trendAnalysis, seasonalFactor: seasonalFactors.current, generatedAt: new Date() }; } /** * Automated reorder point calculation */ async calculateOptimalReorderPoint(sku) { const forecast = await this.generateDemandForecast(sku, 30); const leadTime = await this.getSupplierLeadTime(sku); const serviceLevel = 0.95; // 95% service level // Lead time demand const leadTimeDemand = (forecast.predictedDemand / 30) * leadTime; // Safety stock calculation const demandVariability = this.calculateDemandVariability(sku); const leadTimeVariability = await this.getLeadTimeVariability(sku); const safetyStock = this.calculateSafetyStock( serviceLevel, demandVariability, leadTimeVariability, leadTime ); const reorderPoint = leadTimeDemand + safetyStock; // Update inventory item with new reorder point await this.inventory.client.inventory.update(sku, { reorder_point: Math.ceil(reorderPoint), safety_stock: Math.ceil(safetyStock), lead_time_days: leadTime, last_forecast_update: new Date() }); return { sku, reorderPoint: Math.ceil(reorderPoint), safetyStock: Math.ceil(safetyStock), leadTimeDemand: Math.ceil(leadTimeDemand), forecast }; } /** * Auto-replenishment workflow */ async executeAutoReplenishment() { const itemsNeedingReorder = await this.inventory.client.inventory.list({ available_quantity_lte: 'reorder_point', auto_reorder_enabled: true }); const replenishmentOrders = []; for (const item of itemsNeedingReorder) { try { const reorderCalculation = await this.calculateOptimalOrderQuantity(item.sku); // Create purchase order const purchaseOrder = await this.createPurchaseOrder({ supplier_id: item.primary_supplier_id, items: [{ sku: item.sku, quantity: reorderCalculation.orderQuantity, unit_cost: item.unit_cost }], requested_delivery_date: moment().add(item.lead_time_days, 'days').toDate(), priority: this.calculateOrderPriority(item, reorderCalculation) }); replenishmentOrders.push(purchaseOrder); // Update inventory to reflect incoming stock await this.inventory.client.inventory.update(item.sku, { incoming_quantity: item.incoming_quantity + reorderCalculation.orderQuantity, last_reorder_date: new Date(), next_reorder_check: moment().add(7, 'days').toDate() }); // Log the auto-replenishment action await this.logReplenishmentAction(item.sku, reorderCalculation, purchaseOrder); } catch (error) { await this.notifyReplenishmentFailure(item.sku, error); } } // Send summary report if (replenishmentOrders.length > 0) { await this.sendReplenishmentSummary(replenishmentOrders); } return replenishmentOrders; } calculateOptimalOrderQuantity(sku) { // Economic Order Quantity (EOQ) calculation const annualDemand = this.getAnnualDemand(sku); const orderingCost = this.getOrderingCost(sku); const holdingCost = this.getHoldingCost(sku); const eoq = Math.sqrt((2 * annualDemand * orderingCost) / holdingCost); // Consider supplier constraints const supplierConstraints = this.getSupplierConstraints(sku); const finalQuantity = this.applySupplierConstraints(eoq, supplierConstraints); return { economicOrderQuantity: Math.ceil(eoq), orderQuantity: finalQuantity, annualDemand, totalCost: this.calculateTotalCost(finalQuantity, annualDemand, orderingCost, holdingCost) }; } } ``` ### Scenario 3: Inventory Cycle Counting & Accuracy Implement automated cycle counting and inventory accuracy tracking: ```javascript theme={null} class InventoryAccuracyManager { constructor(inventoryManager) { this.inventory = inventoryManager; this.cycleCountSchedule = new Map(); } /** * Generate cycle count schedule based on ABC analysis */ async generateCycleCountSchedule() { const items = await this.inventory.client.inventory.list(); const abcClassification = await this.performABCAnalysis(items); const schedule = new Map(); // A items: Count monthly // B items: Count quarterly // C items: Count annually const frequencies = { A: 30, // days B: 90, C: 365 }; abcClassification.forEach((classification, sku) => { const frequency = frequencies[classification.category]; const nextCountDate = moment().add(frequency, 'days').toDate(); schedule.set(sku, { category: classification.category, frequency, nextCountDate, priority: classification.category === 'A' ? 'high' : classification.category === 'B' ? 'medium' : 'low' }); }); this.cycleCountSchedule = schedule; return schedule; } /** * Execute cycle count for specific items */ async executeCycleCount(skuList, countedBy) { const cycleCountResults = []; for (const sku of skuList) { try { // Get current system quantity const inventoryItem = await this.inventory.client.inventory.get(sku); const systemQuantity = inventoryItem.available_quantity; // Initiate count (in real implementation, this would interface with warehouse systems) const countResult = await this.initiatePhysicalCount(sku); const variance = countResult.physicalQuantity - systemQuantity; const variancePercentage = Math.abs(variance) / systemQuantity * 100; const result = { sku, systemQuantity, physicalQuantity: countResult.physicalQuantity, variance, variancePercentage, countDate: new Date(), countedBy, location: countResult.location, status: this.determineVarianceStatus(variancePercentage) }; // Update system if variance is within acceptable range if (variancePercentage <= 2) { // 2% tolerance await this.adjustInventoryQuantity(sku, variance, `Cycle count adjustment - ${result.status}`); result.adjusted = true; } else { // Flag for investigation await this.flagForInvestigation(sku, result); result.adjusted = false; } cycleCountResults.push(result); // Update next count date const scheduleItem = this.cycleCountSchedule.get(sku); if (scheduleItem) { scheduleItem.nextCountDate = moment().add(scheduleItem.frequency, 'days').toDate(); scheduleItem.lastCountDate = new Date(); } } catch (error) { cycleCountResults.push({ sku, error: error.message, status: 'failed' }); } } // Generate cycle count report await this.generateCycleCountReport(cycleCountResults); return cycleCountResults; } /** * Track inventory accuracy metrics */ async calculateInventoryAccuracyMetrics(period = 30) { const startDate = moment().subtract(period, 'days').toDate(); // Get all cycle counts in the period const cycleCounts = await this.inventory.client.cycleCounts.list({ date_after: startDate }); const metrics = { totalCounts: cycleCounts.length, accuratecounts: 0, totalVariance: 0, totalValue: 0, byCategory: { A: {}, B: {}, C: {} }, byLocation: new Map(), trends: [] }; cycleCounts.forEach(count => { const isAccurate = Math.abs(count.variancePercentage) <= 2; if (isAccurate) metrics.accurateCount++; metrics.totalVariance += Math.abs(count.variance); metrics.totalValue += count.systemQuantity * count.unitCost; // Track by ABC category const category = this.getItemCategory(count.sku); if (!metrics.byCategory[category].count) { metrics.byCategory[category] = { count: 0, accurate: 0 }; } metrics.byCategory[category].count++; if (isAccurate) metrics.byCategory[category].accurate++; // Track by location if (!metrics.byLocation.has(count.location)) { metrics.byLocation.set(count.location, { count: 0, accurate: 0 }); } const locationMetric = metrics.byLocation.get(count.location); locationMetric.count++; if (isAccurate) locationMetric.accurate++; }); // Calculate accuracy percentages metrics.overallAccuracy = (metrics.accurateCount / metrics.totalCounts) * 100; Object.keys(metrics.byCategory).forEach(category => { const catMetric = metrics.byCategory[category]; if (catMetric.count > 0) { catMetric.accuracy = (catMetric.accurate / catMetric.count) * 100; } }); metrics.byLocation.forEach((locationMetric, location) => { locationMetric.accuracy = (locationMetric.accurate / locationMetric.count) * 100; }); return metrics; } } ``` ### Scenario 4: Seasonal Inventory Planning Handle seasonal demand patterns and inventory planning: ```javascript theme={null} class SeasonalInventoryPlanner { constructor(inventoryManager) { this.inventory = inventoryManager; this.seasonalPatterns = new Map(); } /** * Analyze historical seasonal patterns */ async analyzeSeasonalPatterns(sku, yearsOfHistory = 3) { const salesData = await this.getSalesData(sku, yearsOfHistory); // Group by month const monthlyData = _.groupBy(salesData, sale => moment(sale.date).month()); // Calculate seasonal indices const seasonalIndices = {}; const averageMonthlySales = _.mean(Object.values(monthlyData).map(month => _.sumBy(month, 'quantity'))); Object.keys(monthlyData).forEach(month => { const monthSales = _.sumBy(monthlyData[month], 'quantity'); seasonalIndices[month] = monthSales / averageMonthlySales; }); // Identify peak seasons const peakSeasons = Object.keys(seasonalIndices) .filter(month => seasonalIndices[month] > 1.2) .map(month => ({ month: parseInt(month), monthName: moment().month(month).format('MMMM'), index: seasonalIndices[month] })); const pattern = { sku, seasonalIndices, peakSeasons, isHighlySeasonal: Math.max(...Object.values(seasonalIndices)) > 1.5, volatility: this.calculateVolatility(Object.values(seasonalIndices)) }; this.seasonalPatterns.set(sku, pattern); return pattern; } /** * Generate seasonal inventory plan */ async generateSeasonalPlan(sku, planningHorizon = 12) { const pattern = await this.analyzeSeasonalPatterns(sku); const baseForecast = await this.inventory.demandForecasting.generateDemandForecast(sku, 30); const monthlyPlan = []; const currentMonth = moment().month(); for (let i = 0; i < planningHorizon; i++) { const planMonth = (currentMonth + i) % 12; const seasonalIndex = pattern.seasonalIndices[planMonth] || 1; const adjustedForecast = baseForecast.predictedDemand * seasonalIndex; const leadTime = await this.inventory.getSupplierLeadTime(sku); // Calculate when to place order for this month's demand const orderDate = moment().add(i, 'months').subtract(leadTime, 'days'); monthlyPlan.push({ month: planMonth, monthName: moment().month(planMonth).format('MMMM'), year: moment().add(i, 'months').year(), forecastDemand: Math.round(adjustedForecast), seasonalIndex, recommendedOrderQuantity: this.calculateSeasonalOrderQuantity(sku, adjustedForecast, seasonalIndex), recommendedOrderDate: orderDate.toDate(), estimatedInventoryLevel: 0 // To be calculated }); } // Calculate running inventory levels let runningInventory = await this.getCurrentInventoryLevel(sku); monthlyPlan.forEach((month, index) => { if (moment(month.recommendedOrderDate).isBefore(moment().add(index, 'months'))) { runningInventory += month.recommendedOrderQuantity; } runningInventory -= month.forecastDemand; month.estimatedInventoryLevel = runningInventory; // Flag potential stockouts if (runningInventory < 0) { month.stockoutRisk = true; month.stockoutQuantity = Math.abs(runningInventory); } }); return { sku, planningHorizon, seasonalPattern: pattern, monthlyPlan, summary: { totalDemand: _.sumBy(monthlyPlan, 'forecastDemand'), totalOrders: _.sumBy(monthlyPlan, 'recommendedOrderQuantity'), stockoutRiskMonths: monthlyPlan.filter(m => m.stockoutRisk).length } }; } /** * Pre-season inventory buildup */ async executePreSeasonBuildup(sku, targetMonth, bufferWeeks = 4) { const seasonalPlan = await this.generateSeasonalPlan(sku); const targetMonthPlan = seasonalPlan.monthlyPlan.find(m => m.month === targetMonth); if (!targetMonthPlan) { throw new Error(`No plan found for month ${targetMonth}`); } const buildupStartDate = moment().month(targetMonth).subtract(bufferWeeks, 'weeks'); const currentInventory = await this.getCurrentInventoryLevel(sku); // Calculate required buildup quantity const peakDemand = targetMonthPlan.forecastDemand; const requiredInventory = peakDemand * 1.2; // 20% buffer const buildupRequired = Math.max(0, requiredInventory - currentInventory); if (buildupRequired > 0) { // Create advance purchase order const purchaseOrder = await this.createAdvancePurchaseOrder({ sku, quantity: buildupRequired, requestedDeliveryDate: buildupStartDate.toDate(), reason: `Pre-season buildup for ${targetMonthPlan.monthName}`, priority: 'high' }); // Update seasonal plan tracking await this.updateSeasonalPlanExecution(sku, targetMonth, { buildupOrderId: purchaseOrder.id, buildupQuantity: buildupRequired, buildupDate: new Date() }); return { buildupRequired, purchaseOrder, estimatedReadiness: buildupStartDate.toDate() }; } return { buildupRequired: 0, message: 'Sufficient inventory for peak season' }; } } ``` ## Advanced Testing Examples Create comprehensive tests for your inventory management system: ```javascript theme={null} import { describe, it, beforeEach, afterEach } from 'mocha'; import { expect } from 'chai'; import sinon from 'sinon'; describe('Inventory Management System', () => { let inventoryManager; let mockClient; beforeEach(async () => { mockClient = { inventory: { get: sinon.stub(), update: sinon.stub(), list: sinon.stub() }, locations: { list: sinon.stub() } }; inventoryManager = new MultiLocationInventoryManager('test-key'); inventoryManager.client = mockClient; }); describe('Multi-location allocation', () => { it('should allocate from closest location when sufficient inventory', async () => { // Setup test data mockClient.inventory.list.resolves([ { location_id: 'warehouse_1', sku: 'TEST-001', available_quantity: 100 }, { location_id: 'warehouse_2', sku: 'TEST-001', available_quantity: 50 } ]); const orderItem = { sku: 'TEST-001', quantity: 10 }; const customerLocation = { lat: 40.7128, lng: -74.0060 }; // NYC const allocation = await inventoryManager.findBestAllocation(orderItem, customerLocation); expect(allocation).to.have.property('sku', 'TEST-001'); expect(allocation).to.have.property('quantity', 10); expect(allocation).to.have.property('location'); }); it('should split allocation across multiple locations when needed', async () => { mockClient.inventory.list.resolves([ { location_id: 'warehouse_1', sku: 'TEST-001', available_quantity: 5 }, { location_id: 'warehouse_2', sku: 'TEST-001', available_quantity: 8 } ]); const orderItem = { sku: 'TEST-001', quantity: 10 }; const customerLocation = { lat: 40.7128, lng: -74.0060 }; const allocation = await inventoryManager.attemptSplitAllocation(orderItem, [ { locationId: 'warehouse_1', available: 5, score: 0.8 }, { locationId: 'warehouse_2', available: 8, score: 0.7 } ]); expect(allocation).to.be.an('array'); expect(allocation).to.have.length(2); expect(allocation.reduce((sum, alloc) => sum + alloc.quantity, 0)).to.equal(10); }); }); describe('Demand forecasting', () => { it('should generate accurate demand forecast using multiple models', async () => { const demandForecaster = new DemandForecastingManager(inventoryManager); // Mock historical sales data sinon.stub(demandForecaster, 'getSalesHistory').resolves([ { date: '2024-01-01', quantity: 100 }, { date: '2024-01-02', quantity: 110 }, { date: '2024-01-03', quantity: 95 } // ... more data ]); const forecast = await demandForecaster.generateDemandForecast('TEST-001', 30); expect(forecast).to.have.property('sku', 'TEST-001'); expect(forecast).to.have.property('predictedDemand'); expect(forecast.predictedDemand).to.be.a('number'); expect(forecast).to.have.property('confidence'); expect(forecast.confidence).to.be.within(0, 1); }); }); describe('Cycle counting', () => { it('should adjust inventory when variance is within tolerance', async () => { const accuracyManager = new InventoryAccuracyManager(inventoryManager); mockClient.inventory.get.resolves({ sku: 'TEST-001', available_quantity: 100 }); sinon.stub(accuracyManager, 'initiatePhysicalCount').resolves({ physicalQuantity: 98, location: 'warehouse_1' }); const results = await accuracyManager.executeCycleCount(['TEST-001'], 'test-user'); expect(results).to.have.length(1); expect(results[0]).to.have.property('adjusted', true); expect(results[0].variance).to.equal(-2); expect(results[0].variancePercentage).to.equal(2); }); }); }); // Performance testing describe('Performance Tests', () => { it('should handle bulk inventory updates efficiently', async () => { const startTime = Date.now(); const updates = Array.from({ length: 1000 }, (_, i) => ({ sku: `TEST-${i.toString().padStart(3, '0')}`, quantity: Math.floor(Math.random() * 100) })); await inventoryManager.bulkUpdateInventory(updates); const endTime = Date.now(); const duration = endTime - startTime; expect(duration).to.be.below(5000); // Should complete within 5 seconds }); }); ``` ## Best Practices Summary 1. **Real-time Tracking**: Use webhooks for immediate inventory updates 2. **Demand Forecasting**: Implement multiple forecasting models for accuracy 3. **Multi-location Optimization**: Consider shipping costs and delivery times 4. **Automated Reordering**: Set up intelligent reorder points based on demand patterns 5. **Cycle Counting**: Regular accuracy checks with ABC classification 6. **Seasonal Planning**: Prepare for demand fluctuations in advance 7. **Performance Monitoring**: Track key metrics like turnover and accuracy 8. **Error Handling**: Implement robust error recovery and alerting 9. **Testing**: Comprehensive unit and integration tests 10. **Security**: Secure API keys and implement proper access controls ## Troubleshooting * Check API rate limits and implement backoff * Verify webhook endpoints are accessible * Review inventory update timestamps * Check for concurrent update conflicts * Increase historical data collection period * Review seasonal adjustment factors * Check for data quality issues * Consider external factors (promotions, market changes) * Verify location data and shipping costs * Check inventory reservation logic * Review allocation scoring algorithm * Test with edge cases (zero inventory, single location) ## Next Steps Connect inventory with order management Advanced warehouse operations Automate supplier relationships Deep dive into inventory analytics ## Conclusion You now have a comprehensive inventory management system that handles: * ✅ Multi-location inventory optimization * ✅ Intelligent demand forecasting * ✅ Automated replenishment * ✅ Cycle counting and accuracy tracking * ✅ Seasonal planning and preparation * ✅ Real-time monitoring and alerts This system provides the foundation for scalable, efficient inventory operations that can adapt to your business needs and grow with your company. # Knowledge Base Quickstart Source: https://docs.stateset.com/guides/knowledgebase-quickstart Build and manage intelligent knowledge bases to power your AI agents with accurate, contextual information ## Introduction StateSet Knowledge Base enables your AI agents to access and utilize structured information effectively. By creating comprehensive knowledge bases, your agents can provide accurate, consistent, and contextual responses based on your organization's specific information, policies, and procedures. ## What is a Knowledge Base? A Knowledge Base in StateSet is a collection of structured documents, FAQs, policies, and procedures that AI agents can search and reference when responding to queries. It serves as the "brain" of your AI system, ensuring responses are grounded in your specific business context. ### Key Benefits Reduce hallucinations with fact-based responses Ensure uniform information across all interactions Update once, apply everywhere instantly ## Prerequisites Before creating a knowledge base: * StateSet account with API access * Documents in supported formats (TXT, PDF, MD, DOCX, JSON) * Basic understanding of vector embeddings (helpful but not required) ## Getting Started ```bash theme={null} npm install StateSet-node ``` ```javascript theme={null} const { StateSetClient } = require('StateSet-node'); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); ``` ```javascript theme={null} async function createKnowledgeBase() { try { const kb = await client.knowledgeBase.create({ name: 'Customer Support KB', description: 'Comprehensive knowledge base for customer support', settings: { embedding_model: 'text-embedding-ada-002', chunk_size: 1000, chunk_overlap: 200, metadata_fields: ['category', 'product', 'last_updated'] } }); return kb; } catch (error) { logger.error('Failed to create knowledge base:', error); throw error; } } ``` ## Adding Content ### Document Upload Upload documents to populate your knowledge base: ```javascript theme={null} async function uploadDocument(kbId, filePath, metadata = {}) { const formData = new FormData(); formData.append('file', fs.createReadStream(filePath)); formData.append('metadata', JSON.stringify({ category: metadata.category || 'general', source: metadata.source || 'manual_upload', version: metadata.version || '1.0', tags: metadata.tags || [] })); try { const document = await client.knowledgeBase.uploadDocument(kbId, formData); // Wait for processing to complete const processed = await waitForProcessing(document.id); return { success: true, documentId: document.id, chunks: processed.chunk_count }; } catch (error) { if (error.code === 'UNSUPPORTED_FORMAT') { throw new Error('Document format not supported'); } throw error; } } async function waitForProcessing(documentId, maxAttempts = 30) { for (let i = 0; i < maxAttempts; i++) { const status = await client.documents.getStatus(documentId); if (status.state === 'completed') { return status; } else if (status.state === 'failed') { throw new Error(`Processing failed: ${status.error}`); } // Wait before next check await new Promise(resolve => setTimeout(resolve, 2000)); } throw new Error('Processing timeout'); } ``` ### Structured Data Import Import structured data like FAQs or product information: ```javascript theme={null} async function importStructuredData(kbId, data) { const entries = []; // Process FAQs if (data.faqs) { for (const faq of data.faqs) { entries.push({ content: `Q: ${faq.question}\nA: ${faq.answer}`, metadata: { type: 'faq', category: faq.category, keywords: faq.keywords || [] } }); } } // Process policies if (data.policies) { for (const policy of data.policies) { entries.push({ content: policy.content, metadata: { type: 'policy', name: policy.name, effective_date: policy.effective_date, department: policy.department } }); } } // Batch import const batchSize = 100; const results = []; for (let i = 0; i < entries.length; i += batchSize) { const batch = entries.slice(i, i + batchSize); try { const result = await client.knowledgeBase.importBatch(kbId, { entries: batch, update_existing: true }); results.push(result); } catch (error) { logger.error(`Batch import failed at index ${i}:`, error); // Continue with next batch } } return { totalEntries: entries.length, successfulBatches: results.filter(r => r.success).length, failedBatches: results.filter(r => !r.success).length }; } ``` ### Web Scraping Integration Automatically import content from websites: ```javascript theme={null} async function scrapeAndImport(kbId, urls) { const scrapeJobs = []; for (const url of urls) { try { const job = await client.knowledgeBase.createScrapeJob(kbId, { url, options: { follow_links: true, max_depth: 2, include_patterns: ['/docs/', '/help/'], exclude_patterns: ['/api/', '.pdf'], extract_metadata: true } }); scrapeJobs.push(job); } catch (error) { logger.error(`Failed to create scrape job for ${url}:`, error); } } // Monitor job progress const completed = await monitorScrapeJobs(scrapeJobs); return { total: scrapeJobs.length, completed: completed.length, pages_scraped: completed.reduce((sum, job) => sum + job.pages_processed, 0) }; } ``` ## Querying the Knowledge Base ### Basic Search ```javascript theme={null} async function searchKnowledgeBase(kbId, query, options = {}) { try { const results = await client.knowledgeBase.search(kbId, { query, limit: options.limit || 5, threshold: options.threshold || 0.7, filters: options.filters || {}, include_metadata: true, rerank: true }); return results.map(result => ({ content: result.content, relevance: result.score, source: result.metadata.source, snippet: highlightRelevantText(result.content, query) })); } catch (error) { logger.error('Knowledge base search failed:', error); return []; } } function highlightRelevantText(content, query) { // Extract most relevant sentence const sentences = content.split('. '); const queryWords = query.toLowerCase().split(' '); let bestSentence = sentences[0]; let maxMatches = 0; for (const sentence of sentences) { const matches = queryWords.filter(word => sentence.toLowerCase().includes(word) ).length; if (matches > maxMatches) { maxMatches = matches; bestSentence = sentence; } } return bestSentence; } ``` ### Advanced Filtering ```javascript theme={null} async function advancedSearch(kbId, params) { const results = await client.knowledgeBase.search(kbId, { query: params.query, filters: { category: params.category, date_range: { start: params.startDate, end: params.endDate }, tags: { $in: params.tags }, metadata: { department: params.department, version: { $gte: params.minVersion } } }, sort: { field: 'last_updated', order: 'desc' }, aggregations: { categories: { terms: { field: 'category' } }, tags: { terms: { field: 'tags' } } } }); return { results: results.hits, facets: results.aggregations, total: results.total }; } ``` ## Integration with Agents ### Automatic Knowledge Base Access Configure agents to automatically query knowledge bases: ```javascript theme={null} async function createKnowledgeableAgent(kbId) { const agent = await client.agents.create({ name: 'Support Expert', instructions: `You are a helpful support agent. Always search the knowledge base before responding to ensure accuracy.`, tools: [{ type: 'knowledge_base', knowledge_base_id: kbId, settings: { always_search: true, min_confidence: 0.8, max_results: 3, cite_sources: true } }], behaviors: { on_low_confidence: 'escalate_to_human', on_no_results: 'acknowledge_limitation' } }); return agent; } ``` ### Dynamic Context Injection ```javascript theme={null} async function enhanceAgentResponse(agentId, userQuery) { // Search knowledge base first const kbResults = await searchKnowledgeBase(kbId, userQuery); // Create enhanced prompt with context const enhancedPrompt = { query: userQuery, context: kbResults.map(r => r.content).join('\n\n'), instructions: 'Use the provided context to answer accurately. Cite sources when possible.', metadata: { sources: kbResults.map(r => r.source) } }; // Get agent response with context const response = await client.agents.query(agentId, enhancedPrompt); return { answer: response.text, sources: response.metadata.sources_used, confidence: response.confidence }; } ``` ## Managing Updates ### Version Control ```javascript theme={null} async function updateDocumentWithVersioning(kbId, documentId, newContent) { // Get current version const current = await client.knowledgeBase.getDocument(kbId, documentId); // Create new version const updated = await client.knowledgeBase.updateDocument(kbId, documentId, { content: newContent, metadata: { ...current.metadata, version: incrementVersion(current.metadata.version), previous_version: current.id, updated_at: new Date().toISOString(), updated_by: 'system' }, archive_previous: true }); // Trigger reindexing await client.knowledgeBase.reindex(kbId, { document_ids: [documentId], async: true }); return updated; } ``` ### Bulk Updates ```javascript theme={null} async function bulkUpdateKnowledgeBase(kbId, updates) { const operations = updates.map(update => ({ operation: update.operation || 'upsert', document_id: update.id, content: update.content, metadata: update.metadata })); const result = await client.knowledgeBase.bulkUpdate(kbId, { operations, atomic: true, // All or nothing validate: true // Pre-validate all operations }); if (result.failed.length > 0) { logger.warn('Some updates failed:', result.failed); } return { successful: result.successful.length, failed: result.failed.length, details: result.failed }; } ``` ## Performance Optimization ### Caching Strategies ```javascript theme={null} class KnowledgeBaseCache { constructor(kbId, ttl = 3600) { this.kbId = kbId; this.ttl = ttl; this.cache = new Map(); } async search(query, options) { const cacheKey = this.getCacheKey(query, options); const cached = this.cache.get(cacheKey); if (cached && cached.expires > Date.now()) { return cached.results; } // Perform search const results = await client.knowledgeBase.search(this.kbId, { query, ...options }); // Cache results this.cache.set(cacheKey, { results, expires: Date.now() + (this.ttl * 1000) }); // Clean old entries this.cleanCache(); return results; } getCacheKey(query, options) { return `${query}_${JSON.stringify(options)}`; } cleanCache() { const now = Date.now(); for (const [key, value] of this.cache.entries()) { if (value.expires < now) { this.cache.delete(key); } } } } ``` ### Indexing Best Practices ```javascript theme={null} async function optimizeKnowledgeBase(kbId) { // Analyze current performance const stats = await client.knowledgeBase.getStats(kbId); const optimizations = []; // Check chunk size optimization if (stats.avg_chunk_size > 1500) { optimizations.push({ type: 'rechunk', params: { chunk_size: 1000, chunk_overlap: 200 } }); } // Check for duplicate content if (stats.duplicate_ratio > 0.1) { optimizations.push({ type: 'deduplicate', params: { similarity_threshold: 0.95 } }); } // Apply optimizations for (const opt of optimizations) { await client.knowledgeBase.optimize(kbId, opt); } return optimizations; } ``` ## Monitoring & Analytics ### Usage Analytics ```javascript theme={null} async function getKnowledgeBaseAnalytics(kbId, timeframe = '30d') { const analytics = await client.knowledgeBase.getAnalytics(kbId, { timeframe, metrics: [ 'search_volume', 'unique_queries', 'avg_results_per_query', 'click_through_rate', 'user_satisfaction' ], group_by: 'day' }); // Identify improvement opportunities const insights = { popularQueries: analytics.top_queries.slice(0, 10), noResultQueries: analytics.queries_with_no_results, lowSatisfactionTopics: analytics.low_satisfaction_queries, recommendations: generateRecommendations(analytics) }; return insights; } function generateRecommendations(analytics) { const recommendations = []; if (analytics.no_results_rate > 0.1) { recommendations.push({ type: 'content_gap', message: 'Add content for frequently searched topics with no results', queries: analytics.queries_with_no_results.slice(0, 5) }); } if (analytics.avg_results_quality < 0.7) { recommendations.push({ type: 'content_quality', message: 'Review and improve content quality for better relevance' }); } return recommendations; } ``` ## Troubleshooting ### Common Issues 1. **Poor Search Results** ```javascript theme={null} // Diagnose search quality issues async function diagnoseSearchQuality(kbId, testQuery) { const diagnostics = await client.knowledgeBase.diagnose(kbId, { query: testQuery, return_embeddings: true, explain_scoring: true }); return { embedding_quality: diagnostics.embedding_stats, scoring_explanation: diagnostics.score_breakdown, suggestions: diagnostics.improvement_suggestions }; } ``` 2. **Slow Query Performance** * Reduce chunk size for faster processing * Implement caching for frequent queries * Use filters to narrow search scope 3. **High Memory Usage** * Limit concurrent processing jobs * Use streaming for large documents * Implement pagination for bulk operations ## Security & Access Control ### Implement Access Controls ```javascript theme={null} async function setupAccessControl(kbId) { await client.knowledgeBase.updateSettings(kbId, { access_control: { enabled: true, default_permission: 'read', roles: { admin: ['read', 'write', 'delete', 'manage'], editor: ['read', 'write'], viewer: ['read'] } }, audit_logging: { enabled: true, log_searches: true, log_updates: true } }); } ``` ## Next Steps Learn about Retrieval Augmented Generation Share knowledge across agent teams # Manufacturing Source: https://docs.stateset.com/guides/manufacturing-quickstart Leverage the StateSet API to streamline and manage your manufacturing operations effectively. # Manufacturing and Production API Quickstart Guide Welcome to the StateSet Manufacturing Guide. This document provides developers and technical users with instructions for utilizing the StateSet API to manage core manufacturing processes. Learn how to configure your environment, model production data (Products, BOMs), plan and execute production runs (Work Orders, Manufacturing Orders), and manage associated inventory movements. Following this guide will enable you to integrate StateSet into your manufacturing workflows, enhancing operational efficiency, data accuracy, and cost control. ## Table of Contents 1. [Introduction](#introduction) 2. [Prerequisites](#prerequisites) 3. [Getting Started: SDK Setup](#getting-started-sdk-setup) 4. [Core Manufacturing Concepts](#core-manufacturing-concepts) 5. [API Workflow: End-to-End Manufacturing Process](#api-workflow-end-to-end-manufacturing-process) * [Step 1: Defining Products and Bills of Materials (BOMs)](#step-1-defining-products-and-bills-of-materials-boms) * [Step 2: Planning Production (Work Orders)](#step-2-planning-production-work-orders) * [Step 3: Executing Production (Manufacturing Orders & Activities)](#step-3-executing-production-manufacturing-orders--activities) * [Step 4: Managing Inventory Movements (Picks, Consumption, Receipts)](#step-4-managing-inventory-movements-picks-consumption-receipts) * [Step 5: Maintaining Inventory Accuracy (Cycle Counts)](#step-5-maintaining-inventory-accuracy-cycle-counts) 6. [Optimizing Manufacturing Processes with API Data](#optimizing-manufacturing-processes-with-api-data) 7. [Real-Time Monitoring and System Integration](#real-time-monitoring-and-system-integration) 8. [Error Handling and Logging Strategies](#error-handling-and-logging-strategies) 9. [Troubleshooting Common Manufacturing API Issues](#troubleshooting-common-manufacturing-api-issues) 10. [Support Resources](#support-resources) 11. [Conclusion](#conclusion) *** ## Introduction StateSet offers a comprehensive API designed to manage the complexities of modern manufacturing operations. This guide focuses on the practical application of the API for common workflows, including defining manufacturable items, planning production schedules, tracking execution progress, and maintaining accurate inventory records. By leveraging the StateSet API, you can automate processes, improve data visibility, and enable data-driven optimization. **Key Learning Objectives:** * Configure the StateSet Node.js SDK for secure API interaction. * Understand fundamental manufacturing entities within StateSet (Products, BOMs, WOs, MOs, Inventory). * Utilize API endpoints to create, update, and manage manufacturing data throughout the production lifecycle. * Identify opportunities to use API data for process optimization (e.g., OEE, waste analysis). * Implement robust error handling and logging for reliable integration. *** ## Prerequisites * Node.js (version 16 or higher recommended). * An active StateSet account and a generated API key with appropriate permissions for manufacturing resources. * Basic understanding of JavaScript (`async`/`await`), REST APIs, and JSON data structures. * Familiarity with core manufacturing concepts (BOMs, Work Orders, Inventory Management). *** ## Getting Started: SDK Setup Ensure your development environment is configured to interact with the StateSet API. ### 1. Install the StateSet Node.js SDK Add the official SDK package to your Node.js project using npm or yarn. ```bash theme={null} npm install @stateset/embedded ``` *** ## Core Manufacturing Concepts Understanding these entities within the StateSet context is crucial for effective API usage. ```mermaid theme={null} graph TD subgraph Definition A[Product
(SKU, Name)] --> B(Bill of Materials (BOM)
(Components, Quantities)); end subgraph Planning B --> C{Work Order (WO)
(Product ID, Target Qty, Due Date)}; end subgraph Execution C --> D{Manufacturing Order (MO)
(Tracks actual run, Links to WO)}; D --> E[Picks
(Requests specific inventory)]; D --> F[Machine Usage
(Runtime, Cycles)]; D --> G[Labor Tracking
(Time spent)]; D --> H[Waste & Scrap
(Material loss)]; end subgraph Inventory & Quality I[Inventory
(Part Number, Qty, Location, Cost Layer)]; E --> I; H --> I; J[Finished Goods Receipt
(Output from MO)] --> I; K[Cycle Counts
(Verify Inventory Accuracy)] --> I; end subgraph Supporting Processes L[Kitting
(Pre-assemble components)] --> E; M[Maintenance
(Machine upkeep)] --> F; end C --> J; % WO completion leads to FG Receipt ``` * **Product:** Represents a distinct item that can be manufactured or sold (e.g., finished good, subassembly). Identified by attributes like `sku`, `name`. * **Bill of Materials (BOM):** Defines the "recipe" for manufacturing a specific `Product`. Lists required `components` (other Products or raw materials identified by `item_id`) and their `quantity` and `unit` of measure. Often version-controlled. * **Work Order (WO):** An authorization to produce a specific `quantity` of a `Product` by a certain date. References the relevant `BOM` and specifies production details like `priority` and target `site`. Acts as the high-level production plan. * **Manufacturing Order (MO):** Represents the execution of a `Work Order` or a portion of it. Tracks the actual production run, including start/end times, `status` (e.g., `planned`, `in_progress`, `completed`), resources used, and materials consumed. It's the operational record of production. Often linked back to the source `Work Order` via `work_order_id`. * **Picks:** The operational task of retrieving specific `inventory_item_id`s (representing actual stock) from storage locations to fulfill the material requirements of an `MO`. Tracks requested vs. picked quantities. * **Inventory (`inventory_item_id` vs `item_id`/`part_number`):** * `item_id` or `part_number`: Represents the *type* of item (e.g., 'RESISTOR-10K'). Corresponds to a `Product` or raw material definition. * `inventory_item_id` (or similar concept): Represents a *specific batch/lot/instance* of that item in stock, often with its own location, quantity, and cost layer. Picks operate on these specific inventory units. Inventory movements update the quantity of specific `inventory_item_id`s. * **Cycle Counts:** Periodic verification of physical inventory quantities against system records (`inventory` resource) to ensure data accuracy. * **Waste & Scrap:** Records materials consumed during production that did not become part of the finished good, enabling analysis of production efficiency. * **Machines:** Represents production equipment. Tracking usage (`logRuntime`) and `Maintenance` is vital for OEE and reliability. * **Kitting:** Process of pre-assembling components into a single kit (`item_id`) for easier consumption during final assembly. Managed via BOMs and Inventory. *** ## API Workflow: End-to-End Manufacturing Process This section demonstrates using the StateSet API to manage a typical manufacturing flow. ### Step 1: Defining Products and Bills of Materials (BOMs) Establish the foundation by defining what you manufacture and how. #### A. Create a Product Define the item to be manufactured. ```javascript theme={null} /** * Creates a new Product definition in StateSet. * @param {object} productData - Attributes for the new product. * @returns {Promise} The newly created Product object. */ async function createProduct(productData) { try { logger.info('Creating product:', productData.sku); const newProduct = await client.product.create({ name: productData.name, description: productData.description, sku: productData.sku, unit_of_measure: productData.unit_of_measure, type: productData.type, category: productData.category, sub_category: productData.sub_category, brand: productData.brand, model_number: productData.model_number, serial_number: productData.serial_number, weight: productData.weight, weight_unit: productData.weight_unit, dimensions: productData.dimensions, dimensions_unit: productData.dimensions_unit, color: productData.color, material: productData.material }); logger.info(`Product created successfully: ID=${newProduct.id}, SKU=${newProduct.sku}`); return newProduct; } catch (error) { logger.error(`Error creating product ${productData.sku}:`, error.response ? error.response.data : error.message); throw error; // Re-throw for upstream handling } } // Example Usage: const widgetProductData = { name: 'Standard Widget', description: 'A reliable widget for general use.', sku: 'SW-100', unit_of_measure: 'pcs', type: 'manufactured', category: 'Electronics', sub_category: 'Widgets', brand: 'Acme', model_number: 'SW-100', serial_number: '1234567890', }; const product = await createProduct(widgetProductData); ``` *Purpose:* Records the master data for the manufacturable item. The `sku` or `id` will be used to link BOMs and Orders. #### B. Create a Bill of Materials (BOM) Define the components required to make the Product. ```javascript theme={null} /** * Creates a Bill of Materials (BOM) for a specific Product. * @param {object} bomData - Attributes for the new BOM. * @param {string} bomData.productId - ID of the Product this BOM is for. * @param {Array} bomData.components - Array of { item_id, quantity, unit }. * @returns {Promise} The newly created BOM object. */ async function createBOM(bomData) { try { logger.info(`Creating BOM for Product ID: ${bomData.productId}`); const newBOM = await client.billofmaterials.create({ name: bomData.name || `BOM for Product ${bomData.productId}`, description: bomData.description, product_id: bomData.productId, version: bomData.version || '1.0', // Implement versioning as needed components: bomData.components, is_active: bomData.is_active || true, effective_date: bomData.effective_date || new Date().toISOString(), expiration_date: bomData.expiration_date || null, is_active: bomData.is_active || true, // Add other fields: isActive, effective_date, etc. }); logger.info(`BOM created successfully: ID=${newBOM.id}, Name=${newBOM.name}`); return newBOM; } catch (error) { logger.error(`Error creating BOM for Product ID ${bomData.productId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage (using 'product' from previous step): const widgetBOMData = { productId: product.id, name: 'Standard Widget BOM v1.0', description: 'Components for SW-100', version: '1.0', components: [ { item_id: 'COMP-A', quantity: 2, unit: 'pcs' }, // Assumes COMP-A exists as a Product/Item { item_id: 'COMP-B', quantity: 50, unit: 'g' } // Assumes COMP-B exists as a Product/Item ] }; const bom = await createBOM(widgetBOMData); ``` *Purpose:* Defines the structure and material requirements for manufacturing. The `item_id` for components refers to other `Product` SKUs or raw material identifiers. ### Step 2: Planning Production (Work Orders) Authorize and schedule production runs. #### A. Create a Work Order Generate an order to produce a specific quantity of a Product. ```javascript theme={null} /** * Creates a Work Order to plan the production of a Product. * @param {object} woData - Attributes for the new Work Order. * @param {string} woData.bomId - ID of the BOM to use for this production run. * @param {string} woData.productId - ID of the product being manufactured. * @param {number} woData.quantity - Target quantity to produce. * @returns {Promise} The newly created Work Order object. */ async function createWorkOrder(woData) { try { logger.info(`Creating Work Order for Product ID: ${woData.productId}, Qty: ${woData.quantity}`); const newWorkOrder = await client.workorder.create({ type: woData.type || 'production', // 'production', 'rework', etc. status: woData.status || 'planned', // 'planned', 'released', 'in_progress', 'completed' priority: woData.priority || 'medium', number: woData.number || `WO-${Date.now()}`, // Ensure uniqueness site: woData.site, // Manufacturing location identifier product_id: woData.productId, // What is being made quantity: woData.quantity, // How many due_date: woData.dueDate, // ISO 8601 string bill_of_material_id: woData.bomId, // Which recipe to use is_active: woData.is_active || true, effective_date: woData.effective_date || new Date().toISOString(), expiration_date: woData.expiration_date || null, work_order_line_items: woData.work_order_line_items || [] }); logger.info(`Work Order created successfully: ID=${newWorkOrder.id}, Number=${newWorkOrder.number}`); return newWorkOrder; } catch (error) { logger.error(`Error creating Work Order for Product ID ${woData.productId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage (using 'product' and 'bom' from previous steps): const widgetWOData = { productId: product.id, bomId: bom.id, quantity: 500, dueDate: new Date(Date.now() + 14 * 86400000).toISOString(), // Due in 14 days site: 'FACTORY-A', number: 'WO-SW100-500' }; const workOrder = await createWorkOrder(widgetWOData); ``` *Purpose:* Schedules production, reserves capacity (implicitly), and provides the basis for execution tracking via Manufacturing Orders. ### Step 3: Executing Production (Manufacturing Orders & Activities) Track the actual manufacturing process based on the planned Work Order. #### A. Create a Manufacturing Order Initiate the tracking for the actual production run, linking it to the Work Order. ```javascript theme={null} /** * Creates a Manufacturing Order to track the execution of a Work Order. * @param {object} moData - Attributes for the new Manufacturing Order. * @param {string} moData.workOrderId - ID of the parent Work Order. * @returns {Promise} The newly created Manufacturing Order object. */ async function createManufacturingOrder(moData) { try { logger.info(`Creating Manufacturing Order linked to WO ID: ${moData.workOrderId}`); // Often MO details are derived from the WO initially const parentWO = await client.workorder.get(moData.workOrderId); // Fetch WO details if needed const newMO = await client.manufacturingorder.create({ type: moData.type || parentWO.type || 'production', status: moData.status || 'released', // Often starts as 'released' or 'in_progress' priority: moData.priority || parentWO.priority || 'medium', number: moData.number || `MO-${parentWO.number || Date.now()}`, // Ensure uniqueness site: moData.site || parentWO.site, work_order_id: moData.workOrderId, product_id: parentWO.product_id, // Inherited from WO quantity_planned: parentWO.quantity, // Inherited from WO manufacturing_order_line_items: moData.manufacturing_order_line_items || [], is_active: moData.is_active || true, effective_date: moData.effective_date || new Date().toISOString(), expiration_date: moData.expiration_date || null, actual_start_date: new Date().toISOString(), // Can set start time immediately }); logger.info(`Manufacturing Order created successfully: ID=${newMO.id}, Number=${newMO.number}`); return newMO; } catch (error) { logger.error(`Error creating Manufacturing Order for WO ID ${moData.workOrderId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage (using 'workOrder' from previous step): const widgetMOData = { workOrderId: workOrder.id, status: 'released' // Ready to start picking/production }; const manufacturingOrder = await createManufacturingOrder(widgetMOData); ``` *Purpose:* Creates the operational record for tracking progress, resource consumption, and output related to the planned Work Order. #### B. Track Production Activities (Machine Time, Waste) Record resource usage and material losses during the MO execution. ```javascript theme={null} /** * Logs runtime for a specific machine against a Manufacturing Order. * @param {string} machineId - The ID of the machine used. * @param {string} moId - The ID of the Manufacturing Order. * @param {object} runtimeData - { start_time, end_time, cycle_count (optional) }. * @returns {Promise} The created machine runtime log entry. */ async function logMachineRuntime(machineId, moId, runtimeData) { try { logger.info(`Logging runtime for Machine ID: ${machineId} on MO ID: ${moId}`); // Assuming a dedicated endpoint exists like 'client.machines.logRuntime' or similar // This is a hypothetical structure; adapt to the actual SDK method. const runtimeLog = await client.machines.logRuntime(machineId, { // Adapt SDK call manufacturing_order_id: moId, start_time: runtimeData.start_time, // ISO 8601 string end_time: runtimeData.end_time, // ISO 8601 string is_active: runtimeData.is_active || true, }); logger.info(`Machine runtime logged successfully: Log ID=${runtimeLog.id}`); return runtimeLog; } catch (error) { logger.error(`Error logging runtime for Machine ${machineId} on MO ${moId}:`, error.response ? error.response.data : error.message); throw error; } } /** * Records waste or scrap generated during a Manufacturing Order. * @param {string} moId - The ID of the Manufacturing Order. * @param {object} wasteData - { item_id, quantity, unit, reason, type ('waste'/'scrap') }. * @returns {Promise} The created waste/scrap record. */ async function recordWaste(moId, wasteData) { try { logger.info(`Recording ${wasteData.type} for MO ID: ${moId}, Item: ${wasteData.item_id}, Qty: ${wasteData.quantity}`); // Assuming an endpoint like 'client.wasteAndScrap.create' exists const wasteRecord = await client.wasteAndScrap.create({ // Adapt SDK call manufacturing_order_id: moId, item_id: wasteData.item_id, // The component part number that was wasted quantity: wasteData.quantity, unit: wasteData.unit, type: wasteData.type, // 'waste', 'scrap' reason: wasteData.reason, // Optional fields: recorded_by, timestamp, location_id }); logger.info(`${wasteData.type} recorded successfully: Record ID=${wasteRecord.id}`); // IMPORTANT: This record typically needs a corresponding INVENTORY adjustment // to decrease the quantity of the wasted item_id. // await adjustInventoryForWaste(wasteData.item_id, wasteData.quantity, wasteData.unit, moId); return wasteRecord; } catch (error) { logger.error(`Error recording ${wasteData.type} for MO ID ${moId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage: const startTime = new Date(); const endTime = new Date(startTime.getTime() + 2 * 3600000); // 2 hours later await logMachineRuntime('MACHINE-01', manufacturingOrder.id, { start_time: startTime.toISOString(), end_time: endTime.toISOString() }); await recordWaste(manufacturingOrder.id, { item_id: 'COMP-A', // Wasted component quantity: 5, unit: 'pcs', type: 'scrap', reason: 'Damaged during handling' }); ``` *Purpose:* Captures critical operational data for performance analysis (OEE, yield) and cost tracking. Note the importance of linking waste records to actual inventory adjustments. #### C. Complete the Manufacturing Order Mark the production run as finished and record the output quantity. ```javascript theme={null} /** * Updates the status of a Manufacturing Order, typically to 'completed'. * Records the actual quantity produced. * @param {string} moId - The ID of the Manufacturing Order to complete. * @param {number} quantityCompleted - The actual quantity of the Product produced. * @returns {Promise} The updated Manufacturing Order object. */ async function completeManufacturingOrder(moId, quantityCompleted) { try { logger.info(`Completing Manufacturing Order ID: ${moId}, Qty Produced: ${quantityCompleted}`); const updatedMO = await client.manufacturingorder.update(moId, { status: 'completed', actual_end_date: new Date().toISOString(), quantity_completed: quantityCompleted, // Potentially update line items with actual consumption if tracked there }); logger.info(`Manufacturing Order ${moId} completed successfully.`); // IMPORTANT: MO completion usually triggers Finished Goods Inventory receipt. // await receiveFinishedGoods(updatedMO.product_id, quantityCompleted, moId); return updatedMO; } catch (error) { logger.error(`Error completing Manufacturing Order ${moId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage: const actualQuantityProduced = 495; // Perhaps 5 units were scrapped const completedMO = await completeManufacturingOrder(manufacturingOrder.id, actualQuantityProduced); ``` *Purpose:* Finalizes the production run record, capturing the yield. This event typically triggers the creation of Finished Goods inventory. ### Step 4: Managing Inventory Movements (Picks, Consumption, Receipts) Accurately track materials moving into, through, and out of production. #### A. Create and Complete Picks Manage the process of retrieving components from inventory for the MO. ```javascript theme={null} /** * Creates a Pick task for required inventory items for an MO. * @param {string} moId - The Manufacturing Order needing materials. * @param {Array} itemsToPick - Array of { inventory_item_id, quantity, unit }. * @returns {Promise} The created Pick task object. */ async function createPickTask(moId, itemsToPick) { try { logger.info(`Creating Pick Task for MO ID: ${moId}`); // Assumes an endpoint like 'client.picks.create' exists const newPick = await client.picks.create({ // Adapt SDK call manufacturing_order_id: moId, status: 'pending', // 'pending', 'in_progress', 'completed', 'cancelled' // Optional: picker_id, requested_date, priority items: itemsToPick.map(item => ({ inventory_item_id: item.inventory_item_id, // Specific stock ID quantity_requested: item.quantity, unit: item.unit })) }); logger.info(`Pick Task created successfully: ID=${newPick.id}`); return newPick; } catch (error) { logger.error(`Error creating Pick Task for MO ID ${moId}:`, error.response ? error.response.data : error.message); throw error; } } /** * Marks a Pick task as completed, recording actual picked quantities. * @param {string} pickId - The ID of the Pick task to complete. * @param {Array} itemsPicked - Array of { inventory_item_id, quantity_picked }. * @returns {Promise} The updated Pick task object. */ async function completePickTask(pickId, itemsPicked) { try { logger.info(`Completing Pick Task ID: ${pickId}`); // Assumes an endpoint like 'client.picks.complete' or 'client.picks.update' exists const completedPick = await client.picks.update(pickId, { // Adapt SDK call status: 'completed', completed_date: new Date().toISOString(), // Update line items with actual picked quantities items: itemsPicked.map(item => ({ inventory_item_id: item.inventory_item_id, quantity_picked: item.quantity_picked })) }); logger.info(`Pick Task ${pickId} completed successfully.`); for (const item of itemsPicked) { await adjustInventoryForPick(item.inventory_item_id, item.quantity_picked); } return completedPick; } catch (error) { logger.error(`Error completing Pick Task ${pickId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage: const pickItems = [ { inventory_item_id: 'INV-CA-001', quantity: 2, unit: 'pcs' }, { inventory_item_id: 'INV-CB-005', quantity: 50, unit: 'g' } ]; const pickTask = await createPickTask(manufacturingOrder.id, pickItems); // Later, when picked: Assume only 48g of COMP-B was available/picked const pickedQuantities = [ { inventory_item_id: 'INV-CA-001', quantity_picked: 2 }, { inventory_item_id: 'INV-CB-005', quantity_picked: 48 } ]; const completedPick = await completePickTask(pickTask.id, pickedQuantities); ``` *Purpose:* Manages the physical movement of materials from storage to the production floor. Crucially links to inventory deduction. The distinction between `inventory_item_id` (specific stock) and `item_id` (general part number) is vital here. #### B. Record Finished Goods Receipt (Implied/Separate Step) Increase inventory for the product manufactured upon MO completion. This might be an automatic side-effect of `completeManufacturingOrder` or require a separate inventory transaction. ```javascript theme={null} /** * Creates an inventory movement record for receiving finished goods. * Often triggered after MO completion. * @param {string} productId - The Product ID (SKU) of the item produced. * @param {number} quantity - The quantity produced and received into stock. * @param {string} sourceMoId - The Manufacturing Order ID that produced these goods. * @returns {Promise} The created inventory movement record. */ async function receiveFinishedGoods(productId, quantity, sourceMoId) { try { logger.info(`Receiving Finished Goods: Product ID=${productId}, Qty=${quantity} from MO ID=${sourceMoId}`); // Assumes a general inventory adjustment/movement endpoint const inventoryReceipt = await client.inventory.create({ // Adapt SDK call part_number: productId, // Or item_id quantity: quantity, // Positive quantity for receipt type: 'FG_RECEIPT', // Categorize the movement type source_document_id: sourceMoId, source_document_type: 'ManufacturingOrder', // Important: Determine the UNIT COST of these finished goods // This involves summing material, labor, overhead costs from the MO. // unit_cost: calculateFinishedGoodsCost(sourceMoId), // Requires separate calculation location_id: 'FG-WAREHOUSE', // Target location // Add lot/batch number if applicable }); logger.info(`Finished Goods received into inventory: Movement ID=${inventoryReceipt.id}`); return inventoryReceipt; } catch (error) { logger.error(`Error receiving Finished Goods for Product ${productId} from MO ${sourceMoId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage (called after completeManufacturingOrder): await receiveFinishedGoods(completedMO.product_id, completedMO.quantity_completed, completedMO.id); ``` *Purpose:* Updates inventory levels to reflect newly manufactured stock, making it available for sale or further processes. Calculating the correct `unit_cost` for these finished goods is a critical accounting step often involving cost roll-ups from the MO. ### Step 5: Maintaining Inventory Accuracy (Cycle Counts) Ensure inventory data remains accurate through regular checks. #### A. Schedule and Record Cycle Counts Initiate and record the results of periodic inventory counts. ```javascript theme={null} /** * Schedules a Cycle Count task for specific items or locations. * @param {object} countData - { scheduled_date, location_id, item_ids (optional) }. * @returns {Promise} The created Cycle Count task object. */ async function scheduleCycleCount(countData) { try { logger.info(`Scheduling Cycle Count for Location: ${countData.location_id}`); // Assumes an endpoint like 'client.cycleCounts.create' exists const newCycleCount = await client.cycleCounts.create({ // Adapt SDK call scheduled_date: countData.scheduled_date, // ISO 8601 string location_id: countData.location_id, // ID of the warehouse area being counted status: 'scheduled', // 'scheduled', 'in_progress', 'completed' // Optionally specify items or count everything in the location items_to_count: countData.item_ids || [], // Array of part_numbers/item_ids }); logger.info(`Cycle Count scheduled successfully: ID=${newCycleCount.id}`); return newCycleCount; } catch (error) { logger.error(`Error scheduling Cycle Count for Location ${countData.location_id}:`, error.response ? error.response.data : error.message); throw error; } } /** * Records the results of a completed Cycle Count, highlighting discrepancies. * @param {string} countId - The ID of the Cycle Count task. * @param {Array} countResults - Array of { inventory_item_id, counted_quantity }. * @returns {Promise} The updated Cycle Count task object. */ async function recordCycleCountResults(countId, countResults) { try { logger.info(`Recording results for Cycle Count ID: ${countId}`); // Assumes an endpoint like 'client.cycleCounts.complete' or 'update' const completedCount = await client.cycleCounts.update(countId, { // Adapt SDK call status: 'completed', completion_date: new Date().toISOString(), results: countResults.map(result => ({ inventory_item_id: result.inventory_item_id, // Specific stock ID counted counted_quantity: result.counted_quantity, // The system should calculate discrepancy based on current inventory qty system_quantity: fetchSystemQuantity(result.inventory_item_id), discrepancy: counted_quantity - system_quantity })) }); logger.info(`Cycle Count ${countId} results recorded.`); // IMPORTANT: Discrepancies found during cycle counts require investigation // and subsequent INVENTORY ADJUSTMENTS to correct system quantities. processCycleCountDiscrepancies(completedCount.results); return completedCount; } catch (error) { logger.error(`Error recording results for Cycle Count ${countId}:`, error.response ? error.response.data : error.message); throw error; } } // Example Usage: const tomorrow = new Date(Date.now() + 86400000); const countTask = await scheduleCycleCount({ scheduled_date: tomorrow.toISOString(), location_id: 'BIN-A1', item_ids: ['COMP-A', 'COMP-B'] // Count only these items in this location }); // After counting: const results = [ { inventory_item_id: 'INV-CA-001', counted_quantity: 98 }, // System thought 100? { inventory_item_id: 'INV-CB-005', counted_quantity: 50 } // Matches system? ]; await recordCycleCountResults(countTask.id, results); ``` *Purpose:* Provides a mechanism for systematic inventory verification, identifying discrepancies that require adjustments to maintain accurate stock levels crucial for planning and fulfillment. *** ## Optimizing Manufacturing Processes with API Data The data captured via the StateSet API is invaluable for process improvement. Analyze this data to: * **Calculate Overall Equipment Effectiveness (OEE):** Use machine runtime logs (`logMachineRuntime`), MO planned vs. actual times, and MO `quantity_completed` vs. `quantity_planned` (considering scrap) to measure Availability, Performance, and Quality. * *Availability* = Actual Runtime / Planned Production Time * *Performance* = (Ideal Cycle Time \* Total Pieces Produced) / Actual Runtime * *Quality* = Good Pieces (Completed Qty - Scrap Qty) / Total Pieces Produced * *OEE* = Availability \* Performance \* Quality * **Analyze Waste and Scrap:** Aggregate `wasteAndScrap` records by reason code, item, machine, or operator to identify root causes of material loss and target areas for process improvement or training. * **Optimize Production Scheduling:** Analyze historical MO completion times, lead times derived from WO/MO dates, and resource (machine/labor) utilization data to improve future scheduling accuracy and resource allocation. * **Implement Predictive Maintenance:** Analyze machine runtime hours, cycle counts, and potentially sensor data (if integrated) to predict maintenance needs before failures occur, reducing unplanned downtime. * **Refine BOM Accuracy:** Compare actual component consumption (derived from completed Picks and adjusted for scrap) against theoretical BOM quantities to identify inaccuracies in the Bill of Materials. ```javascript theme={null} // Conceptual OEE Calculation Snippet (Requires fetching related data) async function calculateOEEForMO(moId) { try { const mo = await client.manufacturingorder.get(moId); if (!mo || mo.status !== 'completed') { throw new Error(`Manufacturing Order ${moId} not found or not completed.`); } // --- Data Gathering (Requires specific queries/logic) --- // 1. Planned Time: Derive from MO schedule, associated WO, or standard process times. const plannedProductionTimeHrs = 8; // Placeholder // 2. Actual Runtime: Sum machine runtime logs linked to this MO. const machineLogs = await client.machines.listLogs({ manufacturing_order_id: moId }); const actualRuntimeHrs = machineLogs.reduce((sum, log) => sum + calculateDurationHrs(log.start_time, log.end_time), 0); // 3. Ideal Cycle Time: From Product/Process definition (units per hour). const idealCycleTimeHrsPerUnit = 0.01; // Placeholder (e.g., 100 units/hr = 0.01 hrs/unit) // 4. Total Pieces Produced: Sum of good pieces and scrap for this MO. const scrapRecords = await client.wasteAndScrap.list({ manufacturing_order_id: moId }); const totalScrapQty = scrapRecords.reduce((sum, record) => sum + record.quantity, 0); const goodPieces = mo.quantity_completed; const totalPieces = goodPieces + totalScrapQty; if (plannedProductionTimeHrs <= 0 || actualRuntimeHrs <= 0 || totalPieces <= 0) { console.warn(`Cannot calculate OEE for MO ${moId} due to zero values in time or quantity.`); return null; } // --- Calculation --- const availability = actualRuntimeHrs / plannedProductionTimeHrs; const performance = (idealCycleTimeHrsPerUnit * totalPieces) / actualRuntimeHrs; const quality = goodPieces / totalPieces; const oee = availability * performance * quality; logger.info(`OEE Calculation for MO ${moId}:`); logger.info(` Availability: ${(availability * 100);.toFixed(1)}%`); logger.info(` Performance: ${(performance * 100);.toFixed(1)}%`); logger.info(` Quality: ${(quality * 100);.toFixed(1)}%`); logger.info(` OEE: ${(oee * 100);.toFixed(1)}%`); return { availability, performance, quality, oee }; } catch (error) { logger.error(`Error calculating OEE for MO ${moId}:`, error.message); return null; } } // Placeholder helper function function calculateDurationHrs(startISO, endISO) { return (new Date(endISO) - new Date(startISO)) / (1000 * 60 * 60); } // Example Usage: await calculateOEEForMO(completedMO.id); ``` *Note:* The OEE calculation requires careful data gathering from multiple related records. The example provides the structure but relies on placeholders for data fetching logic. *** ## Real-Time Monitoring and System Integration Leverage real-time data flow for operational visibility and system synchronization. * **Webhooks:** Configure StateSet Webhooks to receive real-time notifications for critical manufacturing events. Examples: * `manufacturingorder.completed`: Trigger downstream processes like FG inventory receipt, shipping notifications, or ERP updates. * `inventory.quantity.low`: Alert purchasing or planning when component stock drops below a threshold. * `pick.completed`: Update shop floor dashboards or trigger material movement confirmations. * `machine.status.changed`: Monitor equipment state changes for immediate visibility. * **Dashboarding:** Feed API data (MO status, queue lengths, OEE metrics, waste levels) into Business Intelligence (BI) tools or custom dashboards for real-time operational monitoring by supervisors and managers. * **ERP/MES Integration:** Synchronize StateSet data (inventory levels, WO/MO status, costs) with your primary ERP or Manufacturing Execution System (MES) to maintain data consistency across platforms. Use the API for bi-directional updates where appropriate. *** ## Error Handling and Logging Strategies Implement robust error handling and logging for reliable manufacturing system integration. * **Specific API Error Handling:** Catch errors from SDK calls. Inspect `error.response.status` (HTTP status code) and `error.response.data` (API error details) to determine the cause (e.g., 400 Bad Request, 401 Unauthorized, 404 Not Found, 429 Rate Limited, 5xx Server Error). * **Input Validation:** Validate data *before* making API calls to prevent unnecessary errors (check required fields, data types, formats). * **Retry Logic:** Implement exponential backoff strategies for transient errors (e.g., 429, 503). Do *not* retry client errors (4xx) without correcting the request. * **Idempotency:** For critical operations like creating orders or inventory movements, utilize idempotency keys if supported by the API, or implement application-level checks to prevent duplicate transactions. * **Centralized Logging:** Log detailed information for both successful operations and errors (timestamp, operation name, input identifiers, outcome, error message, stack trace, API response details) to a dedicated logging service (e.g., Datadog, Splunk, ELK Stack) for monitoring, alerting, and debugging. * **Transactionality (Application Level):** For multi-step workflows (e.g., completing MO -> receiving FG inventory), consider application-level patterns (like sagas or compensating transactions) to handle failures gracefully if the API doesn't support atomic transactions across multiple calls. ```javascript theme={null} // Enhanced Error Handling Wrapper Example (from previous guide, still applicable) async function safeApiOperation(operation, description) { try { logger.info(`Attempting operation: ${description}`); const result = await operation(); // Log success with key identifiers if needed // logger.info(`Operation successful: ${description}`, { resultId: result?.id }); return result; } catch (error) { const timestamp = new Date().toISOString(); let errorDetails = { message: error.message, stack: error.stack?.substring(0, 1000), // Limit stack trace length description: description, timestamp: timestamp }; if (error.response) { errorDetails.apiStatus = error.response.status; errorDetails.apiResponse = error.response.data; } else { errorDetails.type = 'Application Error'; } logger.error(`Error during operation: ${description}`, errorDetails); // Log structured error to external system logger.error('Manufacturing Process Error', errorDetails); // Optional: Notify team on critical errors // if (errorDetails.apiStatus >= 500 || !errorDetails.apiStatus) { // notifyTeam(`Critical error in ${description}: ${error.message}`); // } // Re-throw for workflow control or return specific error indicator throw new Error(`Operation failed: ${description}. Status: ${errorDetails.apiStatus || 'N/A'}. Message: ${errorDetails.message}`); } } // Usage Example: try { const product = await safeApiOperation( () => createProduct({ name: '...', sku: '...' }), 'Create Product SW-101' ); // ... other operations } catch (workflowError) { logger.error("Manufacturing workflow step failed:", workflowError.message); // Implement workflow recovery or termination logic } ``` *** ## Troubleshooting Common Manufacturing API Issues Address frequent problems encountered when integrating manufacturing workflows. * **Authentication Errors (401/403):** * **Solution:** Verify API key validity, environment variable loading, and key permissions for manufacturing-related resources (`product`, `workorder`, `inventory`, etc.). * **Not Found Errors (404):** * **Solution:** Double-check IDs used in requests (`productId`, `bomId`, `woId`, `moId`, `inventory_item_id`). Ensure the referenced resource exists and hasn't been deleted. Check for typos. * **Validation Errors (400):** * **Solution:** Examine `error.response.data` for details. Confirm required fields are present, data types match API expectations (number vs. string), dates are in ISO 8601 format, and enum values (`status`, `type`) are valid. Check quantity/unit consistency. * **Inventory Discrepancies:** * **Solution:** Audit the workflow logic: Are picks correctly deducting inventory? Is waste recording linked to an inventory adjustment? Are FG receipts correctly adding inventory? Use Cycle Counts to identify and investigate differences. Ensure correct `inventory_item_id`s are used. * **Incorrect Production Costs:** * **Solution:** Verify component costs used in calculations. Ensure labor and overhead tracking/allocation logic is correct. Check BOM accuracy. Confirm waste quantities are factored in appropriately. * **Race Conditions/Concurrency Issues:** * **Solution:** If multiple processes might update the same resource (e.g., inventory quantity), use optimistic locking mechanisms (if supported by API via ETags/versions) or structure workflows to minimize concurrent updates on the same item. Ensure idempotency for creation events. *** ## Support Resources Consult these resources for additional help and information: * **API Documentation:** [https://docs.StateSet.com/api-reference](https://docs.StateSet.com/api-reference) * **Developer Community:** [https://StateSet.com/community](https://StateSet.com/community) * **Support Contact:** [support@StateSet.com](mailto:support@StateSet.com) * **Tutorials & Examples:** [https://docs.StateSet.com/tutorials](https://docs.StateSet.com/tutorials) *** ## Conclusion This quickstart guide has provided a comprehensive walkthrough of managing manufacturing and production processes using the StateSet API. You have learned how to set up your environment, define products and BOMs, plan and execute production via Work Orders and Manufacturing Orders, track crucial activities like picks and machine usage, manage inventory movements, and leverage the captured data for optimization. By implementing these workflows and adhering to best practices for error handling and monitoring, you can build robust, efficient, and data-driven manufacturing operations powered by StateSet. Remember to adapt the specific costing, inventory adjustment, and optimization logic to your company's unique requirements and accounting practices. Utilize the available support resources for any further assistance needed. # MCP Integration for AI Agents Source: https://docs.stateset.com/guides/mcp-integration-guide Implement Model Context Protocol (MCP) to enable AI Agents to send messages and interact with the StateSet Commerce Network # MCP Integration for StateSet AI Agents ## Overview The Model Context Protocol (MCP) is an open standard that enables AI agents to seamlessly connect with external tools, services, and data sources. By integrating MCP into StateSet AI Agents, we enable them to send messages, interact with the StateSet Commerce Network, and perform complex operations across the blockchain ecosystem. ## Table of Contents 1. [Introduction to MCP](#introduction-to-mcp) 2. [Architecture Overview](#architecture-overview) 3. [MCP Server Implementation](#mcp-server-implementation) 4. [MCP Client Integration](#mcp-client-integration) 5. [StateSet Commerce Network Integration](#StateSet-commerce-network-integration) 6. [Message Protocol](#message-protocol) 7. [Security Considerations](#security-considerations) 8. [Testing and Deployment](#testing-and-deployment) 9. [Best Practices](#best-practices) ## Introduction to MCP MCP provides a standardized way for AI agents to: * Connect to external tools and services * Send and receive messages across different systems * Maintain context and state across interactions * Execute blockchain transactions on the StateSet Commerce Network ### Key Benefits Unified protocol for all agent-to-network interactions Seamless connection to StateSet modules and services Maintain agent state across sessions and transactions ## Architecture Overview ```mermaid theme={null} graph TB subgraph "AI Agent Layer" Agent[AI Agent] MCPClient[MCP Client] end subgraph "MCP Layer" MCPServer[MCP Server] Transport[Transport Layer] end subgraph "StateSet Commerce Network" OrderModule[Orders Module] PaymentModule[Payments Module] InventoryModule[Inventory Module] MessageBus[Message Bus] end Agent --> MCPClient MCPClient <--> Transport Transport <--> MCPServer MCPServer <--> MessageBus MessageBus --> OrderModule MessageBus --> PaymentModule MessageBus --> InventoryModule ``` ## MCP Server Implementation ### 1. Create the StateSet MCP Server ```typescript theme={null} // mcp-server/src/StateSet-mcp-server.ts import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { StateSetClient } from 'StateSet-node'; interface StateSetMCPConfig { apiKey: string; networkEndpoint: string; chainId: string; } class StateSetMCPServer { private server: Server; private StateSetClient: StateSetClient; constructor(config: StateSetMCPConfig) { this.server = new Server({ name: 'StateSet-commerce-mcp', version: '1.0.0', }, { capabilities: { resources: {}, tools: {}, }, }); this.StateSetClient = new StateSetClient({ apiKey: config.apiKey, networkEndpoint: config.networkEndpoint, chainId: config.chainId }); this.setupHandlers(); } private setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'send_message', description: 'Send a message through the StateSet Commerce Network', inputSchema: { type: 'object', properties: { recipient: { type: 'string', description: 'Recipient address or agent ID' }, message: { type: 'string', description: 'Message content' }, messageType: { type: 'string', enum: ['order', 'payment', 'inventory', 'general'], description: 'Type of message' }, metadata: { type: 'object', description: 'Additional message metadata' } }, required: ['recipient', 'message', 'messageType'] } }, { name: 'create_order', description: 'Create a new order on the StateSet Commerce Network', inputSchema: { type: 'object', properties: { customerId: { type: 'string' }, items: { type: 'array' }, totalAmount: { type: 'string' }, metadata: { type: 'object' } }, required: ['customerId', 'items', 'totalAmount'] } }, { name: 'query_network_state', description: 'Query the current state of the StateSet Commerce Network', inputSchema: { type: 'object', properties: { module: { type: 'string', enum: ['orders', 'payments', 'inventory', 'agents'] }, query: { type: 'object' } }, required: ['module'] } }, { name: 'execute_transaction', description: 'Execute a transaction on the StateSet Commerce Network', inputSchema: { type: 'object', properties: { module: { type: 'string' }, action: { type: 'string' }, params: { type: 'object' }, signer: { type: 'string' } }, required: ['module', 'action', 'params'] } } ] })); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { switch (request.params.name) { case 'send_message': return await this.handleSendMessage(request.params.arguments); case 'create_order': return await this.handleCreateOrder(request.params.arguments); case 'query_network_state': return await this.handleQueryNetworkState(request.params.arguments); case 'execute_transaction': return await this.handleExecuteTransaction(request.params.arguments); default: throw new Error(`Unknown tool: ${request.params.name}`); } }); // List available resources this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [ { uri: 'StateSet://network/status', name: 'Network Status', description: 'Current status of the StateSet Commerce Network', mimeType: 'application/json' }, { uri: 'StateSet://agents/directory', name: 'Agent Directory', description: 'List of registered AI agents on the network', mimeType: 'application/json' }, { uri: 'StateSet://modules/info', name: 'Module Information', description: 'Information about available network modules', mimeType: 'application/json' } ] })); // Handle resource reads this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; switch (uri) { case 'StateSet://network/status': return await this.getNetworkStatus(); case 'StateSet://agents/directory': return await this.getAgentDirectory(); case 'StateSet://modules/info': return await this.getModuleInfo(); default: throw new Error(`Unknown resource: ${uri}`); } }); } private async handleSendMessage(args: any) { try { // Create a message transaction on the StateSet Network const message = { typeUrl: '/StateSet.core.message.MsgSendMessage', value: { sender: args.signer || 'ai-agent-default', recipient: args.recipient, content: args.message, messageType: args.messageType, metadata: JSON.stringify(args.metadata || {}), timestamp: new Date().toISOString() } }; // Broadcast the message to the network const result = await this.StateSetClient.signAndBroadcast( args.signer || 'ai-agent-default', [message], 'auto' ); return { content: [{ type: 'text', text: `Message sent successfully. Transaction hash: ${result.transactionHash}` }], metadata: { transactionHash: result.transactionHash, height: result.height, gasUsed: result.gasUsed } }; } catch (error) { return { content: [{ type: 'text', text: `Failed to send message: ${error.message}` }], isError: true }; } } private async handleCreateOrder(args: any) { try { const order = await this.StateSetClient.orders.create({ customerId: args.customerId, items: args.items, totalAmount: args.totalAmount, status: 'CREATED', metadata: args.metadata }); return { content: [{ type: 'text', text: `Order created successfully. Order ID: ${order.id}` }], metadata: { orderId: order.id, status: order.status, createdAt: order.createdAt } }; } catch (error) { return { content: [{ type: 'text', text: `Failed to create order: ${error.message}` }], isError: true }; } } private async handleQueryNetworkState(args: any) { try { let result; switch (args.module) { case 'orders': result = await this.StateSetClient.orders.list(args.query || {}); break; case 'payments': result = await this.StateSetClient.payments.list(args.query || {}); break; case 'inventory': result = await this.StateSetClient.inventory.list(args.query || {}); break; case 'agents': result = await this.StateSetClient.agents.list(args.query || {}); break; default: throw new Error(`Unknown module: ${args.module}`); } return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], metadata: { module: args.module, count: result.length || result.total } }; } catch (error) { return { content: [{ type: 'text', text: `Query failed: ${error.message}` }], isError: true }; } } private async handleExecuteTransaction(args: any) { try { const msg = { typeUrl: `/StateSet.core.${args.module}.${args.action}`, value: args.params }; const result = await this.StateSetClient.signAndBroadcast( args.signer || 'ai-agent-default', [msg], 'auto' ); return { content: [{ type: 'text', text: `Transaction executed successfully. Hash: ${result.transactionHash}` }], metadata: { transactionHash: result.transactionHash, height: result.height, gasUsed: result.gasUsed, code: result.code } }; } catch (error) { return { content: [{ type: 'text', text: `Transaction failed: ${error.message}` }], isError: true }; } } private async getNetworkStatus() { const status = await this.StateSetClient.getNetworkStatus(); return { contents: [{ uri: 'StateSet://network/status', mimeType: 'application/json', text: JSON.stringify(status, null, 2) }] }; } private async getAgentDirectory() { const agents = await this.StateSetClient.agents.list({ limit: 100 }); return { contents: [{ uri: 'StateSet://agents/directory', mimeType: 'application/json', text: JSON.stringify(agents, null, 2) }] }; } private async getModuleInfo() { const modules = { orders: { description: 'Order management module', actions: ['create', 'fulfill', 'cancel', 'return'] }, payments: { description: 'Payment processing module', actions: ['create', 'process', 'refund'] }, inventory: { description: 'Inventory management module', actions: ['update', 'reserve', 'release'] }, messages: { description: 'Message passing module', actions: ['send', 'broadcast', 'query'] } }; return { contents: [{ uri: 'StateSet://modules/info', mimeType: 'application/json', text: JSON.stringify(modules, null, 2) }] }; } async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); logger.error('StateSet MCP Server started'); } } // Start the server const config: StateSetMCPConfig = { apiKey: process.env.STATESET_API_KEY!, networkEndpoint: process.env.STATESET_NETWORK_ENDPOINT || 'https://rpc.StateSet.zone', chainId: process.env.STATESET_CHAIN_ID || 'StateSet-1' }; const server = new StateSetMCPServer(config); server.start().catch(console.error); ``` ### 2. Package Configuration ```json theme={null} // mcp-server/package.json { "name": "@StateSet/mcp-server", "version": "1.0.0", "description": "MCP Server for StateSet Commerce Network", "main": "dist/index.js", "type": "module", "scripts": { "build": "tsc", "start": "node dist/StateSet-mcp-server.js", "dev": "tsx src/StateSet-mcp-server.ts" }, "dependencies": { "@modelcontextprotocol/sdk": "^0.5.0", "StateSet-node": "^1.0.0", "@cosmjs/stargate": "^0.32.0", "@cosmjs/proto-signing": "^0.32.0" }, "devDependencies": { "@types/node": "^20.0.0", "typescript": "^5.0.0", "tsx": "^4.0.0" } } ``` ## MCP Client Integration ### Integrating MCP Client into AI Agents ```typescript theme={null} // agents/mcp-client-integration.ts import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; import { Agent } from '../response-api-reference/framework'; interface MCPAgentConfig { agentId: string; mcpServerPath: string; capabilities: string[]; } export class MCPEnabledAgent extends Agent { private mcpClient: Client; private connected: boolean = false; constructor(config: MCPAgentConfig) { super(config); this.mcpClient = new Client({ name: `agent-${config.agentId}`, version: '1.0.0', }, { capabilities: {} }); } async connectToMCP() { try { const transport = new StdioClientTransport({ command: 'node', args: [this.config.mcpServerPath] }); await this.mcpClient.connect(transport); this.connected = true; // List available tools const tools = await this.mcpClient.listTools(); logger.info('Available MCP tools:', tools); return true; } catch (error) { logger.error('Failed to connect to MCP server:', error); return false; } } async sendNetworkMessage( recipient: string, message: string, messageType: 'order' | 'payment' | 'inventory' | 'general', metadata?: any ) { if (!this.connected) { throw new Error('MCP client not connected'); } const result = await this.mcpClient.callTool('send_message', { recipient, message, messageType, metadata }); return result; } async createOrder(orderData: { customerId: string; items: any[]; totalAmount: string; metadata?: any; }) { if (!this.connected) { throw new Error('MCP client not connected'); } const result = await this.mcpClient.callTool('create_order', orderData); return result; } async queryNetworkState(module: string, query?: any) { if (!this.connected) { throw new Error('MCP client not connected'); } const result = await this.mcpClient.callTool('query_network_state', { module, query }); return result; } async executeNetworkTransaction( module: string, action: string, params: any, signer?: string ) { if (!this.connected) { throw new Error('MCP client not connected'); } const result = await this.mcpClient.callTool('execute_transaction', { module, action, params, signer }); return result; } // Override the process method to include MCP capabilities async process(input: string, context: any = {}) { // Check if the input requires network interaction if (this.requiresNetworkAction(input)) { const action = await this.determineNetworkAction(input, context); switch (action.type) { case 'send_message': return await this.sendNetworkMessage( action.recipient, action.message, action.messageType, action.metadata ); case 'create_order': return await this.createOrder(action.orderData); case 'query_state': return await this.queryNetworkState(action.module, action.query); case 'execute_transaction': return await this.executeNetworkTransaction( action.module, action.action, action.params, action.signer ); } } // Fall back to standard agent processing return await super.process(input, context); } private requiresNetworkAction(input: string): boolean { const networkKeywords = [ 'send', 'message', 'order', 'create', 'payment', 'inventory', 'network', 'blockchain', 'transaction' ]; return networkKeywords.some(keyword => input.toLowerCase().includes(keyword) ); } private async determineNetworkAction(input: string, context: any) { // Use the agent's LLM to determine the appropriate network action const prompt = ` Given the user input: "${input}" And context: ${JSON.stringify(context)} Determine if this requires a network action and return the appropriate action object. Available actions: 1. send_message: { type: 'send_message', recipient, message, messageType, metadata } 2. create_order: { type: 'create_order', orderData: { customerId, items, totalAmount, metadata } } 3. query_state: { type: 'query_state', module, query } 4. execute_transaction: { type: 'execute_transaction', module, action, params, signer } Return null if no network action is required. `; // This would use the agent's LLM to determine the action // For now, we'll implement basic pattern matching if (input.includes('send') && input.includes('message')) { return { type: 'send_message', recipient: this.extractRecipient(input), message: this.extractMessage(input), messageType: 'general', metadata: {} }; } if (input.includes('create') && input.includes('order')) { return { type: 'create_order', orderData: this.extractOrderData(input, context) }; } // Add more pattern matching as needed return null; } // Helper methods for extracting data from input private extractRecipient(input: string): string { // Implement logic to extract recipient from input return 'default-recipient'; } private extractMessage(input: string): string { // Implement logic to extract message content return input; } private extractOrderData(input: string, context: any): any { // Implement logic to extract order data return { customerId: context.customerId || 'default-customer', items: [], totalAmount: '0', metadata: {} }; } } ``` ## StateSet Commerce Network Integration ### Message Module Implementation ```protobuf theme={null} // proto/StateSet/message/v1/message.proto syntax = "proto3"; package StateSet.message.v1; import "google/protobuf/timestamp.proto"; import "cosmos/base/v1beta1/coin.proto"; // Message represents a message sent through the StateSet network message Message { string id = 1; string sender = 2; string recipient = 3; string content = 4; string message_type = 5; string metadata = 6; // JSON string google.protobuf.Timestamp created_at = 7; MessageStatus status = 8; } enum MessageStatus { MESSAGE_STATUS_UNSPECIFIED = 0; MESSAGE_STATUS_PENDING = 1; MESSAGE_STATUS_DELIVERED = 2; MESSAGE_STATUS_READ = 3; MESSAGE_STATUS_FAILED = 4; } // MsgSendMessage defines a message for sending a message through the network message MsgSendMessage { string sender = 1; string recipient = 2; string content = 3; string message_type = 4; string metadata = 5; } message MsgSendMessageResponse { string message_id = 1; } // Query service for messages service Query { rpc Message(QueryMessageRequest) returns (QueryMessageResponse); rpc Messages(QueryMessagesRequest) returns (QueryMessagesResponse); rpc MessagesByRecipient(QueryMessagesByRecipientRequest) returns (QueryMessagesByRecipientResponse); } message QueryMessageRequest { string message_id = 1; } message QueryMessageResponse { Message message = 1; } message QueryMessagesRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; } message QueryMessagesResponse { repeated Message messages = 1; cosmos.base.query.v1beta1.PageResponse pagination = 2; } message QueryMessagesByRecipientRequest { string recipient = 1; cosmos.base.query.v1beta1.PageRequest pagination = 2; } message QueryMessagesByRecipientResponse { repeated Message messages = 1; cosmos.base.query.v1beta1.PageResponse pagination = 2; } // Msg service for message transactions service Msg { rpc SendMessage(MsgSendMessage) returns (MsgSendMessageResponse); } ``` ## Message Protocol ### Message Types and Formats ```typescript theme={null} // types/message-protocol.ts export enum MessageType { ORDER = 'order', PAYMENT = 'payment', INVENTORY = 'inventory', GENERAL = 'general', SYSTEM = 'system', AGENT_HANDOFF = 'agent_handoff', WORKFLOW_TRIGGER = 'workflow_trigger' } export interface BaseMessage { id: string; sender: string; recipient: string; messageType: MessageType; timestamp: string; metadata: Record; } export interface OrderMessage extends BaseMessage { messageType: MessageType.ORDER; content: { orderId: string; action: 'create' | 'update' | 'cancel' | 'fulfill'; orderData?: any; }; } export interface PaymentMessage extends BaseMessage { messageType: MessageType.PAYMENT; content: { paymentId: string; amount: string; currency: string; status: 'pending' | 'completed' | 'failed'; }; } export interface AgentHandoffMessage extends BaseMessage { messageType: MessageType.AGENT_HANDOFF; content: { fromAgent: string; toAgent: string; context: any; reason: string; }; } export interface WorkflowTriggerMessage extends BaseMessage { messageType: MessageType.WORKFLOW_TRIGGER; content: { workflowId: string; triggerType: string; parameters: Record; }; } ``` ## Security Considerations ### 1. Authentication and Authorization ```typescript theme={null} // security/mcp-auth.ts export class MCPAuthProvider { private validatedAgents: Map = new Map(); async authenticateAgent(agentId: string, signature: string): Promise { // Verify agent signature using public key const agent = await this.getAgentCredentials(agentId); if (!agent) return false; return this.verifySignature(agentId, signature, agent.publicKey); } async authorizeAction(agentId: string, action: string, resource: string): Promise { const permissions = await this.getAgentPermissions(agentId); return permissions.some(p => p.action === action && (p.resource === '*' || p.resource === resource) ); } private async getAgentCredentials(agentId: string): Promise { // Fetch from StateSet network or cache return this.validatedAgents.get(agentId) || null; } private async getAgentPermissions(agentId: string): Promise { // Query permissions from the network const agent = await this.StateSetClient.agents.get(agentId); return agent.permissions || []; } private verifySignature(agentId: string, signature: string, publicKey: string): boolean { // Implement signature verification return true; // Placeholder } } interface AgentCredentials { agentId: string; publicKey: string; permissions: Permission[]; } interface Permission { action: string; resource: string; } ``` ### 2. Message Encryption ```typescript theme={null} // security/message-encryption.ts export class MessageEncryption { async encryptMessage(message: any, recipientPublicKey: string): Promise { // Implement end-to-end encryption for sensitive messages // Using recipient's public key return JSON.stringify(message); // Placeholder } async decryptMessage(encryptedMessage: string, privateKey: string): Promise { // Decrypt message using private key return JSON.parse(encryptedMessage); // Placeholder } } ``` ## Testing and Deployment ### 1. Unit Tests ```typescript theme={null} // tests/mcp-server.test.ts import { describe, it, expect } from 'vitest'; import { StateSetMCPServer } from '../src/StateSet-mcp-server'; describe('StateSet MCP Server', () => { let server: StateSetMCPServer; beforeEach(() => { server = new StateSetMCPServer({ apiKey: 'test-key', networkEndpoint: 'https://yourapp.com:26657', chainId: 'test-chain' }); }); it('should list available tools', async () => { const tools = await server.listTools(); expect(tools).toContain('send_message'); expect(tools).toContain('create_order'); expect(tools).toContain('query_network_state'); expect(tools).toContain('execute_transaction'); }); it('should send a message successfully', async () => { const result = await server.handleSendMessage({ recipient: 'agent-123', message: 'Test message', messageType: 'general', metadata: { test: true } }); expect(result.isError).toBeFalsy(); expect(result.metadata.transactionHash).toBeDefined(); }); it('should handle network errors gracefully', async () => { // Simulate network error server.StateSetClient = null; const result = await server.handleSendMessage({ recipient: 'agent-123', message: 'Test message', messageType: 'general' }); expect(result.isError).toBeTruthy(); expect(result.content[0].text).toContain('Failed to send message'); }); }); ``` ## Best Practices ### 1. Error Handling ```typescript theme={null} class MCPErrorHandler { static handleError(error: any, context: string): MCPError { if (error.code === 'NETWORK_ERROR') { return new MCPError( 'Network communication failed', 'NETWORK_ERROR', { originalError: error, context } ); } if (error.code === 'UNAUTHORIZED') { return new MCPError( 'Agent not authorized for this action', 'AUTH_ERROR', { originalError: error, context } ); } return new MCPError( 'An unexpected error occurred', 'UNKNOWN_ERROR', { originalError: error, context } ); } } class MCPError extends Error { constructor( message: string, public code: string, public details: any ) { super(message); this.name = 'MCPError'; } } ``` ### 2. Rate Limiting ```typescript theme={null} class MCPRateLimiter { private requests: Map = new Map(); constructor( private maxRequests: number = 100, private windowMs: number = 60000 // 1 minute ) {} async checkLimit(agentId: string): Promise { const now = Date.now(); const requests = this.requests.get(agentId) || []; // Remove old requests outside the window const validRequests = requests.filter(time => now - time < this.windowMs); if (validRequests.length >= this.maxRequests) { return false; } validRequests.push(now); this.requests.set(agentId, validRequests); return true; } } ``` ### 3. Monitoring and Observability ```typescript theme={null} class MCPMonitor { private metrics: Map = new Map(); recordToolCall(toolName: string, agentId: string, duration: number, success: boolean) { const key = `tool_call_${toolName}`; const current = this.metrics.get(key) || { total: 0, success: 0, failed: 0, avgDuration: 0 }; current.total++; if (success) current.success++; else current.failed++; current.avgDuration = (current.avgDuration * (current.total - 1) + duration) / current.total; this.metrics.set(key, current); // Send to monitoring service this.sendToMonitoring({ metric: 'mcp.tool_call', tags: { tool: toolName, agent: agentId, success: success.toString() }, value: duration }); } private sendToMonitoring(metric: any) { // Implement sending to Prometheus, DataDog, etc. logger.info('Metric:', metric); } } ``` ## Conclusion By implementing MCP (Model Context Protocol) for StateSet AI Agents, we enable: 1. **Standardized Communication**: All agents can communicate with the StateSet Commerce Network using a unified protocol 2. **Enhanced Capabilities**: Agents can perform complex operations like creating orders, processing payments, and managing inventory 3. **Scalability**: New tools and services can be easily added to the MCP server 4. **Security**: Built-in authentication, authorization, and encryption ensure secure communications 5. **Interoperability**: Agents can work together and hand off tasks seamlessly This implementation provides a robust foundation for AI agents to interact with the StateSet Commerce Network, enabling autonomous commerce operations at scale. ## Next Steps 1. **Deploy MCP Server**: Set up the MCP server in your environment 2. **Update Agents**: Integrate MCP client capabilities into existing agents 3. **Test Integration**: Run comprehensive tests to ensure reliability 4. **Monitor Performance**: Set up monitoring for MCP operations 5. **Extend Capabilities**: Add new tools and resources as needed For more information and support, visit the [StateSet Documentation](https://docs.StateSet.com) or join our [Discord community](https://discord.gg/VfcaqgZywq). # MHG User Guide Source: https://docs.stateset.com/guides/mhg-guide Getting started with the StateSet API ### StateSet One User Documentation for Morrison Hotel Gallery #### Table of Contents 1. [Overview](#overview) 2. [Logging In](#logging-in) 3. [Navigation](#navigation) 4. [Order Management](#order-management) * [Pending Orders](#pending-orders) * [Active Orders](#active-orders) * [Archived Orders](#archived-orders) * [Sales View](#sales-view) * [Ready to Pay](#ready-to-pay) 5. [Search Functionality](#search-functionality) 6. [Filters and Sorting](#filters-and-sorting) 7. [Order Details and Editing](#order-details-and-editing) 8. [Automation Features](#automation-features) 9. [Shopify Integration](#shopify-integration) 10. [Troubleshooting](#troubleshooting) ## Overview StateSet One is a platform integrated with Shopify to automate more of the order process, reduce manual work, and provide real-time, essential data in a customizable platform for MHG. This documentation will guide you through using StateSet One for order management. ## Logging In 1. Go to [https://StateSet.com/main-view](https://StateSet.com/main-view) 2. Enter your username and password 3. Click "Log In" Note: The system is transitioning from passwordless login to direct login. If you encounter issues, please contact [dom@StateSet.com](mailto:dom@StateSet.com) ## Navigation The top navigation bar includes the following sections: 1. Pending 2. Active 3. Archived 4. Sales View 5. Ready to Pay ## Post-Purchase Order Management and Automation An order is created in Shopify, creating a webhook which is then used to create the Order and Order Line Items in StateSet. The order line items are updated in StateSet. This tracks photographer acknowledgement, need by date, print status, and more. The order is marked as fulfilled in Shopify. This moves the order to the archived view. ### Print Object Fields | Field Name | Type | Description | | ------------------------------------- | ------------------------ | --------------------------------------------------------------- | | id | uuid | Primary key, unique, default: gen\_random\_uuid() | | outstanding\_order\_id | uuid | Unique identifier for the outstanding order | | print\_name | text | Name of the print (nullable) | | edition\_number | text | Edition number of the print (nullable) | | photographer | text | Name of the photographer (nullable) | | print\_size | text | Size of the print (nullable) | | notification\_sent | boolean | Whether a notification has been sent (nullable) | | notification\_created | timestamp with time zone | When the notification was created (nullable) | | framed | boolean | Whether the print is framed (nullable) | | unframed | boolean | Whether the print is unframed (nullable) | | damaged\_print | text | Details about any damage to the print (nullable) | | photographer\_to\_framer | text | Information about photographer to framer shipment (nullable) | | mhg\_to\_framer | text | Information about MHG to framer shipment (nullable) | | notes | text | Additional notes about the order (nullable) | | date\_sent\_to\_framer | date | Date the print was sent to the framer (nullable) | | date\_back\_from\_framer | date | Date the print returned from the framer (nullable) | | date\_shipped\_pu\_complete | date | Date the order was shipped or picked up (nullable) | | date\_received\_at\_fulfill\_location | date | Date received at fulfillment location (nullable) | | sku | text | Stock Keeping Unit (nullable) | | framer\_location | text | Location of the framer (nullable) | | created\_at | timestamp with time zone | Creation date of the record (nullable, default: now()) | | date\_ordered | date | Date the order was placed (nullable) | | fulfillment\_location | text | Location for order fulfillment (nullable) | | framer | text | Name or details of the framer (nullable) | | sales\_person | text | Name of the sales person (nullable) | | print\_status | text | Current status of the print (nullable) | | invoice\_number | text | Invoice number for the order (nullable) | | issues | text | Any issues with the order (nullable) | | balance\_due | text | Remaining balance on the order (nullable) | | back\_from\_framer | boolean | Whether the print is back from the framer (nullable) | | date\_of\_sale | date | Date of the sale (nullable) | | need\_by\_date | date | Required delivery date (nullable) | | tracking\_number | text | Shipping tracking number (nullable) | | view\_status | text | Current view status of the order (nullable, default: 'pending') | | photographer\_acknowledged | boolean | Whether the photographer has acknowledged the order (nullable) | | client\_name | text | Name of the client (nullable) | | en\_route | boolean | Whether the order is en route (nullable) | ### Fulfillment Locations * Soho * West LA * Sunset Marquis ### Print Statuses * En Route * At Framer * Received * Ready ### Pending Orders `StateSet.com/pending-main-view` * This view shows orders that have not yet been paid for or are partially paid. * Orders with the "Partial OOI" Shopify tag will appear here with a checkbox to alert that not every print needs to be ordered. ### Active Orders `StateSet.com/main-view` * This view displays orders that are currently being processed. * Orders tagged with "OOI" (Out of Inventory) in Shopify will automatically appear in this view. ### Archived Orders `StateSet.com/archived` * This view shows completed orders. * Orders are automatically moved here when fulfilled in Shopify. ### Sales View `StateSet.com/sales-view` * This view includes a Client Name column and will show active orders. ### Ready to Pay `StateSet.com/ready-to-pay` * This page populates with a duplication of a print when tagged "OOI" in Shopify and marked "received" in StateSet. ## Search Functionality * Use the search bar to find orders by various criteria including Print, Photographer and Invoice Number ### Filters and Sorting * Use filters to narrow down orders based on specific criteria. * Sorting is available for most columns. * Filters and sorting preferences are retained when navigating between pages. Filters can be cleared by setting the picklist to "All print, locations etc." ### Order Details and Editing * Click on an order to view its details in the side panel. * Inline editing is available for most fields, including the "Acknowledged" checkbox in the Active view. * The "Instructions" column can be expanded to view full text. ### Automation Features * "OOI" Shopify tag moves orders directly to Active view. * Setting the Sales Order Date moves an order from Pending to Active. * Fulfillment in Shopify automatically moves an order to Archived in StateSet. * Setting "En Route Date" moves an order status to "En Route". * Setting the "To Framer Date" updates the print status to "At Framer". ### Color Coding for Orders * Orders that are ready to print are green * Orders that are at framer are blue * Orders that are received are orange * Orders that are alert are red ### Shopify Integration * StateSet pulls in relevant order data from Shopify, including custom tags. * Changes in StateSet can be written back to Shopify via API. * The Invoice Number in StateSet links back to the corresponding Shopify order page. ### StateSet Value Props * **Automated Order Management:** StateSet One integrates seamlessly with Shopify to automate various aspects of order management, reducing manual work and ensuring that orders are processed efficiently and accurately. This includes automatic updates to order statuses and the movement of orders between different stages (e.g., from Pending to Active, or Active to Archived) based on predefined triggers. * **Real-Time Data and Customization:** The platform provides real-time access to essential data through customizable views, allowing users to manage orders, track statuses, and update details with minimal effort. Custom filters, sorting, and inline editing enhance the user experience by making it easy to find and manage specific orders. * **Comprehensive Order Tracking:** StateSet One offers detailed tracking for each order, including various print statuses, fulfillment locations, and shipment details. This ensures that every aspect of an order—from creation to fulfillment—is closely monitored, providing transparency and reducing the risk of errors. * **Seamless Shopify Integration:** The integration with Shopify allows StateSet to pull in relevant order data and custom tags, ensuring that both platforms remain synchronized. Updates made in StateSet can also be written back to Shopify, maintaining consistency and accuracy across systems. * **Automation of Complex Workflows:** StateSet simplifies complex workflows through automation, such as automatically moving orders to different views based on tags or status updates, and color-coding orders based on their readiness or alert status. This automation helps users focus on critical tasks and reduces the need for manual intervention. ## Troubleshooting If you encounter any issues: * Ensure you're using the latest version of your web browser. * Clear your browser cache and cookies. * If problems persist, contact your system administrator or StateSet support. This is a living document and will be updated as new features are implemented and workflows are refined. # Multi-Agent System Architectures Source: https://docs.stateset.com/guides/multi-agent-systems Design and build multi-agent systems with triage routing, hierarchical support, and collaborative operations. # Multi-Agent System Architectures Welcome to the architectural guide for building advanced multi-agent systems. This guide moves beyond single-agent setups to explore powerful patterns for orchestrating teams of AI agents. By delegating tasks to specialized agents, you can build more robust, scalable, and maintainable AI applications. We will explore three distinct architectural patterns using ResponseCX agents (patterns compatible with the OpenAI Agents API): 1. **General Triage Model**: A central agent routes diverse tasks to the correct specialist. 2. **Hierarchical Customer Support**: A tiered system for handling customer service with clear escalation paths. 3. **Collaborative Operations Team**: An internal-facing system where agents act as a team of department heads to run a business. *** ## 1. General Triage Model This is a fundamental pattern where a primary **Triage Agent** acts as a smart router. It assesses incoming requests and delegates them to a specialist agent with the appropriate tools and expertise. ### Use Case Ideal for applications that handle a wide variety of tasks, such as a general-purpose assistant that needs to access a knowledge base, manage user-specific memory, or perform business operations. ### Architecture ```mermaid theme={null} graph TD A[User Request] --> TriageAgent{Triage Agent}; TriageAgent -- "Knowledge Question?" --> KnowledgeAgent[Knowledge Agent]; TriageAgent -- "Memory Operation?" --> MemoryAgent[Memory Agent]; TriageAgent -- "Business Task?" --> BusinessAgent[Business Agent]; subgraph "Specialist Tools" KnowledgeAgent -- "Uses" --> Pinecone[(Vector DB)]; MemoryAgent -- "Uses" --> Mem0[(Memory API)]; BusinessAgent -- "Uses" --> StateSet[(Business API)]; end KnowledgeAgent --> TriageAgent; MemoryAgent --> TriageAgent; BusinessAgent --> TriageAgent; ``` ### Implementation The `TriageAgent` is configured with `handoffs` to the specialist agents. Each specialist has a narrow set of tools and instructions, making them experts at their specific function. ```typescript theme={null} // Define Specialist Agents const knowledgeAgent = new Agent({ name: 'Knowledge Base Agent', handoffDescription: 'For questions about our products, services, or policies.', tools: [vectorSearchTool], // ...instructions }); const memoryAgent = new Agent({ name: 'Memory Agent', handoffDescription: 'To remember or recall user-specific information.', tools: [memoryTool], // ...instructions }); // Define the Triage Agent const triageAgent = Agent.create({ name: 'Response AI Triage Agent', instructions: 'You are a master router. Your job is to delegate tasks to the correct specialist agent.', handoffs: [knowledgeAgent, memoryAgent /*, ...other specialists */], }); // Enable handoffs back to the triage agent knowledgeAgent.handoffs = [triageAgent]; memoryAgent.handoffs = [triageAgent]; ``` *** ## 2. Hierarchical Customer Support Model This pattern builds on the triage model to create a more structured, customer-facing support system. It defines clear roles for different levels of support and includes a dedicated escalation path for complex or sensitive issues. ### Use Case Perfect for building a scalable, AI-powered customer service department that can handle a high volume of requests while providing expert-level support and a great customer experience for difficult cases. ### Architecture ```mermaid theme={null} graph TD subgraph "Triage & Initial Contact" A[User Request] --> Triage{Triage Agent} end subgraph "Tier 1: Specialist Agents" Triage -- "Order Inquiry" --> OrderAgent[Order Support Specialist] Triage -- "Return Request" --> ReturnsAgent[Returns Specialist] Triage -- "Policy Question" --> FAQAgent[FAQ Assistant] end subgraph "Tier 2: Escalation Path" Triage -- "Complex Issue / Frustration" --> EscalationAgent[Senior Support Specialist] OrderAgent -- "Escalate" --> EscalationAgent ReturnsAgent -- "Escalate" --> EscalationAgent end ``` ### Implementation The key here is the `SeniorSupportSpecialist`, which has access to a broader set of tools and is given instructions that explicitly grant it authority to override policies or offer compensation. ```typescript theme={null} // Tier 1 Specialist const orderSupportAgent = new Agent({ name: 'Order Support Specialist', handoffDescription: 'Handles order tracking, modifications, and cancellations.', tools: [orderLookupTool, updateOrderTool], // ...instructions }); // Tier 2 Escalation Agent const escalationAgent = new Agent({ name: 'Senior Support Specialist', handoffDescription: 'For complex issues, policy exceptions, and VIP customer care.', instructions: `You are a Senior Support Specialist with authority to make exceptions and offer compensation. ## Your Enhanced Authority: - Offer discounts or store credit. - Override standard return policies when justified. - Handle complaints with full resolution power.`, tools: [orderLookupTool, updateOrderTool, createReturnTool, createTicketTool], // Has more tools }); // Triage Agent with an escalation path const triageAgent = Agent.create({ name: 'Customer Service Triage', instructions: `Your job is to route customers to the correct specialist. If the customer is angry or the issue is complex, route to the Senior Support Specialist.`, handoffs: [orderSupportAgent, returnsAgent, faqAgent, escalationAgent], }); // Allow Tier 1 agents to escalate orderSupportAgent.handoffs = [triageAgent, escalationAgent]; returnsAgent.handoffs = [triageAgent, escalationAgent]; ``` *** ## 3. Collaborative Operations Team Model This architecture is designed for internal use, acting as an "agentic operating system" for a business. A `Master Orchestrator` agent acts as a CEO or project manager, delegating high-level goals to a team of agents representing different departments. These specialists can collaborate and hand off tasks to each other. ### Use Case An internal tool for business leaders to analyze performance, generate strategies, and optimize operations by interacting with a team of AI department heads. ### Architecture ```mermaid theme={null} graph TD A[User Request / Business Goal] --> Orchestrator{Master Orchestrator}; Orchestrator -- "Marketing Strategy?" --> Marketing[Marketing Specialist]; Orchestrator -- "Sales Performance?" --> Sales[Sales Manager]; Orchestrator -- "Inventory/Fulfillment?" --> Operations[Operations Director]; subgraph "Specialist Collaboration (Peer-to-Peer Handoffs)" Marketing <--> Sales; Sales <--> Operations; Operations <--> Marketing; end ``` ### Implementation The main difference is the handoff configuration. Here, specialists can hand off tasks directly to each other, enabling true collaboration to solve multi-faceted problems. ```typescript theme={null} // Define department-specialized agents const marketingAgent = new Agent({ name: 'Marketing Specialist', instructions: 'You are an expert in marketing campaigns, analytics, and strategy.', tools: [generateMarketingStrategyTool, campaignManagementTool], }); const salesAgent = new Agent({ name: 'Sales Manager', instructions: 'You are an expert in sales performance, forecasting, and pricing.', tools: [salesAnalysisTool], }); const operationsAgent = new Agent({ name: 'Operations Director', instructions: 'You are an expert in inventory, fulfillment, and supply chain.', tools: [inventoryAnalysisTool], }); // The Orchestrator delegates to any specialist const orchestratorAgent = Agent.create({ name: 'Master Orchestrator', instructions: 'You are the orchestrator for the business. Delegate tasks to the appropriate department head.', handoffs: [marketingAgent, salesAgent, operationsAgent], }); // Configure peer-to-peer handoffs for collaboration marketingAgent.handoffs = [orchestratorAgent, salesAgent, operationsAgent]; salesAgent.handoffs = [orchestratorAgent, marketingAgent, operationsAgent]; operationsAgent.handoffs = [orchestratorAgent, marketingAgent, salesAgent]; ``` *** ## Best Practices for Multi-Agent Systems ### 1. Error Handling and Resilience Implement robust error handling to ensure your multi-agent system gracefully handles failures: ```typescript theme={null} // Wrap agent interactions with try-catch blocks async function handleUserRequest(request: string) { try { const response = await triageAgent.process(request); return response; } catch (error) { if (error.code === 'HANDOFF_FAILED') { // Fallback to a general purpose agent return await fallbackAgent.process(request); } else if (error.code === 'TIMEOUT') { // Implement retry logic with exponential backoff return await retryWithBackoff(() => triageAgent.process(request)); } // Log error for monitoring logger.error('Agent processing failed', { error, request }); throw new Error('Unable to process request. Please try again.'); } } // Implement timeout handling for long-running operations async function processWithTimeout(agent: Agent, request: string, timeoutMs = 30000) { const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Operation timed out')), timeoutMs) ); return Promise.race([ agent.process(request), timeoutPromise ]); } ``` ### 2. Monitoring and Observability Track key metrics to ensure your multi-agent system performs optimally: ```typescript theme={null} // Track handoff patterns and success rates interface HandoffMetrics { sourceAgent: string; targetAgent: string; success: boolean; duration: number; timestamp: Date; } class MetricsCollector { async trackHandoff(metrics: HandoffMetrics) { // Send to your monitoring service await analytics.track('agent_handoff', metrics); // Alert on failed handoffs if (!metrics.success) { await alerting.notify({ type: 'handoff_failure', severity: 'warning', details: metrics }); } } } ``` ### 3. Testing Multi-Agent Interactions Create comprehensive tests for your multi-agent systems: ```typescript theme={null} describe('Multi-Agent System Tests', () => { it('should correctly route customer support requests', async () => { const testCases = [ { input: 'Where is my order #12345?', expectedAgent: 'Order Support Specialist' }, { input: 'I need to return a damaged item', expectedAgent: 'Returns Specialist' }, { input: 'I\'m very upset about my experience!', expectedAgent: 'Senior Support Specialist' } ]; for (const testCase of testCases) { const result = await triageAgent.route(testCase.input); expect(result.selectedAgent).toBe(testCase.expectedAgent); } }); it('should handle circular handoffs gracefully', async () => { // Test that prevents infinite loops between agents const maxHandoffs = 5; const result = await triageAgent.process('Complex request requiring multiple handoffs', { maxHandoffs }); expect(result.handoffCount).toBeLessThanOrEqual(maxHandoffs); }); }); ``` ### 4. Performance Optimization Optimize your multi-agent system for speed and efficiency: ```typescript theme={null} // Cache frequently accessed data const agentCache = new Map(); // Preload agent configurations async function initializeAgents() { const agents = [triageAgent, orderAgent, returnsAgent, escalationAgent]; await Promise.all(agents.map(async (agent) => { // Preload tools and configurations await agent.initialize(); // Warm up the agent with common queries await agent.warmup([ 'Order status inquiry', 'Return request', 'Product information' ]); })); } // Implement connection pooling for external services const connectionPool = new ConnectionPool({ maxConnections: 10, idleTimeout: 300000 // 5 minutes }); ``` ### 5. Security Considerations Ensure your multi-agent system maintains security best practices: ```typescript theme={null} // Implement rate limiting per user const rateLimiter = new RateLimiter({ windowMs: 60000, // 1 minute maxRequests: 10 }); // Sanitize user inputs before processing function sanitizeInput(input: string): string { // Remove potential injection attempts return input .replace(/)<[^<]*)*<\/script>/gi, '') .replace(/[<>]/g, '') .trim(); } // Implement authorization checks for sensitive operations async function authorizeAgentAction(agent: Agent, action: string, context: Context) { const permissions = await getAgentPermissions(agent.id); if (!permissions.includes(action)) { throw new Error(`Agent ${agent.name} not authorized for action: ${action}`); } // Log all authorized actions for audit trail await auditLog.record({ agent: agent.id, action, context, timestamp: new Date() }); } ``` *** ## Challenges and Limitations of Multi-Agent Systems While powerful, multi-agent systems come with challenges: ### 1. Context Sharing and Reliability * Agents must share full context to avoid compounding errors; dispersed decision-making can lead to inconsistencies (Cognition, 2025). * Recommendation: Use single-threaded designs or context compression for long tasks. ### 2. Coordination Complexity * Managing interactions between agents can be difficult, leading to conflicts or unpredictable behavior. * Solution: Implement robust orchestration with clear protocols. ### 3. Scalability Issues * As systems grow, resource demands increase; optimize by matching agents to tasks based on cost, speed, and quality needs. ### 4. Security and Privacy * Distributed systems heighten risks; use encryption, audits, and access controls. ### 5. Development Overhead * Building and debugging multi-agent systems is more complex than single-agent setups. Experts note that multi-agents can be fragile without careful design, suggesting starting simple and scaling cautiously. *** ## Advanced Patterns ### Dynamic Agent Creation Create agents dynamically based on business needs: ```typescript theme={null} class DynamicAgentFactory { async createSpecialistAgent(specialty: string, tools: Tool[]) { const agent = new Agent({ name: `${specialty} Specialist`, handoffDescription: `Handles ${specialty.toLowerCase()} related queries`, instructions: await this.generateInstructions(specialty), tools }); // Register with the triage agent await this.registerWithTriage(agent); return agent; } private async generateInstructions(specialty: string): Promise { // Use AI to generate role-specific instructions return await generateAgentInstructions({ role: specialty, capabilities: this.getCapabilitiesForSpecialty(specialty), guidelines: this.getCompanyGuidelines() }); } } ``` ### Adaptive Routing Implement intelligent routing that learns from past interactions: ```typescript theme={null} class AdaptiveRouter { private routingHistory: Map = new Map(); async route(request: string, context: Context): Promise { // Get historical routing decisions for similar requests const similarRequests = await this.findSimilarRequests(request); // Calculate success rates for each agent const agentPerformance = this.calculateAgentPerformance(similarRequests); // Select the best performing agent for this type of request const selectedAgent = this.selectOptimalAgent(agentPerformance, context); // Track this routing decision this.trackRoutingDecision(request, selectedAgent); return selectedAgent; } private calculateAgentPerformance(history: RoutingDecision[]): Map { const performance = new Map(); for (const decision of history) { const currentScore = performance.get(decision.agentId) || 0; const newScore = decision.success ? currentScore + 1 : currentScore - 1; performance.set(decision.agentId, newScore); } return performance; } } ``` *** ## Conclusion Multi-agent systems represent the future of AI-powered business operations. By implementing these patterns and best practices, you can build robust, scalable, and intelligent systems that dramatically improve efficiency and customer satisfaction. ### Next Steps Explore the complete Agents API documentation Learn how to train and optimize your agents See real-world integration examples Get help from our team # Multi-Channel Commerce Integration Guide Source: https://docs.stateset.com/guides/multi-channel-integration-guide Complete guide to integrating TikTok Shop, Amazon, Walmart, and other e-commerce channels with StateSet # Multi-Channel Commerce Integration Guide Welcome to the StateSet Multi-Channel Commerce Integration Guide! This comprehensive guide will walk you through integrating major e-commerce channels including TikTok Shop, Amazon, Walmart, and more into your unified commerce platform using StateSet's powerful APIs and tools. ## Table of Contents 1. [Introduction](#introduction) 2. [Prerequisites](#prerequisites) 3. [Channel Overview](#channel-overview) 4. [TikTok Shop Integration](#tiktok-shop-integration) 5. [Amazon Integration](#amazon-integration) 6. [Walmart Integration](#walmart-integration) 7. [Shopify Integration](#shopify-integration) 8. [eBay Integration](#ebay-integration) 9. [Multi-Channel Order Management](#multi-channel-order-management) 10. [Inventory Synchronization](#inventory-synchronization) 11. [Pricing Strategies](#pricing-strategies) 12. [Analytics and Reporting](#analytics-and-reporting) 13. [Best Practices](#best-practices) 14. [Troubleshooting](#troubleshooting) *** ## Introduction In today's omnichannel commerce landscape, selling across multiple platforms is essential for maximizing reach and revenue. However, managing inventory, orders, and customer data across TikTok Shop, Amazon, Walmart, and other channels can quickly become overwhelming without the right tools. StateSet provides a unified platform that seamlessly integrates with major e-commerce channels, enabling you to: * **Centralize order management** across all sales channels * **Synchronize inventory** in real-time to prevent overselling * **Automate product listings** with channel-specific optimizations * **Track performance** with unified analytics * **Streamline fulfillment** with intelligent order routing ### Benefits of Multi-Channel Integration Reach customers where they shop with presence across multiple platforms Manage all channels from a single dashboard with automated workflows Provide consistent service and faster fulfillment across all channels Make informed decisions with unified analytics across all platforms *** ## Prerequisites Before starting your multi-channel integration journey, ensure you have: Sign up for a StateSet account at [StateSet.com/sign-up](https://StateSet.com/sign-up) and obtain your API credentials from the dashboard: [app.StateSet.com/settings/api-keys](https://app.StateSet.com/settings/api-keys) Active seller accounts on the platforms you want to integrate: * TikTok Shop Seller Center account * Amazon Seller Central or Vendor Central account * Walmart Marketplace seller account * Additional platform accounts as needed * Node.js 16+ or Python 3.8+ * Git for version control * Your preferred code editor * Postman or similar API testing tool * Product catalog with SKUs, descriptions, and images * Warehouse/fulfillment setup * Customer service processes * Return/refund policies for each channel *** ## Channel Overview ### Supported Channels StateSet supports integration with major e-commerce platforms, each with unique features and requirements: | Channel | Type | Key Features | Best For | | ---------------------- | ------------------- | ----------------------------------------------------- | --------------------------------------- | | **TikTok Shop** | Social Commerce | Live streaming, short videos, influencer partnerships | Trending products, younger demographics | | **Amazon** | Marketplace | FBA/FBM, Prime eligibility, vast customer base | All product types, fast shipping | | **Walmart** | Marketplace | Competitive pricing, WFS program, trusted brand | Value-focused products, US market | | **Shopify** | Direct-to-Consumer | Full customization, brand control, apps ecosystem | Brand building, customer relationships | | **eBay** | Marketplace/Auction | Auctions, global reach, collectibles | Unique items, international sales | | **Etsy** | Marketplace | Handmade/vintage focus, creative community | Artisan products, crafts | | **Facebook/Instagram** | Social Commerce | Social shopping, targeted ads, shops | Visual products, brand awareness | ### Integration Architecture ```mermaid theme={null} graph TB A[StateSet Platform] --> B[Channel Connector API] B --> C[TikTok Shop API] B --> D[Amazon SP-API] B --> E[Walmart API] B --> F[Shopify API] B --> G[Other Channels] H[Your Store] --> A I[Inventory System] --> A J[Order Management] --> A K[Analytics] --> A style A fill:#f9f,stroke:#333,stroke-width:4px style H fill:#bbf,stroke:#333,stroke-width:2px ``` *** ## TikTok Shop Integration TikTok Shop has rapidly become a major player in social commerce, combining entertainment with shopping through short-form videos and live streams. Integrating TikTok Shop with StateSet allows you to tap into this growing marketplace while maintaining centralized control. ### TikTok Shop Setup 1. Visit [TikTok Shop Seller Center](https://seller.tiktok.com) 2. Complete the business verification process 3. Set up your shop profile and policies 4. Configure shipping and return settings Navigate to the API settings in TikTok Shop Seller Center: ```javascript theme={null} // TikTok Shop API Configuration const tiktokConfig = { appKey: process.env.TIKTOK_APP_KEY, appSecret: process.env.TIKTOK_APP_SECRET, shopId: process.env.TIKTOK_SHOP_ID, accessToken: null // Will be set after OAuth }; ``` Implement TikTok Shop OAuth flow: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import axios from 'axios'; import crypto from 'crypto'; class TikTokShopConnector { constructor(config) { this.config = config; this.baseURL = 'https://open-api.tiktokglobalshop.com'; this.StateSet = new StateSetClient(process.env.STATESET_API_KEY); } // Generate signature for TikTok API requests generateSignature(path, params, body = '') { const timestamp = Math.floor(Date.now() / 1000); const signString = [ this.config.appKey, path, timestamp, JSON.stringify(params), body ].join(''); return crypto .createHmac('sha256', this.config.appSecret) .update(signString) .digest('hex'); } // Get OAuth authorization URL getAuthorizationURL() { const state = crypto.randomBytes(16).toString('hex'); const params = new URLSearchParams({ app_key: this.config.appKey, state: state, redirect_uri: process.env.TIKTOK_REDIRECT_URI }); return { url: `https://auth.tiktok-shops.com/oauth/authorize?${params}`, state: state }; } // Exchange authorization code for access token async getAccessToken(code) { const path = '/api/v2/token/get'; const params = { app_key: this.config.appKey, app_secret: this.config.appSecret, auth_code: code, grant_type: 'authorized_code' }; const response = await axios.post( `${this.baseURL}${path}`, params ); if (response.data.code === 0) { this.config.accessToken = response.data.data.access_token; // Store token in StateSet await this.StateSet.channels.updateCredentials({ channel: 'tiktok_shop', credentials: { access_token: response.data.data.access_token, refresh_token: response.data.data.refresh_token, expires_at: new Date(Date.now() + response.data.data.expires_in * 1000) } }); return response.data.data; } throw new Error(`TikTok OAuth failed: ${response.data.message}`); } } ``` ### Product Synchronization Synchronize your product catalog with TikTok Shop while handling platform-specific requirements: ```javascript theme={null} class TikTokProductSync { constructor(connector, StateSet) { this.connector = connector; this.StateSet = StateSet; } // Map StateSet product to TikTok Shop format mapProductToTikTok(product) { return { title: product.name, description: this.formatDescription(product.description), category_id: this.mapCategory(product.category), brand: product.brand || 'Unbranded', images: product.images.map(img => ({ url: img.url })), skus: product.variants.map(variant => ({ seller_sku: variant.sku, price: { amount: variant.price * 100, // TikTok uses cents currency: 'USD' }, inventory: [{ warehouse_id: process.env.TIKTOK_WAREHOUSE_ID, quantity: variant.inventory_quantity }], sales_attributes: this.mapVariantAttributes(variant) })), package_dimensions: { length: product.dimensions?.length || 10, width: product.dimensions?.width || 10, height: product.dimensions?.height || 10, unit: 'CENTIMETER', weight: product.weight || 100, weight_unit: 'GRAM' }, is_cod_allowed: false, delivery_service_ids: [process.env.TIKTOK_DELIVERY_SERVICE_ID] }; } // Sync products from StateSet to TikTok Shop async syncProducts(options = {}) { const { limit = 100, offset = 0 } = options; try { // Fetch products from StateSet const products = await this.StateSet.products.list({ limit, offset, expand: ['variants', 'images'] }); const results = { success: [], failed: [], skipped: [] }; for (const product of products.data) { try { // Check if product should be listed on TikTok if (!product.channels?.includes('tiktok_shop')) { results.skipped.push({ sku: product.sku, reason: 'Not enabled for TikTok Shop' }); continue; } // Map and validate product data const tiktokProduct = this.mapProductToTikTok(product); // Create or update product on TikTok const response = await this.createOrUpdateProduct(tiktokProduct); // Update StateSet with TikTok product ID await this.StateSet.products.update(product.id, { external_ids: { ...product.external_ids, tiktok_shop: response.product_id } }); results.success.push({ sku: product.sku, tiktok_id: response.product_id }); } catch (error) { results.failed.push({ sku: product.sku, error: error.message }); } } // Log sync results await this.StateSet.logs.create({ type: 'channel_sync', channel: 'tiktok_shop', action: 'product_sync', results: results, timestamp: new Date() }); return results; } catch (error) { logger.error('Product sync failed:', error); throw error; } } // Format description for TikTok requirements formatDescription(description) { // TikTok has specific requirements for product descriptions let formatted = description .replace(/<[^>]*>/g, '') // Remove HTML tags .substring(0, 2000); // Max 2000 characters // Add required disclaimers if needed if (!formatted.includes('shipping')) { formatted += '\n\nShipping: Standard shipping available.'; } return formatted; } // Map categories between platforms mapCategory(StateSetCategory) { const categoryMap = { 'electronics': '6001', 'clothing': '6002', 'home-garden': '6003', 'beauty': '6004', 'sports': '6005', // Add more mappings based on TikTok's category tree }; return categoryMap[StateSetCategory] || '9999'; // Default category } } ``` ### Order Management Handle TikTok Shop orders and sync them with your StateSet order management system: ```javascript theme={null} class TikTokOrderManager { constructor(connector, StateSet) { this.connector = connector; this.StateSet = StateSet; } // Fetch new orders from TikTok Shop async fetchNewOrders() { const path = '/api/orders/search'; const params = { create_time_from: Math.floor((Date.now() - 3600000) / 1000), // Last hour create_time_to: Math.floor(Date.now() / 1000), order_status: 'AWAITING_SHIPMENT', page_size: 100 }; const orders = await this.connector.makeRequest('POST', path, params); for (const tiktokOrder of orders.data.orders) { await this.processOrder(tiktokOrder); } } // Process individual TikTok order async processOrder(tiktokOrder) { try { // Check if order already exists const existingOrder = await this.StateSet.orders.list({ external_id: tiktokOrder.order_id, channel: 'tiktok_shop' }); if (existingOrder.data.length > 0) { return; // Order already processed } // Create order in StateSet const StateSetOrder = await this.StateSet.orders.create({ external_id: tiktokOrder.order_id, channel: 'tiktok_shop', customer: { email: tiktokOrder.buyer_email || `tiktok_${tiktokOrder.buyer_user_id}@example.com`, name: tiktokOrder.recipient_address.name, phone: tiktokOrder.recipient_address.phone }, shipping_address: { line1: tiktokOrder.recipient_address.address_line1, line2: tiktokOrder.recipient_address.address_line2, city: tiktokOrder.recipient_address.city, state: tiktokOrder.recipient_address.state, postal_code: tiktokOrder.recipient_address.zipcode, country: tiktokOrder.recipient_address.country_code }, line_items: tiktokOrder.item_list.map(item => ({ external_id: item.sku_id, sku: item.seller_sku, name: item.product_name, quantity: item.quantity, price: item.sku_original_price / 100, // Convert from cents discount: item.sku_platform_discount / 100 })), subtotal: tiktokOrder.payment_info.sub_total / 100, shipping_cost: tiktokOrder.payment_info.shipping_fee / 100, tax: tiktokOrder.payment_info.tax / 100, total: tiktokOrder.payment_info.total_amount / 100, currency: tiktokOrder.payment_info.currency, payment_status: 'paid', fulfillment_status: 'unfulfilled', tags: ['tiktok_shop', tiktokOrder.order_type], metadata: { tiktok_order_status: tiktokOrder.order_status, tiktok_tracking_number: tiktokOrder.tracking_number, tiktok_carrier: tiktokOrder.shipping_provider } }); // Create webhook for order updates await this.StateSet.webhooks.subscribe({ url: process.env.WEBHOOK_URL, events: [`order.${StateSetOrder.id}.updated`], metadata: { channel: 'tiktok_shop', external_order_id: tiktokOrder.order_id } }); logger.info(`Created order ${StateSetOrder.id} from TikTok order ${tiktokOrder.order_id}`); } catch (error) { logger.error(`Failed to process TikTok order ${tiktokOrder.order_id}:`, error); // Log error for manual review await this.StateSet.logs.create({ type: 'order_sync_error', channel: 'tiktok_shop', order_id: tiktokOrder.order_id, error: error.message, raw_data: tiktokOrder }); } } } ``` ### Live Commerce Integration TikTok Shop's unique live streaming features require special handling: ```javascript theme={null} class TikTokLiveCommerce { constructor(connector, StateSet) { this.connector = connector; this.StateSet = StateSet; } // Create live stream session async createLiveSession(sessionData) { const products = await this.StateSet.products.list({ ids: sessionData.product_ids }); // Register products for live stream const liveProducts = await this.connector.makeRequest( 'POST', '/api/products/live_stream/add', { product_ids: products.data.map(p => p.external_ids.tiktok_shop), session_id: sessionData.session_id } ); // Create campaign in StateSet const campaign = await this.StateSet.campaigns.create({ name: sessionData.name, type: 'live_stream', channel: 'tiktok_shop', start_date: sessionData.start_time, end_date: sessionData.end_time, products: sessionData.product_ids, metadata: { tiktok_session_id: sessionData.session_id, host: sessionData.host_username, expected_viewers: sessionData.expected_viewers } }); return campaign; } // Track live stream performance async trackLiveMetrics(sessionId) { const metrics = await this.connector.makeRequest( 'GET', `/api/live_stream/metrics/${sessionId}` ); await this.StateSet.analytics.create({ type: 'live_stream_metrics', channel: 'tiktok_shop', session_id: sessionId, metrics: { viewers: metrics.viewer_count, engagement_rate: metrics.engagement_rate, conversion_rate: metrics.conversion_rate, revenue: metrics.total_revenue / 100, orders: metrics.order_count, top_products: metrics.top_selling_products }, timestamp: new Date() }); } } ``` *** ## Amazon Integration Amazon remains the largest e-commerce marketplace globally. Integrating with Amazon through their SP-API (Selling Partner API) enables automated inventory management, order processing, and listing optimization. ### Amazon SP-API Setup 1. Go to [Amazon Developer Portal](https://developer.amazonservices.com) 2. Register your application 3. Define your app's data access requirements 4. Complete the approval process Set up your Amazon SP-API configuration: ```javascript theme={null} const amazonConfig = { clientId: process.env.AMAZON_CLIENT_ID, clientSecret: process.env.AMAZON_CLIENT_SECRET, refreshToken: process.env.AMAZON_REFRESH_TOKEN, region: 'na', // na, eu, fe marketplace: 'ATVPDKIKX0DER', // US marketplace ID }; ``` Create an Amazon connector with LWA (Login with Amazon) authentication: ```javascript theme={null} import { SellingPartnerAPI } from 'amazon-sp-api'; import { StateSetClient } from 'StateSet-node'; class AmazonConnector { constructor(config) { this.config = config; this.StateSet = new StateSetClient(process.env.STATESET_API_KEY); this.sp = new SellingPartnerAPI({ region: config.region, refresh_token: config.refreshToken, credentials: { SELLING_PARTNER_APP_CLIENT_ID: config.clientId, SELLING_PARTNER_APP_CLIENT_SECRET: config.clientSecret, }, }); } async testConnection() { try { const markets = await this.sp.callAPI({ operation: 'getMarketplaceParticipations', endpoint: 'sellers', }); logger.info('Connected to Amazon marketplaces:', markets); return true; } catch (error) { logger.error('Amazon connection failed:', error); return false; } } } ``` ### Product Listing Management ```javascript theme={null} class AmazonProductManager { constructor(connector) { this.connector = connector; this.sp = connector.sp; this.StateSet = connector.StateSet; } // Create or update Amazon listing async createListing(product) { const feedDocument = await this.createProductFeed(product); // Submit feed to Amazon const feed = await this.sp.callAPI({ operation: 'createFeed', endpoint: 'feeds', body: { feedType: 'POST_PRODUCT_DATA', marketplaceIds: [this.connector.config.marketplace], inputFeedDocumentId: feedDocument.feedDocumentId, }, }); // Monitor feed processing await this.monitorFeed(feed.feedId); // Update StateSet with Amazon ASIN const catalogItem = await this.getProductBySkU(product.sku); await this.StateSet.products.update(product.id, { external_ids: { ...product.external_ids, amazon_asin: catalogItem.asin, }, }); } // Create product feed XML createProductFeed(product) { const xml = `
1.01 ${this.connector.config.merchantId}
Product 1 Update ${product.sku} ${product.id_type || 'UPC'} ${product.id_value} A_GEN_TAX ${this.sanitizeForAmazon(product.name)} ${product.brand} ${this.sanitizeForAmazon(product.description)} ${product.features[0]} ${product.features[1]} ${product.category} HealthMisc
`; return this.uploadFeedDocument(xml); } // Inventory synchronization async syncInventory() { const inventory = await this.StateSet.inventory.list({ channel: 'amazon', }); const feedItems = inventory.data.map(item => ({ sku: item.sku, quantity: item.available_quantity, fulfillment_center_id: item.warehouse_id || 'DEFAULT', })); const feed = await this.submitInventoryFeed(feedItems); return this.monitorFeed(feed.feedId); } } ``` ### Order Processing ```javascript theme={null} class AmazonOrderProcessor { constructor(connector) { this.connector = connector; this.sp = connector.sp; this.StateSet = connector.StateSet; } // Fetch and process new orders async processNewOrders() { const orders = await this.sp.callAPI({ operation: 'getOrders', endpoint: 'orders', query: { MarketplaceIds: [this.connector.config.marketplace], CreatedAfter: new Date(Date.now() - 3600000).toISOString(), OrderStatuses: ['Unshipped', 'PartiallyShipped'], }, }); for (const amazonOrder of orders.Orders) { await this.createStateSetOrder(amazonOrder); } } // Create order in StateSet async createStateSetOrder(amazonOrder) { // Get order items const orderItems = await this.sp.callAPI({ operation: 'getOrderItems', endpoint: 'orders', path: { orderId: amazonOrder.AmazonOrderId, }, }); const StateSetOrder = await this.StateSet.orders.create({ external_id: amazonOrder.AmazonOrderId, channel: 'amazon', customer: { email: amazonOrder.BuyerEmail || `amazon_${amazonOrder.BuyerInfo?.BuyerName}@marketplace.com`, name: amazonOrder.BuyerInfo?.BuyerName || 'Amazon Customer', }, shipping_address: { line1: amazonOrder.ShippingAddress?.AddressLine1, line2: amazonOrder.ShippingAddress?.AddressLine2, city: amazonOrder.ShippingAddress?.City, state: amazonOrder.ShippingAddress?.StateOrRegion, postal_code: amazonOrder.ShippingAddress?.PostalCode, country: amazonOrder.ShippingAddress?.CountryCode, }, line_items: orderItems.OrderItems.map(item => ({ external_id: item.OrderItemId, sku: item.SellerSKU, asin: item.ASIN, name: item.Title, quantity: parseInt(item.QuantityOrdered), price: parseFloat(item.ItemPrice?.Amount || 0), tax: parseFloat(item.ItemTax?.Amount || 0), })), subtotal: parseFloat(amazonOrder.OrderTotal?.Amount) - parseFloat(amazonOrder.TaxTotal?.Amount || 0), tax: parseFloat(amazonOrder.TaxTotal?.Amount || 0), total: parseFloat(amazonOrder.OrderTotal?.Amount), currency: amazonOrder.OrderTotal?.CurrencyCode, fulfillment_channel: amazonOrder.FulfillmentChannel, metadata: { amazon_order_status: amazonOrder.OrderStatus, is_prime: amazonOrder.IsPrime, is_premium_order: amazonOrder.IsPremiumOrder, shipment_service_level: amazonOrder.ShipmentServiceLevel, }, }); return StateSetOrder; } // Update shipment tracking async updateShipmentTracking(orderId, trackingInfo) { const feed = await this.sp.callAPI({ operation: 'createFeed', endpoint: 'feeds', body: { feedType: 'POST_ORDER_FULFILLMENT_DATA', marketplaceIds: [this.connector.config.marketplace], content: this.createFulfillmentFeed(orderId, trackingInfo), }, }); return this.monitorFeed(feed.feedId); } } ``` ### FBA Integration ```javascript theme={null} class AmazonFBAManager { constructor(connector) { this.connector = connector; this.sp = connector.sp; this.StateSet = connector.StateSet; } // Create FBA shipment async createInboundShipment(products) { // Prepare shipment items const items = products.map(p => ({ SellerSKU: p.sku, QuantityShipped: p.quantity, PrepDetailsList: p.prep_instructions || [], })); // Create shipment plan const plan = await this.sp.callAPI({ operation: 'createInboundShipmentPlan', endpoint: 'fulfillmentInbound', body: { ShipFromAddress: { Name: process.env.WAREHOUSE_NAME, AddressLine1: process.env.WAREHOUSE_ADDRESS, City: process.env.WAREHOUSE_CITY, StateOrProvinceCode: process.env.WAREHOUSE_STATE, PostalCode: process.env.WAREHOUSE_ZIP, CountryCode: 'US', }, InboundShipmentPlanRequestItems: items, }, }); // Create actual shipment for (const shipment of plan.InboundShipmentPlans) { await this.createShipment(shipment); } } // Monitor FBA inventory async getFBAInventory() { const inventory = await this.sp.callAPI({ operation: 'getInventorySummaries', endpoint: 'fbaInventory', query: { marketplaceIds: [this.connector.config.marketplace], details: true, }, }); // Update StateSet inventory levels for (const item of inventory.inventorySummaries) { await this.StateSet.inventory.update({ sku: item.sellerSku, channel: 'amazon_fba', available: item.totalQuantity - item.reservedQuantity, reserved: item.reservedQuantity, inbound: item.inboundQuantity, }); } } } ``` *** ## Walmart Integration Walmart Marketplace is a rapidly growing platform with strict performance requirements. Integration requires careful attention to their API specifications and fulfillment standards. ### Walmart Setup 1. Apply at [Walmart Marketplace](https://marketplace.walmart.com) 2. Complete the approval process 3. Set up your seller profile 4. Configure tax settings and shipping templates Access Walmart Developer Portal: ```javascript theme={null} const walmartConfig = { clientId: process.env.WALMART_CLIENT_ID, clientSecret: process.env.WALMART_CLIENT_SECRET, consumerId: process.env.WALMART_CONSUMER_ID, privateKey: process.env.WALMART_PRIVATE_KEY, keyVersion: process.env.WALMART_KEY_VERSION, }; ``` Walmart uses a unique signature-based authentication: ```javascript theme={null} import crypto from 'crypto'; import { StateSetClient } from 'StateSet-node'; class WalmartConnector { constructor(config) { this.config = config; this.baseURL = 'https://marketplace.walmartapis.com/v3'; this.StateSet = new StateSetClient(process.env.STATESET_API_KEY); } generateSignature(consumerId, privateKey, keyVersion, timestamp) { const stringToSign = `${consumerId}\n${timestamp}\n${keyVersion}`; const sign = crypto.createSign('RSA-SHA256'); sign.update(stringToSign); return sign.sign(privateKey, 'base64'); } getAuthHeaders() { const timestamp = Date.now(); const signature = this.generateSignature( this.config.consumerId, this.config.privateKey, this.config.keyVersion, timestamp ); return { 'WM_CONSUMER.ID': this.config.consumerId, 'WM_CONSUMER.INTIMESTAMP': timestamp, 'WM_SEC.AUTH_SIGNATURE': signature, 'WM_SEC.KEY_VERSION': this.config.keyVersion, 'WM_QOS.CORRELATION_ID': crypto.randomUUID(), 'Content-Type': 'application/json', }; } async makeRequest(method, endpoint, data = null) { const response = await axios({ method, url: `${this.baseURL}${endpoint}`, headers: this.getAuthHeaders(), data, }); return response.data; } } ``` ### Product Management ```javascript theme={null} class WalmartProductManager { constructor(connector) { this.connector = connector; this.StateSet = connector.StateSet; } // Create Walmart listing async createListing(product) { const walmartItem = { Item: [{ sku: product.sku, productIdentifiers: { productIdType: product.id_type || 'UPC', productId: product.id_value, }, MPProduct: { productName: product.name, shortDescription: product.short_description, longDescription: product.description, mainImageUrl: product.images[0]?.url, additionalImageUrl: product.images.slice(1).map(img => img.url), price: { currency: 'USD', amount: product.price, }, shippingWeight: { value: product.weight || 1, unit: 'lb', }, category: this.mapToWalmartCategory(product.category), brand: product.brand, }, }], }; const response = await this.connector.makeRequest( 'POST', '/items', walmartItem ); // Update StateSet with Walmart item ID await this.StateSet.products.update(product.id, { external_ids: { ...product.external_ids, walmart_item_id: response.ItemResponse[0].itemId, }, }); return response; } // Bulk inventory update async updateInventory(inventoryUpdates) { const inventory = { InventoryHeader: { version: '1.4', }, Inventory: inventoryUpdates.map(item => ({ sku: item.sku, quantity: { unit: 'EACH', amount: item.quantity, }, })), }; return this.connector.makeRequest( 'PUT', '/inventory', inventory ); } // Price updates with competitive intelligence async updatePricing(priceUpdates) { const priceFeed = { PriceHeader: { version: '1.7', }, Price: priceUpdates.map(item => ({ sku: item.sku, pricing: [{ currentPrice: { value: { currency: 'USD', amount: item.price, }, }, comparisonPrice: item.compare_at_price ? { value: { currency: 'USD', amount: item.compare_at_price, }, } : undefined, }], })), }; return this.connector.makeRequest( 'PUT', '/price', priceFeed ); } } ``` ### Order Management ```javascript theme={null} class WalmartOrderManager { constructor(connector) { this.connector = connector; this.StateSet = connector.StateSet; } // Fetch new orders async fetchOrders() { const orders = await this.connector.makeRequest( 'GET', '/orders?createdStartDate=' + new Date(Date.now() - 3600000).toISOString() ); for (const order of orders.list.elements.order) { await this.processOrder(order); } } // Process Walmart order async processOrder(walmartOrder) { const StateSetOrder = await this.StateSet.orders.create({ external_id: walmartOrder.purchaseOrderId, channel: 'walmart', customer: { email: walmartOrder.customerEmailId, name: `${walmartOrder.shippingInfo.postalAddress.name}`, phone: walmartOrder.shippingInfo.phone, }, shipping_address: { line1: walmartOrder.shippingInfo.postalAddress.address1, line2: walmartOrder.shippingInfo.postalAddress.address2, city: walmartOrder.shippingInfo.postalAddress.city, state: walmartOrder.shippingInfo.postalAddress.state, postal_code: walmartOrder.shippingInfo.postalAddress.postalCode, country: walmartOrder.shippingInfo.postalAddress.country, }, line_items: walmartOrder.orderLines.orderLine.map(line => ({ external_id: line.lineNumber, sku: line.item.sku, name: line.item.productName, quantity: line.orderLineQuantity.amount, price: line.charges.charge.find(c => c.chargeType === 'PRODUCT').chargeAmount.amount, tax: line.charges.charge.find(c => c.chargeType === 'TAX')?.chargeAmount.amount || 0, })), shipping_method: walmartOrder.shippingInfo.methodCode, metadata: { walmart_order_date: walmartOrder.orderDate, walmart_estimated_delivery: walmartOrder.shippingInfo.estimatedDeliveryDate, walmart_shipping_program: walmartOrder.fulfillment?.shipMethod, }, }); // Acknowledge order await this.acknowledgeOrder(walmartOrder.purchaseOrderId); return StateSetOrder; } // Ship order with tracking async shipOrder(orderId, shipmentData) { const shipment = { orderShipment: { orderLines: { orderLine: shipmentData.lines.map(line => ({ lineNumber: line.lineNumber, orderLineStatuses: { orderLineStatus: [{ status: 'Shipped', statusQuantity: { unitOfMeasurement: 'EACH', amount: line.quantity, }, trackingInfo: { shipDateTime: new Date().toISOString(), carrierName: { carrier: shipmentData.carrier, }, methodCode: shipmentData.method, trackingNumber: shipmentData.tracking_number, }, }], }, })), }, }, }; return this.connector.makeRequest( 'POST', `/orders/${orderId}/shipping`, shipment ); } } ``` ### Walmart Fulfillment Services (WFS) ```javascript theme={null} class WalmartWFSManager { constructor(connector) { this.connector = connector; this.StateSet = connector.StateSet; } // Create WFS inbound shipment async createInboundShipment(items) { const shipment = { inboundOrderId: crypto.randomUUID(), orderType: 'NEW_PRODUCT', preferredCarrier: 'FedEx', estimatedDeliveryDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), inboundOrderItems: items.map(item => ({ sku: item.sku, quantity: item.quantity, itemDetails: { countryOfOrigin: 'US', isHazmat: false, }, })), }; const response = await this.connector.makeRequest( 'POST', '/fulfillment/inbound-shipments', shipment ); // Store shipment details await this.StateSet.shipments.create({ type: 'inbound', channel: 'walmart_wfs', external_id: response.inboundOrderId, items: items, status: 'pending', }); return response; } // Monitor WFS inventory async getWFSInventory() { const inventory = await this.connector.makeRequest( 'GET', '/fulfillment/inventory' ); // Sync with StateSet for (const item of inventory.elements) { await this.StateSet.inventory.update({ sku: item.sku, channel: 'walmart_wfs', available: item.availableQuantity, reserved: item.reservedQuantity, inbound: item.inboundQuantity, }); } } } ``` *** ## Multi-Channel Order Management Centralizing order management across all channels is crucial for operational efficiency and customer satisfaction. StateSet provides a unified order management system that aggregates orders from all channels. ### Unified Order Dashboard ```javascript theme={null} class MultiChannelOrderManager { constructor(StateSet) { this.StateSet = StateSet; this.channels = { tiktok: new TikTokOrderManager(), amazon: new AmazonOrderProcessor(), walmart: new WalmartOrderManager(), shopify: new ShopifyOrderManager(), }; } // Aggregate orders from all channels async syncAllChannels() { const syncResults = await Promise.all([ this.channels.tiktok.fetchNewOrders(), this.channels.amazon.processNewOrders(), this.channels.walmart.fetchOrders(), this.channels.shopify.syncOrders(), ]); return { total_orders: syncResults.reduce((sum, result) => sum + result.count, 0), by_channel: syncResults.map((result, index) => ({ channel: Object.keys(this.channels)[index], count: result.count, errors: result.errors, })), }; } // Intelligent order routing async routeOrder(orderId) { const order = await this.StateSet.orders.get(orderId); // Determine optimal fulfillment location const fulfillmentLocation = await this.determineOptimalFulfillment(order); // Route based on criteria if (order.tags.includes('priority')) { return this.routeToPriorityFulfillment(order, fulfillmentLocation); } else if (order.channel === 'amazon' && order.metadata.is_prime) { return this.routeToFBA(order); } else { return this.routeToStandardFulfillment(order, fulfillmentLocation); } } // Batch order processing async processBatchOrders(orderIds) { const orders = await this.StateSet.orders.list({ ids: orderIds }); // Group by fulfillment method const grouped = orders.data.reduce((acc, order) => { const method = order.fulfillment_method || 'standard'; if (!acc[method]) acc[method] = []; acc[method].push(order); return acc; }, {}); // Process each group const results = await Promise.all( Object.entries(grouped).map(([method, orders]) => this.processFulfillmentGroup(method, orders) ) ); return results; } } ``` ### Order Status Synchronization ```javascript theme={null} class OrderStatusSync { constructor(StateSet) { this.StateSet = StateSet; } // Sync order status back to channels async syncOrderStatus(orderId, newStatus) { const order = await this.StateSet.orders.get(orderId); switch (order.channel) { case 'tiktok_shop': await this.updateTikTokStatus(order, newStatus); break; case 'amazon': await this.updateAmazonStatus(order, newStatus); break; case 'walmart': await this.updateWalmartStatus(order, newStatus); break; case 'shopify': await this.updateShopifyStatus(order, newStatus); break; } // Update StateSet order await this.StateSet.orders.update(orderId, { status: newStatus, status_updated_at: new Date(), }); } // Bulk status updates async bulkStatusUpdate(updates) { const results = await Promise.allSettled( updates.map(update => this.syncOrderStatus(update.orderId, update.status) ) ); return { success: results.filter(r => r.status === 'fulfilled').length, failed: results.filter(r => r.status === 'rejected').map(r => r.reason), }; } } ``` *** ## Inventory Synchronization Real-time inventory synchronization prevents overselling and ensures accurate availability across all channels. ### Centralized Inventory Management ```javascript theme={null} class MultiChannelInventorySync { constructor(StateSet) { this.StateSet = StateSet; this.syncInterval = 300000; // 5 minutes this.channels = ['tiktok_shop', 'amazon', 'walmart', 'shopify']; } // Real-time inventory sync async syncInventory(sku, adjustment) { const inventory = await this.StateSet.inventory.get(sku); // Calculate new available quantity const newQuantity = inventory.available_quantity + adjustment; // Update all channels in parallel const updates = await Promise.allSettled([ this.updateTikTokInventory(sku, newQuantity), this.updateAmazonInventory(sku, newQuantity), this.updateWalmartInventory(sku, newQuantity), this.updateShopifyInventory(sku, newQuantity), ]); // Update StateSet inventory await this.StateSet.inventory.update(sku, { available_quantity: newQuantity, last_sync: new Date(), sync_status: this.determineSyncStatus(updates), }); return updates; } // Buffer stock management async allocateBufferStock(sku) { const inventory = await this.StateSet.inventory.get(sku); const salesVelocity = await this.calculateSalesVelocity(sku); // Allocate buffer based on channel performance const bufferAllocation = { tiktok_shop: Math.ceil(salesVelocity.tiktok * 1.2), amazon: Math.ceil(salesVelocity.amazon * 1.5), // Higher buffer for Amazon walmart: Math.ceil(salesVelocity.walmart * 1.3), shopify: Math.ceil(salesVelocity.shopify * 1.1), }; // Ensure total doesn't exceed available const totalBuffer = Object.values(bufferAllocation).reduce((a, b) => a + b, 0); if (totalBuffer > inventory.available_quantity) { // Proportionally reduce buffers const ratio = inventory.available_quantity / totalBuffer; Object.keys(bufferAllocation).forEach(channel => { bufferAllocation[channel] = Math.floor(bufferAllocation[channel] * ratio); }); } return bufferAllocation; } // Inventory forecasting async forecastInventoryNeeds() { const products = await this.StateSet.products.list({ active: true }); const forecasts = []; for (const product of products.data) { const salesHistory = await this.getSalesHistory(product.sku, 30); // Last 30 days const forecast = { sku: product.sku, current_stock: product.inventory_quantity, avg_daily_sales: salesHistory.average, days_of_stock: Math.floor(product.inventory_quantity / salesHistory.average), reorder_point: salesHistory.average * 7, // 7-day buffer suggested_reorder_quantity: salesHistory.average * 30, // 30-day supply }; if (forecast.current_stock <= forecast.reorder_point) { forecast.action = 'REORDER_NOW'; forecast.urgency = 'HIGH'; } else if (forecast.days_of_stock < 14) { forecast.action = 'REORDER_SOON'; forecast.urgency = 'MEDIUM'; } else { forecast.action = 'MONITOR'; forecast.urgency = 'LOW'; } forecasts.push(forecast); } return forecasts; } } ``` ### Inventory Reconciliation ```javascript theme={null} class InventoryReconciliation { constructor(StateSet) { this.StateSet = StateSet; } // Daily reconciliation process async performReconciliation() { const discrepancies = []; const products = await this.StateSet.products.list(); for (const product of products.data) { // Get inventory from each channel const channelInventory = await Promise.all([ this.getTikTokInventory(product.sku), this.getAmazonInventory(product.sku), this.getWalmartInventory(product.sku), this.getShopifyInventory(product.sku), ]); // Compare with StateSet master inventory const StateSetInventory = await this.StateSet.inventory.get(product.sku); channelInventory.forEach((inv, index) => { if (inv && Math.abs(inv.quantity - StateSetInventory.available_quantity) > 0) { discrepancies.push({ sku: product.sku, channel: ['tiktok', 'amazon', 'walmart', 'shopify'][index], channel_quantity: inv.quantity, StateSet_quantity: StateSetInventory.available_quantity, difference: inv.quantity - StateSetInventory.available_quantity, }); } }); } // Auto-resolve minor discrepancies for (const discrepancy of discrepancies) { if (Math.abs(discrepancy.difference) <= 5) { await this.autoResolveDiscrepancy(discrepancy); } else { await this.flagForManualReview(discrepancy); } } return { total_checked: products.data.length, discrepancies_found: discrepancies.length, auto_resolved: discrepancies.filter(d => Math.abs(d.difference) <= 5).length, manual_review_required: discrepancies.filter(d => Math.abs(d.difference) > 5).length, }; } } ``` *** ## Pricing Strategies Dynamic pricing across channels requires careful consideration of platform fees, competition, and margin requirements. ### Dynamic Pricing Engine ```javascript theme={null} class MultiChannelPricingEngine { constructor(StateSet) { this.StateSet = StateSet; this.channelFees = { tiktok_shop: 0.05, // 5% commission amazon: 0.15, // 15% average referral fee walmart: 0.15, // 15% referral fee shopify: 0.029, // 2.9% + $0.30 transaction fee }; } // Calculate channel-specific pricing async calculateChannelPrices(product, targetMargin = 0.30) { const baseCost = product.cost || 0; const prices = {}; for (const [channel, feeRate] of Object.entries(this.channelFees)) { // Calculate minimum price to achieve target margin const minPrice = baseCost / (1 - targetMargin - feeRate); // Get competitive pricing data const competitorPrices = await this.getCompetitorPrices(product.sku, channel); // Determine optimal price prices[channel] = { minimum: Math.ceil(minPrice * 100) / 100, competitive: competitorPrices.median, recommended: this.calculateOptimalPrice(minPrice, competitorPrices), margin: this.calculateMargin(prices[channel].recommended, baseCost, feeRate), }; } return prices; } // Implement repricing strategies async implementRepricingStrategy(strategy = 'competitive') { const products = await this.StateSet.products.list({ active: true }); for (const product of products.data) { const channelPrices = await this.calculateChannelPrices(product); // Update prices on each channel await Promise.all([ this.updateTikTokPrice(product.sku, channelPrices.tiktok_shop.recommended), this.updateAmazonPrice(product.sku, channelPrices.amazon.recommended), this.updateWalmartPrice(product.sku, channelPrices.walmart.recommended), this.updateShopifyPrice(product.sku, channelPrices.shopify.recommended), ]); // Log pricing changes await this.StateSet.pricing_history.create({ sku: product.sku, timestamp: new Date(), strategy: strategy, prices: channelPrices, }); } } } ``` *** ## Analytics and Reporting Comprehensive analytics across all channels provide insights for optimization and growth. ### Multi-Channel Analytics Dashboard ```javascript theme={null} class MultiChannelAnalytics { constructor(StateSet) { this.StateSet = StateSet; } // Generate comprehensive channel performance report async generateChannelReport(dateRange) { const channels = ['tiktok_shop', 'amazon', 'walmart', 'shopify']; const report = { summary: {}, by_channel: {}, top_products: [], recommendations: [], }; // Aggregate data for each channel for (const channel of channels) { const channelData = await this.getChannelMetrics(channel, dateRange); report.by_channel[channel] = { revenue: channelData.revenue, orders: channelData.order_count, aov: channelData.revenue / channelData.order_count, conversion_rate: channelData.conversion_rate, return_rate: channelData.return_rate, profit_margin: channelData.profit_margin, top_products: channelData.top_products.slice(0, 5), }; } // Calculate summary metrics report.summary = { total_revenue: Object.values(report.by_channel).reduce((sum, ch) => sum + ch.revenue, 0), total_orders: Object.values(report.by_channel).reduce((sum, ch) => sum + ch.orders, 0), average_margin: this.calculateWeightedAverage(report.by_channel, 'profit_margin', 'revenue'), best_channel: this.identifyBestChannel(report.by_channel), }; // Generate recommendations report.recommendations = this.generateRecommendations(report); return report; } // Real-time performance monitoring async monitorPerformance() { const alerts = []; // Check inventory levels const lowStock = await this.checkLowStockItems(); if (lowStock.length > 0) { alerts.push({ type: 'LOW_STOCK', severity: 'HIGH', items: lowStock, action: 'Reorder immediately to prevent stockouts', }); } // Check pricing competitiveness const pricingIssues = await this.checkPricingCompetitiveness(); if (pricingIssues.length > 0) { alerts.push({ type: 'PRICING_ALERT', severity: 'MEDIUM', items: pricingIssues, action: 'Review and adjust pricing to remain competitive', }); } // Check channel performance const performanceIssues = await this.checkChannelPerformance(); performanceIssues.forEach(issue => alerts.push(issue)); return alerts; } } ``` *** ## Best Practices ### 1. **Channel-Specific Optimization** Each platform has unique requirements and best practices: * Use trending sounds and hashtags in product videos * Partner with influencers for live selling events * Optimize for mobile-first shopping experience * Leverage TikTok's algorithm with engaging content * Optimize listings with A+ content * Maintain high seller metrics (>95% positive feedback) * Use FBA for Prime eligibility * Implement aggressive pricing strategies * Focus on competitive pricing * Maintain fast shipping times (less than 2 days) * Use Walmart Fulfillment Services (WFS) * Optimize for Walmart's search algorithm ### 2. **Inventory Management** ```javascript theme={null} // Best practice: Implement safety stock calculations function calculateSafetyStock(sku, leadTime, servicelevel = 0.95) { const dailyDemand = getAverageDailyDemand(sku); const demandStdDev = getDemandStandardDeviation(sku); const zScore = getZScore(servicelevel); // 1.65 for 95% service level return Math.ceil(zScore * Math.sqrt(leadTime) * demandStdDev); } ``` ### 3. **Order Processing Automation** ```javascript theme={null} // Best practice: Implement automated order routing class AutomatedOrderRouter { async routeOrder(order) { const rules = [ { condition: o => o.shipping_speed === 'express', action: 'route_to_nearest_warehouse' }, { condition: o => o.total > 500, action: 'flag_for_fraud_review' }, { condition: o => o.channel === 'amazon' && o.is_prime, action: 'route_to_fba' }, { condition: o => o.items.some(i => i.is_hazmat), action: 'route_to_specialized_fulfillment' }, ]; for (const rule of rules) { if (rule.condition(order)) { return this.executeAction(rule.action, order); } } return this.defaultRouting(order); } } ``` *** ## Troubleshooting ### Common Integration Issues **Problem**: API authentication fails across channels **Solutions**: * Verify API credentials are correctly set in environment variables * Check if tokens have expired and need refresh * Ensure IP whitelisting is configured if required * Validate signature generation for platforms like Walmart ```javascript theme={null} // Debug authentication async function debugAuth(channel) { logger.info(`Testing ${channel} authentication...`); try { const result = await testChannelConnection(channel); logger.info('Success:', result); } catch (error) { logger.error('Auth failed:', error.message); logger.info('Check:', getAuthChecklistForChannel(channel);); } } ``` **Problem**: Inventory levels don't match across channels **Solutions**: * Implement regular reconciliation jobs * Use webhooks for real-time updates * Add buffer stock to prevent overselling * Log all inventory movements for audit trail **Problem**: Orders take too long to process **Solutions**: * Implement parallel processing for bulk operations * Use queue systems for order processing * Optimize API calls with batch operations * Cache frequently accessed data *** ## Complete Implementation Example Here's a complete example bringing together all the concepts: ```javascript theme={null} // main.js - Complete multi-channel integration setup import { StateSetClient } from 'StateSet-node'; import { TikTokShopConnector } from './channels/tiktok'; import { AmazonConnector } from './channels/amazon'; import { WalmartConnector } from './channels/walmart'; import { MultiChannelOrderManager } from './orders/manager'; import { MultiChannelInventorySync } from './inventory/sync'; import { MultiChannelAnalytics } from './analytics/dashboard'; class MultiChannelCommerceSystem { constructor() { this.StateSet = new StateSetClient(process.env.STATESET_API_KEY); this.initializeChannels(); this.setupAutomation(); } async initializeChannels() { // Initialize channel connectors this.channels = { tiktok: new TikTokShopConnector({ appKey: process.env.TIKTOK_APP_KEY, appSecret: process.env.TIKTOK_APP_SECRET, }), amazon: new AmazonConnector({ clientId: process.env.AMAZON_CLIENT_ID, clientSecret: process.env.AMAZON_CLIENT_SECRET, }), walmart: new WalmartConnector({ consumerId: process.env.WALMART_CONSUMER_ID, privateKey: process.env.WALMART_PRIVATE_KEY, }), }; // Test all connections await this.testAllConnections(); } setupAutomation() { // Order sync every 5 minutes setInterval(() => this.syncOrders(), 300000); // Inventory sync every 15 minutes setInterval(() => this.syncInventory(), 900000); // Price optimization daily scheduleDaily(() => this.optimizePricing(), '02:00'); // Analytics report weekly scheduleWeekly(() => this.generateWeeklyReport(), 'Monday', '09:00'); } async syncOrders() { const orderManager = new MultiChannelOrderManager(this.StateSet); const results = await orderManager.syncAllChannels(); logger.info(`Synced ${results.total_orders} orders across all channels`); // Process any alerts if (results.alerts?.length > 0) { await this.handleAlerts(results.alerts); } } async syncInventory() { const inventorySync = new MultiChannelInventorySync(this.StateSet); const results = await inventorySync.performFullSync(); // Check for low stock const lowStock = await inventorySync.checkLowStock(); if (lowStock.length > 0) { await this.createReorderSuggestions(lowStock); } } async optimizePricing() { const pricingEngine = new MultiChannelPricingEngine(this.StateSet); await pricingEngine.implementRepricingStrategy('competitive'); } async generateWeeklyReport() { const analytics = new MultiChannelAnalytics(this.StateSet); const report = await analytics.generateChannelReport({ start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), end: new Date(), }); // Send report to stakeholders await this.emailReport(report); } } // Initialize the system const commerceSystem = new MultiChannelCommerceSystem(); // Express server for webhooks import express from 'express'; const app = express(); app.post('/webhooks/orders', async (req, res) => { const { channel, event, data } = req.body; await commerceSystem.handleOrderWebhook(channel, event, data); res.status(200).send('OK'); }); app.post('/webhooks/inventory', async (req, res) => { const { sku, adjustment } = req.body; await commerceSystem.handleInventoryWebhook(sku, adjustment); res.status(200).send('OK'); }); app.listen(process.env.PORT || 3000, () => { logger.info('Multi-channel commerce system running'); }); ``` *** ## Conclusion Successfully integrating multiple e-commerce channels requires careful planning, robust error handling, and continuous optimization. By following this guide and implementing the provided examples, you'll be able to: * **Centralize operations** across TikTok Shop, Amazon, Walmart, and other platforms * **Automate routine tasks** like inventory sync and order processing * **Optimize performance** with data-driven insights * **Scale efficiently** as your business grows Remember to: * Start with one channel and gradually add others * Monitor performance metrics closely * Keep your integration code modular and maintainable * Stay updated with platform API changes * Implement proper error handling and logging For additional support and resources, visit the [StateSet Documentation](https://docs.StateSet.com) or contact our support team. *** # Order Operations Source: https://docs.stateset.com/guides/order-operations Leverage StateSet to automate and orchestrate order operations across Shopify, NetSuite, DCL, and Gorgias. # StateSet One Agentic Order Operations: Quickstart Guide Welcome to the StateSet One Agentic Order Operations Quickstart Guide. This document is designed for developers and technical teams to understand and utilize the automated workflows built on StateSet (powered by Temporal) that integrate Shopify, NetSuite, DCL (Distribution Alternatives), Gorgias, and other services for e-commerce operations. This guide will walk you through the core automated processes, key API interactions, and data flows, enabling you to manage, monitor, and potentially extend these agentic operations. ## Table of Contents 1. [Introduction](#introduction) 2. [System Architecture Overview](#system-architecture-overview) 3. [Prerequisites](#prerequisites) 4. [Core Workflows & API Interactions](#core-workflows--api-interactions) * [A. Shopify Order Ingestion (`shopifyToNetsuiteWorkflow`)](#a-shopify-order-ingestion-shopifytonetsuiteworkflow) * [B. Order Fulfillment Dispatch (NetSuite to DCL - `netsuiteToDCLWorkflow`)](#b-order-fulfillment-dispatch-netsuite-to-dcl---netsuitetodclworkflow) * [C. Fulfillment & Tracking Updates (DCL to NetSuite & Shopify - `dclFulfillmentWorkflow` / `dclTrackingUpdateWorkflow`)](#c-fulfillment--tracking-updates-dcl-to-netsuite--shopify---dclfulfillmentworkflow--dcltrackingupdateworkflow) * [D. Inbound Logistics: PO/ASN Management](#d-inbound-logistics-poasn-management) * [PO/TO Notification to DCL (`dclPoNotificationWorkflow`)](#poto-notification-to-dcl-dclponotificationworkflow) * [PO Receipt Processing from DCL (`dclPoReceiptWorkflow`)](#po-receipt-processing-from-dcl-dclporeceiptworkflow) * [E. Inventory Synchronization](#e-inventory-synchronization) * [Standard Inventory Sync (`inventorySyncWorkflow`)](#standard-inventory-sync-inventorysyncworkflow) * [Bundle Inventory Sync (`inventoryBundlesSyncWorkflow`)](#bundle-inventory-sync-inventorybundlessyncworkflow) * [F. Returns, Cancellations & Refunds](#f-returns-cancellations--refunds) * [G. Agentic Customer Service (`mienneResponseWorkflow`)](#g-agentic-customer-service-mienneresponseworkflow) 5. [Key Configuration Parameters](#key-configuration-parameters) 6. [Development Environment: Activities & Workflows](#development-environment-activities--workflows) 7. [Error Handling & Monitoring](#error-handling--monitoring) 8. [Troubleshooting Common Issues](#troubleshooting-common-issues) 9. [Support Resources](#support-resources) 10. [Conclusion](#conclusion) *** ## Introduction StateSet One platform orchestrates complex order operations by connecting various e-commerce and backend systems. This automation streamlines processes from order capture to fulfillment, inventory management, and customer service. Key benefits include: * **Automated Order Flow:** Seamlessly move order data from Shopify to NetSuite and then to DCL for fulfillment. * **Real-time Fulfillment Updates:** Keep Shopify and NetSuite synchronized with shipment and tracking information from DCL. * **Inventory Accuracy:** Maintain consistent inventory levels between NetSuite, DCL, and Shopify. * **Efficient Inbound Logistics:** Automate PO/ASN communication with DCL and item receipt processing in NetSuite. * **Agentic Customer Service:** Enhance Gorgias with AI-powered responses and actions via integrations with Recharge and Shopify. * **Centralized Orchestration:** Utilize StateSet (Temporal) for robust, observable, and scalable workflow management. This guide focuses on the API-driven interactions orchestrated by the workflows defined in `workflows.js` and activities in `activities.js`. *** ## System Architecture Overview The core data flow is designed for efficiency and accuracy: ```mermaid theme={null} graph TD Shopify_Orders[Shopify: Paid+Unfulfilled Orders] -->|CRON Job / Webhook| WF_ShopifyToNS(shopifyToNetsuiteWorkflow) WF_ShopifyToNS -->|StateSet.order.create()| StateSet_Order[StateSet: Order Record] WF_ShopifyToNS -->|NetSuite API| NS_SO[NetSuite: Sales Order (Pending Fulfillment)] NS_SO -->|Flag: custbody_sent_to_3pl=F| WF_NSToDCL(netsuiteToDCLWorkflow) WF_NSToDCL -->|NetSuite API: Update custbody_sent_to_3pl=T| NS_SO WF_NSToDCL -->|DCL API| DCL_Batch[DCL: Batch/Shipments Created] DCL_Batch -->|DCL Webhook / Poll| WF_DCLFulfillment(dclFulfillmentWorkflow / dclTrackingUpdateWorkflow) WF_DCLFulfillment -->|NetSuite API| NS_IF_CS[NetSuite: Item Fulfillment + Cash Sale] WF_DCLFulfillment -->|StateSet API| StateSet_Order_Fulfilled(StateSet: Order Status FULFILLED) WF_DCLFulfillment -->|Shopify API| Shopify_Fulfillment[Shopify: Fulfillment w/ Tracking] NS_Inventory[NetSuite: Inventory Levels] -->|Scheduled| WF_InvSync(inventorySyncWorkflow / inventoryBundlesSyncWorkflow) WF_InvSync -->|Shopify API| Shopify_Inventory[Shopify: Inventory Update] NS_PO_TO[NetSuite: PO/TO (Send to DCL)] -->|Flag Trigger| WF_DCLPONotif(dclPoNotificationWorkflow) WF_DCLPONotif -->|DCL API| DCL_ASN[DCL: PO Notification (ASN)] WF_DCLPONotif -->|NetSuite API: Update Flag| NS_PO_TO DCL_POReceipts[DCL: PO Receipts] -->|Scheduled Poll| WF_DCLPOReceipt(dclPoReceiptWorkflow) WF_DCLPOReceipt -->|NetSuite API| NS_ItemReceipt[NetSuite: Item Receipt] Gorgias_Ticket[Gorgias: Customer Ticket] -->|Webhook| WF_MienneResponse(mienneResponseWorkflow) WF_MienneResponse -->|OpenAI/Recharge/Shopify APIs| Gorgias_Response[Gorgias: AI Response/Action] subgraph Email Processing Email_PO[Email: PO Attachment] -->|Parser| StateSet_PO_Email[StateSet.purchaseorder.create()] StateSet_PO_Email -->|NetSuite API| NS_PO_Email[NetSuite: Purchase Order] end ``` *** ## Prerequisites Before implementing or extending these workflows, ensure you have: * **API Credentials:** Access keys and tokens for Shopify, NetSuite, DCL (Distribution Alternatives), Gorgias, and StateSet APIs. * **StateSet Account:** A StateSet account with API key for workflow orchestration. * **Temporal Setup:** Access to the Temporal dashboard for monitoring workflows and activities. * **Environment Variables:** Configure necessary secrets (e.g., API keys) in your deployment environment. * **Development Tools:** Node.js environment for working with workflows.js and activities.js. ## Core Workflows & API Interactions ### A. Shopify Order Ingestion (`shopifyToNetsuiteWorkflow`) This workflow automates the transfer of paid and unfulfilled orders from Shopify to NetSuite. **Trigger:** Shopify webhook on order creation/update or scheduled CRON job. **Purpose:** Convert Shopify Order to NetSuite Sales Order (SO) and tag the order as `SENT_TO_NS`. **Steps:** 1. Fetch new or updated orders from Shopify. 2. Create an order record in StateSet using `StateSet.order.create()`. 3. Transform order data and create a Sales Order in NetSuite (status: Pending Fulfillment). 4. Update Shopify with NetSuite SO ID if needed. **Key API Calls:** * Shopify API: GET /admin/api/2023-01/orders.json * StateSet API: POST /orders * NetSuite API: POST /record/v1/salesOrder **Error Handling:** Retries on API failures; logs to Temporal for monitoring. ### B. Order Fulfillment Dispatch (NetSuite to DCL - `netsuiteToDCLWorkflow`) Dispatches approved Sales Orders from NetSuite to DCL for fulfillment. **Trigger:** NetSuite flag `custbody_sent_to_3pl = F` on Sales Order. **Purpose:** Transform SO and POST to DCL; set `custbody_sent_to_3pl = T`. **Steps:** 1. Query NetSuite for eligible Sales Orders. 2. Transform data to DCL format. 3. POST to DCL API to create batch/shipments. 4. Update NetSuite flag to prevent re-processing. **Key API Calls:** * NetSuite API: GET /record/v1/salesOrder (with search filters) * DCL API: POST /shipments * NetSuite API: PATCH /record/v1/salesOrder/ ### C. Fulfillment & Tracking Updates (DCL to NetSuite & Shopify - `dclFulfillmentWorkflow` / `dclTrackingUpdateWorkflow`) Handles fulfillment confirmations and tracking updates from DCL. **Trigger:** DCL webhook or polling on shipment updates. **Purpose:** Create Item Fulfillment & optional Cash Sale in NetSuite; push tracking to Shopify. **Steps:** 1. Receive fulfillment data from DCL. 2. Create Item Fulfillment in NetSuite. 3. Optionally create Cash Sale if applicable. 4. Update StateSet order status to FULFILLED. 5. Update Shopify with fulfillment and tracking info. **Key API Calls:** * NetSuite API: POST /record/v1/itemFulfillment * StateSet API: PATCH /orders/ * Shopify API: POST /admin/api/2023-01/fulfillments.json ### D. Inbound Logistics: PO/ASN Management #### PO/TO Notification to DCL (`dclPoNotificationWorkflow`) **Trigger:** Flag trigger on NetSuite PO/TO (status: Pending Receipt). **Purpose:** Send ASN (Advance Ship Notice) to DCL. **Steps:** 1. Detect flagged PO/TO in NetSuite. 2. Transform to DCL ASN format. 3. POST to DCL API. 4. Update NetSuite flag. #### PO Receipt Processing from DCL (`dclPoReceiptWorkflow`) **Trigger:** Scheduled poll of DCL PO receipts. **Purpose:** Create Item Receipt in NetSuite, reconcile quantities, close PO if complete. **Steps:** 1. Poll DCL for new receipts. 2. Create Item Receipt in NetSuite. 3. Reconcile and update quantities. 4. Close PO if fully received. ### E. Inventory Synchronization #### Standard Inventory Sync (`inventorySyncWorkflow`) **Trigger:** Scheduled (every 15 minutes). **Purpose:** Pull inventory from NetSuite, bulk update Shopify. **Steps:** 1. Query NetSuite inventory levels. 2. Transform data. 3. Bulk update Shopify inventory. #### Bundle Inventory Sync (`inventoryBundlesSyncWorkflow`) **Trigger:** Scheduled (every 15 minutes + 10 seconds). **Purpose:** Compute bundle availability and update Shopify bundles. **Steps:** 1. Request BOM data from NetSuite. 2. Calculate bundle\_qty = MIN(component\_qty\[]). 3. Update Shopify. ### F. Returns, Cancellations & Refunds This section covers workflows for handling returns, cancellations, and refunds, integrating with Gorgias, Shopify, and other systems. **Trigger:** Gorgias ticket creation, Shopify cancellation request, or manual initiation. **Purpose:** Validate and process returns/cancellations, update relevant systems, and issue refunds. **Steps:** 1. Receive and validate return/cancellation request (e.g., check eligibility within 30 days). 2. Generate customer response and return label (US or CA specific). 3. Create return record in StateSet. 4. Optionally cancel subscriptions. 5. Wait period (e.g., 3 days) for receipt. 6. If conditions met (e.g., instant refund eligible), process refund via Shopify/Recharge. 7. Update NetSuite, DCL if inventory affected. 8. Post updates to Gorgias/Zendesk. **Key API Calls:** * StateSet API: POST /returns * Shopify API: POST /refunds * Gorgias API: POST /tickets//messages **Error Handling:** Validate order status, handle partial refunds, log discrepancies. ### G. Agentic Customer Service (`ResponseWorkflow`) **Trigger:** Webhook from Gorgias on new ticket. **Purpose:** Generate AI-powered responses and actions using OpenAI, Recharge, and Shopify. **Steps:** 1. Receive ticket data. 2. Analyze with OpenAI. 3. Perform actions (e.g., refund, subscription update). 4. Post response to Gorgias. ## Key Configuration Parameters * **API Endpoints:** Configure URLs for Shopify, NetSuite, DCL, etc. * **Credentials:** Secure storage of API keys and tokens. * **Schedules:** CRON expressions for inventory syncs. * **Flags:** Custom fields in NetSuite (e.g., custbody\_sent\_to\_3pl). * **Thresholds:** Inventory warning levels, retry limits. ## Development Environment: Activities & Workflows Workflows are defined in `workflows.js` using Temporal syntax. Activities (API calls, transformations) are in `activities.js`. **Setup:** * Install Temporal SDK: `npm install @temporalio/workflow` * Run worker: `node worker.js` **Extending:** * Add new activities for custom API integrations. * Compose new workflows for additional processes. ## Error Handling & Monitoring * **Retries:** Exponential backoff for transient failures. * **Compensation:** Saga pattern for rollbacks. * **Monitoring:** Temporal UI for workflow visibility; integrate with Grafana/Prometheus. * **Alerts:** Slack/Email notifications on failures. ## Troubleshooting Common Issues * **API Rate Limits:** Implement throttling in activities. * **Data Mismatches:** Validate transformations between systems. * **Webhook Failures:** Check signatures and endpoints. * **Inventory Discrepancies:** Run manual syncs via CLI. ## Support Resources * StateSet Documentation: [docs.StateSet.com](https://docs.StateSet.com) * Temporal Docs: [docs.temporal.io](https://docs.temporal.io) * Support: [support@StateSet.com](mailto:support@StateSet.com) * Community Forum: forum.StateSet.com ## Conclusion This quickstart provides the foundation for leveraging StateSet One for order operations. By automating these workflows, you achieve efficiency, accuracy, and scalability. For custom extensions, contact StateSet support. # Order Settlements Quickstart Source: https://docs.stateset.com/guides/order-settlement Getting started with Order Settlements # Order Settlements Quickstart Guide ## Table of Contents 1. [Introduction](#introduction) 2. [Core Concepts](#core-concepts) 3. [Setting Up Your Environment](#setting-up-your-environment) 4. [StateSet API Integration](#StateSet-api-integration) 5. [TikTok Shop Integration](#tiktok-shop-integration) 6. [Amazon Integration](#amazon-integration) 7. [Shopify Integration](#shopify-integration) 8. [Consolidating Settlement Data](#consolidating-settlement-data) 9. [Reporting and Analytics](#reporting-and-analytics) 10. [Automated Reconciliation](#automated-reconciliation) 11. [Error Handling and Logging](#error-handling-and-logging) 12. [Best Practices and Optimization](#best-practices-and-optimization) ## Introduction This guide demonstrates how to use StateSet's API to manage order settlements across multiple e-commerce platforms: TikTok Shop, Amazon, Shopify, and StateSet's own system. By following this guide, you'll learn how to consolidate settlement data, process it efficiently, and gain insights into your multi-channel e-commerce operations. ## Core Concepts Before diving into the implementation, let's review some core concepts related to order settlements: * **Settlement**: A financial report that summarizes transactions over a specific period, including order revenue, fees, refunds, and adjustments. * **Payout**: The actual transfer of funds from the e-commerce platform to the seller's bank account. * **Reconciliation**: The process of matching settlement data with actual received payments and internal order records. * **Fees**: Charges applied by e-commerce platforms for their services (e.g., referral fees, fulfillment fees). * **Adjustments**: Corrections or changes to settlement amounts due to various factors (e.g., customer claims, charge backs). ## Setting Up Your Environment 1. Sign up for StateSet at [StateSet.com/sign-up](https://StateSet.com/sign-up) 2. Generate an API key in the [StateSet Cloud Console](https://cloud.StateSet.com/api-keys) 3. Install the StateSet Node.js SDK: ```bash theme={null} npm install StateSet-node ``` 4. Set up environment variables: ```bash theme={null} export STATESET_API_KEY=your_api_key_here export TIKTOK_SHOP_API_KEY=your_tiktok_api_key_here export AMAZON_SP_API_KEY=your_amazon_api_key_here export SHOPIFY_API_KEY=your_shopify_api_key_here ``` 5. Initialize the StateSet client: ```javascript theme={null} import { StateSet } from 'StateSet-node'; const client = new StateSet(process.env.STATESET_API_KEY); ``` ## StateSet API Integration First, let's set up the core functionality using StateSet's API: ```javascript theme={null} // Create a new settlement record async function createSettlement(platformName, settlementData) { const settlement = await client.settlements.create({ platform: platformName, settlement_date: settlementData.settlementDate, payout_amount: settlementData.payoutAmount, currency: settlementData.currency, status: 'pending', raw_data: JSON.stringify(settlementData) }); return settlement; } // Update a settlement record async function updateSettlement(settlementId, updateData) { const updatedSettlement = await client.settlements.update(settlementId, updateData); return updatedSettlement; } // Get settlement details async function getSettlement(settlementId) { const settlement = await client.settlements.get(settlementId); return settlement; } // List settlements with filtering async function listSettlements(filters) { const settlements = await client.settlements.list(filters); return settlements; } ``` ## TikTok Shop Integration Now, let's integrate TikTok Shop settlements: ```javascript theme={null} async function fetchTikTokSettlements(startDate, endDate) { const response = await StateSet.tiktokshop.settlements({ start_date: startDate, end_date: endDate }); for (const settlement of response.data.settlements) { await createSettlement('TikTok Shop', { settlementDate: settlement.settlement_date, payoutAmount: settlement.payout_amount, currency: settlement.currency }); } } ``` ## Amazon Integration Integrate Amazon Seller Central settlements: ```javascript theme={null} async function fetchAmazonSettlements(startDate, endDate) { const response = await StateSet.amazon.reports({ operation: 'getReportDocument', endpoint: 'reports', query: { reportTypes: ['GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE'], startDate, endDate } }); for (const settlement of response.reportDocuments) { const settlementDetails = await spApi.download(settlement); await createSettlement('Amazon', { settlementDate: settlementDetails.settlementDate, payoutAmount: settlementDetails.totalAmount, currency: settlementDetails.currency }); } } ``` ## Shopify Integration Integrate Shopify settlements: ```javascript theme={null} async function fetchShopifyPayouts(startDate, endDate) { const payouts = await StateSet.shopify.payouts.list({ date_min: startDate, date_max: endDate }); for (const payout of payouts) { await createSettlement('Shopify', { settlementDate: payout.date, payoutAmount: payout.amount, currency: payout.currency }); } } ``` ## Consolidating Settlement Data Now that we have integrations for each platform, let's create a function to consolidate all settlement data: ```javascript theme={null} async function consolidateSettlements(startDate, endDate) { await fetchTikTokSettlements(startDate, endDate); await fetchAmazonSettlements(startDate, endDate); await fetchShopifyPayouts(startDate, endDate); const consolidatedData = await listSettlements({ start_date: startDate, end_date: endDate }); return consolidatedData; } ``` ## Reporting and Analytics Create summary reports and analytics based on the consolidated data: ```javascript theme={null} async function generateSettlementSummary(startDate, endDate) { const settlements = await consolidateSettlements(startDate, endDate); const summary = { totalPayout: 0, byCurrency: {}, byPlatform: {} }; for (const settlement of settlements) { summary.totalPayout += settlement.payout_amount; if (!summary.byCurrency[settlement.currency]) { summary.byCurrency[settlement.currency] = 0; } summary.byCurrency[settlement.currency] += settlement.payout_amount; if (!summary.byPlatform[settlement.platform]) { summary.byPlatform[settlement.platform] = 0; } summary.byPlatform[settlement.platform] += settlement.payout_amount; } return summary; } ``` ## Automated Reconciliation Implement an automated reconciliation process to match settlements with internal order data: ```javascript theme={null} async function reconcileSettlements(startDate, endDate) { const settlements = await consolidateSettlements(startDate, endDate); const internalOrders = await client.orders.list({ start_date: startDate, end_date: endDate }); const reconciliationResults = []; for (const settlement of settlements) { const matchingOrders = internalOrders.filter(order => order.platform === settlement.platform && order.currency === settlement.currency && new Date(order.created_at) <= new Date(settlement.settlement_date) ); const totalOrderAmount = matchingOrders.reduce((sum, order) => sum + order.total_amount, 0); const discrepancy = settlement.payout_amount - totalOrderAmount; reconciliationResults.push({ settlement_id: settlement.id, expected_amount: totalOrderAmount, actual_amount: settlement.payout_amount, discrepancy, status: Math.abs(discrepancy) < 0.01 ? 'matched' : 'discrepancy_detected' }); } return reconciliationResults; } ``` ## Error Handling and Logging Implement robust error handling and logging: ```javascript theme={null} async function safeApiCall(apiFunction, ...args) { try { return await apiFunction(...args); } catch (error) { logger.error(`API call failed: ${error.message}`); await client.logs.create({ level: 'error', message: `API call to ${apiFunction.name} failed: ${error.message}`, stacktrace: error.stack }); throw error; } } // Usage const settlements = await safeApiCall(consolidateSettlements, startDate, endDate); ``` # Orders Management Quickstart Source: https://docs.stateset.com/guides/orders-quickstart Complete guide to managing orders with StateSet API - from creation to fulfillment # Orders Management Quickstart Guide Welcome to the StateSet Orders Management Quickstart! This comprehensive guide will walk you through building a production-ready order management system using the StateSet API. You'll learn how to handle the complete order lifecycle, from creation through fulfillment and delivery. Imagine you're an e-commerce business selling products through your online store, marketplaces, and physical locations. You need to efficiently manage orders, keep track of inventory, and make sure your customers get their products on time, no matter where they ordered them from. StateSet helps you achieve this with its powerful DOM features. ## Table of Contents 1. [Introduction](#introduction) 2. [Getting Started](#getting-started) 3. [Core Concepts of DOM](#core-concepts-of-dom) 4. [API Walkthrough: End-to-End DOM Workflow](#api-walkthrough-end-to-end-dom-workflow) * [Workflow 1: Order Capture and Routing](#workflow-1-order-capture-and-routing) * [Workflow 2: Inventory Management and Allocation](#workflow-2-inventory-management-and-allocation) * [Workflow 3: Fulfillment](#workflow-3-fulfillment) * [Workflow 4: Cross-Channel Synchronization](#workflow-4-cross-channel-synchronization) * [Workflow 5: Reporting and Analytics](#workflow-5-reporting-and-analytics) 5. [Integration with Other Systems](#integration-with-other-systems) 6. [Real-Time Order Monitoring](#real-time-order-monitoring) 7. [Error Handling and Logging](#error-handling-and-logging) 8. [Troubleshooting and Maintenance](#troubleshooting-and-maintenance) 9. [Support Resources](#support-resources) 10. [Conclusion](#conclusion) *** ## Introduction Distributed Order Management (DOM) is crucial for businesses managing orders across multiple channels and fulfillment locations. StateSet One provides a powerful API that simplifies DOM workflows, allowing you to manage your entire operation efficiently. **What You'll Learn:** * How to set up your StateSet environment and use the SDK. * Core DOM concepts, including order management, inventory control, and fulfillment. * How to use the StateSet API to manage your order process from start to finish. * Strategies for cross-channel synchronization and real-time monitoring. * How to handle errors and integrate with other systems. *** ## Prerequisites Before you begin, ensure you have: * A StateSet account ([Sign up here](https://StateSet.com/sign-up)) * API credentials from the [StateSet Cloud Console](https://cloud.StateSet.com/api-keys) * Node.js 16+ installed * Basic understanding of REST APIs and JavaScript/TypeScript * Your eCommerce platform credentials (if integrating) ## Getting Started Install the StateSet SDK and required dependencies: ```bash theme={null} npm install StateSet-node dotenv # or yarn add StateSet-node dotenv ``` Create a `.env` file in your project root: ```bash theme={null} # StateSet Configuration STATESET_API_KEY=sk_live_your_actual_key_here STATESET_ENVIRONMENT=production # Webhook Configuration (optional) WEBHOOK_SECRET=whsec_J7xK9mP3nQ5rS8tU... WEBHOOK_URL=https://api.yourstore.com/webhooks/StateSet # Integration Keys (if applicable) SHOPIFY_API_KEY=shpat_c7e4b2f1a... STRIPE_API_KEY=sk_live_your_stripe_key_here ``` Create a robust client with error handling and retry logic: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import winston from 'winston'; import dotenv from 'dotenv'; dotenv.config(); // Configure structured logging const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), transports: [ new winston.transports.File({ filename: 'orders.log' }), new winston.transports.Console({ format: winston.format.simple() }) ] }); class OrderManagementClient { constructor() { this.logger = logger; this.client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.STATESET_ENVIRONMENT, maxRetries: 3, timeout: 30000 }); this.initializeWebhooks(); } async verifyConnection() { try { const health = await this.client.health.check(); this.logger.info('Successfully connected to StateSet API', { status: health.status, timestamp: new Date().toISOString() }); return true; } catch (error) { this.logger.error('StateSet API connection failed', { error: error.message, stack: error.stack }); throw new Error('Unable to connect to StateSet API'); } } async initializeWebhooks() { if (process.env.WEBHOOK_URL) { try { await this.client.webhooks.create({ url: process.env.WEBHOOK_URL, events: [ 'order.created', 'order.updated', 'order.fulfilled', 'inventory.updated' ], secret: process.env.WEBHOOK_SECRET }); this.logger.info('Webhooks configured successfully', { url: process.env.WEBHOOK_URL }); } catch (error) { this.logger.warn('Webhook configuration failed', { error: error.message, url: process.env.WEBHOOK_URL }); } } } } // Initialize and verify connection const orderClient = new OrderManagementClient(); await orderClient.verifyConnection(); ``` *** ## Core Concepts of DOM Before diving into the API, it's important to understand the key concepts behind a Distributed Order Management system. Here is a simplified view of the process: ```mermaid theme={null} graph LR A[Order] --> B(Order Management); B --> C{Inventory Management}; C --> D[Fulfillment]; D --> E(Cross-Channel Sync); E --> F(Reporting & Analytics); ``` * **Order Management:** This encompasses the entire lifecycle of an order, from the moment a customer places it to its successful delivery. This includes capturing the order, routing, tracking status, and handling any modifications. *Why is it important?* Centralized order management improves efficiency by managing all orders in one platform. It also enhances the customer experience by providing accurate and timely information. * **Inventory Management:** This involves tracking and managing inventory levels across multiple locations. Accurate inventory data is key to ensuring products are available when they are needed, minimizing stockouts or overstocks. *Why is it important?* Proper inventory control is needed to fulfill orders and make sure your products are available. It also helps prevent delays in fulfillment. * **Fulfillment Orchestration:** This is the process of coordinating and executing the fulfillment of orders. It includes selecting the right fulfillment locations, picking and packing items, and shipping them to the customer. *Why is it important?* Proper fulfillment orchestration helps ensure products get to your customer quickly and efficiently. * **Cross-Channel Synchronization:** This ensures that order status and inventory levels are consistent across all sales channels. This will help create a seamless experience for the customers. *Why is it important?* Without it, inconsistencies will frustrate customers. For example, a customer could order an item online and find out it is out of stock at the physical store. * **Reporting and Analytics:** This provides insights into order trends, fulfillment performance, and inventory management. It enables data-driven decision-making and optimization of the overall process. *Why is it important?* Analysis of your data will allow you to make more informed decisions about your business. Understanding these core components will be essential as we explore the StateSet API and its functionalities. *** ## API Walkthrough: End-to-End DOM Workflow Let's dive into the end-to-end workflow with the StateSet API. ### Workflow 1: Order Capture and Routing In this section, we'll cover capturing orders from various sources and intelligently routing them to the best fulfillment location. #### Example 1: Capture an Order ```javascript theme={null} async function captureOrder(orderData) { try { let order; switch(orderData.type) { case 'standard': // See https://docs.StateSet.com/StateSet-commerce-api-reference/orders/create for details on the create order endpoint order = await client.order.create({ source: orderData.channel, channel_order_id: orderData.channelOrderId, customer: orderData.customer, line_items: orderData.lineItems, total_price: orderData.totalPrice, currency: orderData.currency, shipping_address: orderData.shippingAddress, status: 'received' }); break; case 'pre-order': order = await createPreOrder(orderData); break; case 'backorder': order = await createBackOrder(orderData); break; case 'subscription': order = await createSubscriptionOrder(orderData); break; default: throw new Error('Unsupported order type'); } logger.info("Order Created:", order); return order; } catch (error) { logger.error("Error capturing order:", error); throw error; } } const order = await captureOrder({ type: 'standard', channel: 'web', channelOrderId: 'WEB-001', customer: { id: 'cust_001' }, lineItems: [ { product_id: 'prod_001', quantity: 2, price: 20, weight: 1, length: 5, width: 5, height: 5 }, { product_id: 'prod_002', quantity: 1, price: 30, weight: 2, length: 10, width: 10, height: 10 } ], totalPrice: 70, currency: 'USD', shippingAddress: { street: '123 Main St', city: 'Anytown', state: 'CA', zip: '12345' } }) ``` This function demonstrates how to capture an order using the `client.order.create()` method. The order details include customer information, line items, shipping address, and the source channel. This captures data from different types of orders, and can be easily expanded to include different order scenarios. #### Example 2: Route an Order ```javascript theme={null} async function routeOrder(orderId) { try { // See https://docs.StateSet.com/StateSet-commerce-api-reference/orders/get for details const order = await client.order.get(orderId); const fulfillmentLocations = await client.location.list({ type: 'fulfillment' }); if (!order || !fulfillmentLocations.length) { throw new Error('Invalid order or no fulfillment locations available'); } // Placeholder: This is where you would use a machine learning algorithm to predict the best fulfillment location const mlPrediction = { confidence: 0.95, locationScores: fulfillmentLocations.reduce((acc, location) => { acc[location.id] = Math.random(); return acc; }, {}) } const inventoryLevels = await getInventoryLevels(order.line_items.map(item => item.product_id)); const shippingRates = await getShippingRates(order); const optimalLocation = determineOptimalLocation(order, fulfillmentLocations, mlPrediction, shippingRates, inventoryLevels); if (!optimalLocation) { throw new Error('Unable to determine optimal fulfillment location'); } // See https://docs.StateSet.com/StateSet-commerce-api-reference/orders/update for details const updatedOrder = await client.order.update(orderId, { assigned_location: optimalLocation.id, status: 'routed', routing_metadata: { prediction_confidence: mlPrediction.confidence, selected_shipping_rate: optimalLocation.selectedRate } }); await logRoutingDecision(orderId, optimalLocation, mlPrediction); logger.info("Order Routed:", updatedOrder); return { optimalLocation, updatedOrder }; } catch (error) { logger.error(`Error routing order ${orderId}:`, error); await client.order.update(orderId, { status: 'routing_failed' }); throw error; } } function determineOptimalLocation(order, locations, mlPrediction, shippingRates, inventoryLevels) { const scoredLocations = locations.map(location => { const inventoryScore = calculateInventoryScore(location, order, inventoryLevels); const shippingScore = calculateShippingScore(location, shippingRates); const mlScore = mlPrediction.locationScores[location.id] || 0; const fulfillmentCost = estimateFulfillmentCost(location, order); const totalScore = (inventoryScore * 0.4) + (shippingScore * 0.3) + (mlScore * 0.2) - (fulfillmentCost * 0.1); return { ...location, score: totalScore, selectedRate: shippingRates[location.id].cheapestRate }; }); return scoredLocations.reduce((best, current) => current.score > best.score ? current : best , scoredLocations[0]); } function calculateInventoryScore(location, order, inventoryLevels) { return order.line_items.reduce((score, item) => { const availability = inventoryLevels[location.id]?.[item.product_id] || 0; return score + (availability >= item.quantity ? 1 : 0); }, 0) / order.line_items.length; } function calculateShippingScore(location, shippingRates) { const locationRates = shippingRates[location.id]; const cheapestRate = locationRates.cheapestRate; const fastestRate = locationRates.fastestRate; return 1 - (cheapestRate.price / fastestRate.price); } function estimateFulfillmentCost(location, order) { // Simplified cost estimation const baseCost = location.fulfillmentCostFactor || 1; return baseCost * order.line_items.reduce((total, item) => total + item.quantity, 0); } async function getShippingRates(order) { try { const carriers = await client.carrier.list(); const fulfillmentLocations = await client.location.list({ type: 'fulfillment' }); const rates = {}; for (const location of fulfillmentLocations) { const locationRates = await Promise.all(carriers.map(carrier => carrier.getRates({ origin: location.address, destination: order.shipping_address, packages: convertOrderToPackages(order) }) )); const flatRates = locationRates.flatMap(rate => rate); rates[location.id] = { allRates: flatRates, cheapestRate: flatRates.reduce((min, rate) => rate.price < min.price ? rate : min), fastestRate: flatRates.reduce((fastest, rate) => rate.deliveryDays < fastest.deliveryDays ? rate : fastest) }; } return rates; } catch (error) { logger.error("Error fetching shipping rates:", error); throw error } } function convertOrderToPackages(order) { // Simplified conversion - in reality, this would involve a more complex packing algorithm return [{ weight: order.line_items.reduce((total, item) => total + (item.weight * item.quantity), 0), dimensions: { length: Math.max(...order.line_items.map(item => item.length)), width: Math.max(...order.line_items.map(item => item.width)), height: Math.max(...order.line_items.map(item => item.height)) } }]; } async function getInventoryLevels(productIds) { const inventoryRecords = await client.inventory.list({ product_id: { in: productIds } }); return inventoryRecords.reduce((acc, record) => { acc[record.location_id] = acc[record.location_id] || {}; acc[record.location_id][record.product_id] = record.available_quantity; return acc; }, {}); } async function logRoutingDecision(orderId, optimalLocation, mlPrediction) { await client.log.create({ type: 'order_routing', order_id: orderId, selected_location: optimalLocation.id, ml_confidence: mlPrediction.confidence, routing_score: optimalLocation.score }); } // Example usage const routedOrder = await routeOrder(order.id); logger.info("Routed Order:", routedOrder); ``` This function illustrates a more complex process, using a combination of inventory data, shipping rates, and an ML prediction (placeholder) to determine the optimal fulfillment location for the order. It includes placeholders for you to expand to include your own logic. This helps to understand the decision making process that goes into routing. ### Workflow 2: Inventory Management and Allocation This section focuses on managing inventory levels, allocating stock to orders, and rebalancing inventory across locations. #### Example 1: Get a Global Inventory View ```javascript theme={null} async function getGlobalInventory(productId) { try { const inventoryList = await client.inventory.list({ product_id: productId }); const globalInventory = inventoryList.reduce((acc, inv) => { acc[inv.location_id] = { quantity: inv.quantity, type: inv.inventory_type, // 'owned', 'dropship', or 'jit' safetyStock: inv.safety_stock_level }; return acc; }, {}); logger.info("Global Inventory:", globalInventory); return globalInventory; } catch (error) { logger.error("Error fetching global inventory:", error); throw error; } } //Example of use const globalInventory = await getGlobalInventory('prod_001') ``` This function retrieves a global view of inventory for a specific product across all locations, using the `client.inventory.list()` method. This will give you a snapshot of all the inventory, including the type and safety stock levels. #### Example 2: Allocate Inventory for an Order ```javascript theme={null} async function allocateInventory(orderId) { let allocatedItems = []; try { const order = await client.order.get(orderId); const allocationResults = await Promise.all(order.line_items.map(async (item) => { const allocation = await determineOptimalAllocation(item, order.assigned_location); return { item, allocation }; })); for (const { item, allocation } of allocationResults) { for (const alloc of allocation) { if (alloc.quantity > 0) { await client.inventory.allocate({ product_id: item.product_id, location_id: alloc.location_id, quantity: alloc.quantity, allocation_type: alloc.type, order_id: orderId, item_id: item.id }); allocatedItems.push({ item_id: item.id, product_id: item.product_id, allocated_quantity: alloc.quantity, location_id: alloc.location_id, allocation_type: alloc.type }); } } } const fullyAllocated = allocatedItems.every(ai => ai.allocated_quantity === order.line_items.find(li => li.id === ai.item_id).quantity ); await client.order.update(orderId, { status: fullyAllocated ? 'fully_allocated' : 'partially_allocated', inventory_allocations: allocatedItems }); await logAllocationResult(orderId, allocatedItems, fullyAllocated); logger.info("Allocation Results:", { orderId, allocatedItems, fullyAllocated }); return { orderId, allocatedItems, fullyAllocated }; } catch (error) { logger.error(`Error allocating inventory for order ${orderId}:`, error); await client.order.update(orderId, { status: 'allocation_failed', allocation_error: error.message }); throw error; } } async function determineOptimalAllocation(item, preferredLocation) { const inventory = await getInventoryLevels(item.product_id); const reservations = await getActiveReservations(item.product_id); const safetyStockLevels = await getSafetyStockLevels(item.product_id); let remainingQuantity = item.quantity; let allocations = []; // Try to allocate from the preferred location first if (inventory[preferredLocation]) { const preferredAllocation = allocateFromLocation( preferredLocation, remainingQuantity, inventory[preferredLocation], reservations[preferredLocation], safetyStockLevels[preferredLocation] ); if (preferredAllocation.quantity > 0) { allocations.push(preferredAllocation); remainingQuantity -= preferredAllocation.quantity; } } // If we couldn't fully allocate from the preferred location, try others if (remainingQuantity > 0) { for (const [locationId, quantity] of Object.entries(inventory)) { if (locationId === preferredLocation) continue; const allocation = allocateFromLocation( locationId, remainingQuantity, quantity, reservations[locationId], safetyStockLevels[locationId] ); if (allocation.quantity > 0) { allocations.push(allocation); remainingQuantity -= allocation.quantity; if (remainingQuantity === 0) break; } } } // If we still couldn't allocate everything, create a backorder if (remainingQuantity > 0) { allocations.push({ location_id: 'backorder', quantity: remainingQuantity, type: 'backorder' }); } return allocations; } function allocateFromLocation(locationId, requiredQuantity, availableQuantity, reservations, safetyStock) { const effectiveQuantity = Math.max(availableQuantity - reservations - safetyStock, 0); const allocatedQuantity = Math.min(requiredQuantity, effectiveQuantity); return { location_id: locationId, quantity: allocatedQuantity, type: allocatedQuantity > 0 ? 'standard' : 'none' }; } async function getActiveReservations(productId) { const reservations = await client.reservation.list({ product_id: productId, status: 'active' }); return reservations.reduce((acc, reservation) => { acc[reservation.location_id] = (acc[reservation.location_id] || 0) + reservation.quantity; return acc; }, {}); } async function getSafetyStockLevels(productId) { const safetyStockRecords = await client.safetyStock.list({ product_id: productId }); return safetyStockRecords.reduce((acc, record) => { acc[record.location_id] = record.quantity; return acc; }, {}); } async function logAllocationResult(orderId, allocatedItems, fullyAllocated) { await client.log.create({ type: 'inventory_allocation', order_id: orderId, allocated_items: allocatedItems, fully_allocated: fullyAllocated, timestamp: new Date().toISOString() }); } //Example of use const allocatedOrder = await allocateInventory(order.id) logger.info("Allocated order:", allocatedOrder); ``` This code shows how inventory is allocated to an order, based on the preferred location and available inventory. This function also demonstrates how to allocate from other locations if the primary location does not have sufficient stock. #### Example 3: Rebalance Inventory ````javascript theme={null} async function rebalanceInventory() { const rebalancingLog = []; try { const inventory = await client.inventory.list(); const locations = await client.location.list(); const salesVelocity = await getSalesVelocityByLocation(); const seasonalTrends = await getSeasonalTrends(); const shippingCosts = await getShippingCostMatrix(); const storageCapacity = await getStorageCapacityByLocation(); const rebalancingPlan = generateRebalancingPlan( inventory, locations, salesVelocity, seasonalTrends, shippingCosts, storageCapacity ); for (const transfer of rebalancingPlan) { try { await client.inventory.transfer(transfer); rebalancingLog.push({ status: 'success', transfer: transfer }); } catch (transferError) { logger.error(`Error executing transfer:`, transferError); rebalancingLog.push({ status: 'failed', transfer: transfer, error: transferError.message }); } } const successfulTransfers = rebalancingLog.filter(log => log.status === 'success').length; logger.info(`Inventory rebalancing completed. ${successfulTransfers}/${rebalancingPlan.length} transfers successful.`); await logRebalancingResult(rebalancingLog); return { totalTransfers: rebalancingPlan.length, successfulTransfers: successfulTransfers, rebalancingLog: rebalancingLog }; } catch (error) { logger.error("Error in inventory rebalancing process:", error); await logRebalancingError(error); throw error; } } function generateRebalancingPlan(inventory, locations, salesVelocity, seasonalTrends, shippingCosts, storageCapacity) { const rebalancingPlan = []; // Group inventory by product const productInventory = groupInventoryByProduct(inventory); for (const [productId, productLocations] of Object.entries(productInventory)) { const totalInventory = sum(Object.values(productLocations)); const totalSalesVelocity = sum(Object.values(salesVelocity[productId] || {})); if (totalSalesVelocity === 0) continue; // Skip products with no sales const idealDistribution = calculateIdealDistribution( productId, totalInventory, locations, salesVelocity, seasonalTrends, storageCapacity ); for (const [fromLocation, fromQuantity] of Object.entries(productLocations)) { const idealQuantity = idealDistribution[fromLocation] || 0; const difference = fromQuantity - idealQuantity; if (difference > 0) { // This location has excess inventory for (const [toLocation, toIdealQuantity] of Object.entries(idealDistribution)) { if (productLocations[toLocation] < toIdealQuantity) { const transferQuantity = Math.min(difference, toIdealQuantity - productLocations[toLocation]); if (transferQuantity > 0 && isTransferCostEffective(productId, fromLocation, toLocation, transferQuantity, shippingCosts)) { rebalancingPlan.push({ product_id: productId, from_location: fromLocation, to_location: toLocation, quantity: transferQuantity }); productLocations[fromLocation] -= transferQuantity; productLocations[toLocation] = (productLocations[toLocation] || 0) + transferQuantity; } } } } } } return rebalancingPlan; } function calculateIdealDistribution(productId, totalInventory, locations, salesVelocity, seasonalTrends, storageCapacity) { const distribution = {}; const totalSalesVelocity = sum(Object.values(salesVelocity[productId] || {})); for (const location of locations) { const locationSalesVelocity = salesVelocity[productId]?.[location.id] || 0; const seasonalFactor = seasonalTrends[productId]?.[location.id] || 1; const adjustedSalesVelocity = locationSalesVelocity * seasonalFactor; let idealQuantity = Math.round((adjustedSalesVelocity / totalSalesVelocity) * totalInventory); idealQuantity = Math.min(idealQuantity, storageCapacity[location.id]); // Respect storage capacity distribution[location.id] = idealQuantity; } return distribution; } function isTransferCostEffective(productId, fromLocation, toLocation, quantity, shippingCosts) { const transferCost = shippingCosts[fromLocation]?.[toLocation] * quantity; const productValue = getProductValue(productId); const transferValueRatio = transferCost / (productValue * quantity); // Consider transfer cost-effective if it's less than 10% of the inventory value return transferValueRatio < 0.1; } function groupInventoryByProduct(inventory) { return inventory.reduce((acc, item) => { acc[item.product_id] = acc[item.product_id] || {}; acc[item.product_id][item.location_id] = item.quantity; return acc; }, {}); } async function getSalesVelocityByLocation() { // Placeholder: In a real implementation you'd use a caching layer const cacheKey = 'sales_velocity'; // let salesVelocity = cache.get(cacheKey); //if (salesVelocity) { // return salesVelocity; //} try { // Assume we're fetching data for the last 90 days const endDate = new Date(); const startDate = new Date(endDate.getTime() - (90 * 24 * 60 * 60 * 1000)); const salesData = await client.analytics.getSales({ start_date: startDate.toISOString(), end_date: endDate.toISOString(), group_by: ['product_id', 'location_id'] }); let salesVelocity = salesData.reduce((acc, sale) => { acc[sale.product_id] = acc[sale.product_id] || {}; acc[sale.product_id][sale.location_id] = sale.quantity / 90; // Daily sales velocity return acc; }, {}); // cache.set(cacheKey, salesVelocity); return salesVelocity; } catch (error) { logger.error('Error fetching sales velocity:', error); throw new Error('Failed to fetch sales velocity data'); } } async function getSeasonalTrends() { // Placeholder: In a real implementation you'd use a caching layer const cacheKey = 'seasonal_trends'; // let seasonalTrends = cache.get(cacheKey); // if (seasonalTrends) { // return seasonalTrends; // } try { // Assume we're fetching seasonal data for the next 90 days const startDate = new Date(); const endDate = new Date(startDate.getTime() + (90 * 24 * 60 * 60 * 1000)); const trendsData = await client.analytics.getSeasonalTrends({ start_date: startDate.toISOString(), end_date: endDate.toISOString(), group_by: ['product_id', 'location_id'] }); let seasonalTrends = trendsData.reduce((acc, trend) => { acc[trend.product_id] = acc[trend.product_id] || {}; acc[trend.product_id][trend.location_id] = trend.seasonal_factor; return acc; }, {}); // cache.set(cacheKey, seasonalTrends); return seasonalTrends; } catch (error) { logger.error('Error fetching seasonal trends:', error); throw new Error('Failed to fetch seasonal trend data'); } } async function getShippingCostMatrix() { // Placeholder: In a real implementation you'd use a caching layer const cacheKey = 'shipping_cost_matrix'; // let shippingCostMatrix = cache.get(cacheKey); // if (shippingCostMatrix) { // return shippingCostMatrix; // } try { const locations = await client.location.list(); let shippingCostMatrix = {}; for (const fromLocation of locations) { shippingCostMatrix[fromLocation.id] = {}; for (const toLocation of locations) { if (fromLocation.id !== toLocation.id) { const shippingRate = await client.shipping.getRate({ from: fromLocation.id, to: toLocation.id, weight: 1, // Assume 1 kg as a base weight volume: 1 // Assume 1 cubic meter as a base volume }); shippingCostMatrix[fromLocation.id][toLocation.id] = shippingRate.cost; } } } // cache.set(cacheKey, shippingCostMatrix); return shippingCostMatrix; } catch (error) { logger.error('Error fetching shipping cost matrix:', error); throw new Error('Failed to fetch shipping cost data'); } } async function getStorageCapacityByLocation() { // Placeholder: In a real implementation you'd use a caching layer const cacheKey = 'storage_capacity'; // let storageCapacity = cache.get(cacheKey); // if (storageCapacity) { // return storageCapacity; //} try { const locations = await client.location.list(); let storageCapacity = {}; for (const location of locations) { const capacityData = await client.warehouse.getCapacity(location.id); storageCapacity[location.id] = capacityData.available_capacity; } // cache.set(cacheKey, storageCapacity); return storageCapacity; } catch (error) { logger.error('Error fetching storage capacity:', error); throw new Error('Failed to fetch storage capacity data'); } } function getProductValue(productId) { return new Promise((resolve, reject) => { // Placeholder: In a real implementation you'd use a caching layer const cacheKey = `product_value_${productId}`; // const cachedValue = cache.get(cacheKey); //if (cachedValue) { // resolve(cachedValue); // } else { client.product.get(productId) .then(product => { const value = product.cost || product.price || 0; // cache.set(cacheKey, value); resolve(value); }) .catch(error => { logger.error(`Error fetching product value for ${productId}:`, error); reject(new Error(`Failed to fetch product value for ${productId}`)); }); // } }); } function sum(numbers) { return numbers.reduce((a, b) => a + b, 0); } async function logRebalancingResult(rebalancingLog) { await client.log.create({ type: 'inventory_rebalancing', result: rebalancingLog, timestamp: new Date().toISOString() }); } async function logRebalancingError(error) { await client.log.create({ type: 'inventory_rebalancing_error', error: error.message, stack: error.stack, timestamp: new Date().toISOString() }); } // Example of use const rebalancedInventory = await rebalanceInventory(); logger.info("Rebalanced Inventory:", rebalancedInventory); ## Support Resources If you encounter issues or have questions, here are some resources that can help you: * **StateSet Documentation:** [https://docs.StateSet.com](https://docs.StateSet.com) * **Community:** [https://StateSet.com/community](https://StateSet.com/community) * **Email Support:** [support@StateSet.com](mailto:support@StateSet.com) ## Complete Order Lifecycle Implementation Here's a production-ready implementation that ties everything together: ```javascript import { StateSetClient } from 'StateSet-node'; import { EventEmitter } from 'events'; class OrderLifecycleManager extends EventEmitter { constructor(apiKey) { super(); this.client = new StateSetClient({ apiKey }); this.setupEventHandlers(); } /** * Process a complete order from creation to delivery */ async processOrder(orderData) { const orderLog = { orderId: null, steps: [], errors: [], startTime: Date.now() }; try { // Step 1: Validate and create order this.emit('step:start', 'order_creation'); const order = await this.createOrderWithValidation(orderData); orderLog.orderId = order.id; orderLog.steps.push({ step: 'created', timestamp: Date.now() }); // Step 2: Check inventory and allocate this.emit('step:start', 'inventory_check'); const allocation = await this.allocateInventoryWithFallback(order); orderLog.steps.push({ step: 'allocated', timestamp: Date.now() }); // Step 3: Route to optimal fulfillment center this.emit('step:start', 'routing'); const routing = await this.routeOrderIntelligently(order, allocation); orderLog.steps.push({ step: 'routed', timestamp: Date.now() }); // Step 4: Create fulfillment order this.emit('step:start', 'fulfillment'); const fulfillment = await this.createFulfillmentWithRetry(order, routing); orderLog.steps.push({ step: 'fulfillment_created', timestamp: Date.now() }); // Step 5: Generate shipping label this.emit('step:start', 'shipping'); const shipping = await this.generateShippingLabel(fulfillment); orderLog.steps.push({ step: 'shipped', timestamp: Date.now() }); // Step 6: Notify customer this.emit('step:start', 'notification'); await this.sendCustomerNotifications(order, shipping); orderLog.steps.push({ step: 'customer_notified', timestamp: Date.now() }); // Success! orderLog.completionTime = Date.now(); orderLog.duration = orderLog.completionTime - orderLog.startTime; this.emit('order:complete', orderLog); return { success: true, order, fulfillment, shipping, log: orderLog }; } catch (error) { orderLog.errors.push({ step: this.currentStep, error: error.message, timestamp: Date.now() }); // Attempt recovery await this.handleOrderError(orderLog, error); this.emit('order:failed', orderLog); throw error; } } async createOrderWithValidation(orderData) { // Validate order data const validation = this.validateOrderData(orderData); if (!validation.valid) { throw new Error(`Order validation failed: ${validation.errors.join(', ')}`); } // Check for duplicate orders const isDuplicate = await this.checkDuplicateOrder(orderData); if (isDuplicate) { throw new Error('Duplicate order detected'); } // Create order with idempotency key const order = await this.client.orders.create({ ...orderData, idempotency_key: this.generateIdempotencyKey(orderData) }); return order; } async allocateInventoryWithFallback(order) { try { // Try primary allocation return await this.client.inventory.allocate({ order_id: order.id, items: order.items }); } catch (error) { if (error.code === 'INSUFFICIENT_INVENTORY') { // Try split fulfillment return await this.attemptSplitFulfillment(order); } throw error; } } async routeOrderIntelligently(order, allocation) { // Get all potential fulfillment locations const locations = await this.client.locations.list({ type: 'fulfillment', active: true }); // Score each location const scoredLocations = await Promise.all( locations.map(async (location) => { const score = await this.scoreLocation(location, order, allocation); return { location, score }; }) ); // Select optimal location const optimal = scoredLocations.reduce((best, current) => current.score > best.score ? current : best ); // Update order with routing await this.client.orders.update(order.id, { fulfillment_location: optimal.location.id, routing_score: optimal.score }); return optimal; } async createFulfillmentWithRetry(order, routing) { let attempts = 0; const maxAttempts = 3; while (attempts < maxAttempts) { try { return await this.client.fulfillment.create({ order_id: order.id, location_id: routing.location.id, priority: this.calculatePriority(order) }); } catch (error) { attempts++; if (attempts >= maxAttempts) throw error; // Wait with exponential backoff await this.sleep(Math.pow(2, attempts) * 1000); } } } async generateShippingLabel(fulfillment) { // Select best carrier const carrier = await this.selectOptimalCarrier(fulfillment); // Generate label const label = await this.client.shipping.createLabel({ fulfillment_id: fulfillment.id, carrier: carrier.id, service: carrier.recommended_service, insurance: fulfillment.total_value > 100 }); return label; } async sendCustomerNotifications(order, shipping) { const notifications = []; // Email notification notifications.push( this.client.notifications.send({ type: 'email', to: order.customer_email, template: 'order_shipped', data: { order_number: order.number, tracking_number: shipping.tracking_number, tracking_url: shipping.tracking_url, estimated_delivery: shipping.estimated_delivery } }) ); // SMS if opted in if (order.customer_phone && order.sms_opt_in) { notifications.push( this.client.notifications.send({ type: 'sms', to: order.customer_phone, message: `Your order ${order.number} has shipped! Track: ${shipping.tracking_url}` }) ); } await Promise.all(notifications); } setupEventHandlers() { this.on('step:start', (step) => { this.currentStep = step; logger.info(`📋 Starting: ${step}`); }); this.on('order:complete', (log) => { logger.info(`✅ Order ${log.orderId} completed in ${log.duration}ms`); }); this.on('order:failed', (log) => { logger.error(`❌ Order ${log.orderId} failed:`, log.errors); }); } // Helper methods validateOrderData(data) { const errors = []; if (!data.customer_email) errors.push('Missing customer email'); if (!data.items || data.items.length === 0) errors.push('No items in order'); if (!data.shipping_address) errors.push('Missing shipping address'); // Validate each item data.items?.forEach((item, index) => { if (!item.sku) errors.push(`Item ${index}: missing SKU`); if (!item.quantity || item.quantity < 1) errors.push(`Item ${index}: invalid quantity`); if (!item.price || item.price < 0) errors.push(`Item ${index}: invalid price`); }); return { valid: errors.length === 0, errors }; } generateIdempotencyKey(orderData) { return `${orderData.source}-${orderData.external_id}-${Date.now()}`; } async checkDuplicateOrder(orderData) { if (!orderData.external_id) return false; const existing = await this.client.orders.list({ external_id: orderData.external_id, created_after: new Date(Date.now() - 24 * 60 * 60 * 1000) // Last 24 hours }); return existing.length > 0; } calculatePriority(order) { // Priority based on shipping method, customer tier, etc. if (order.shipping_method === 'express') return 'high'; if (order.customer_tier === 'vip') return 'high'; if (order.total_value > 500) return 'medium'; return 'normal'; } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Usage example const orderManager = new OrderLifecycleManager(process.env.STATESET_API_KEY); // Process an order const result = await orderManager.processOrder({ source: 'website', external_id: 'WEB-12345', customer_email: 'customer@example.com', customer_phone: '+1234567890', sms_opt_in: true, shipping_method: 'standard', items: [ { sku: 'WIDGET-001', quantity: 2, price: 29.99, name: 'Premium Widget' } ], shipping_address: { name: 'John Doe', street1: '123 Main St', city: 'San Francisco', state: 'CA', zip: '94105', country: 'US' }, billing_address: { // Same as shipping or different } }); logger.info('Order processed:', result); ```` ## Webhook Integration Implement real-time order tracking with webhooks: ```javascript theme={null} import express from 'express'; import crypto from 'crypto'; const app = express(); app.use(express.json()); // Webhook endpoint app.post('/webhooks/StateSet', async (req, res) => { try { // Verify webhook signature const signature = req.headers['x-StateSet-signature']; const payload = JSON.stringify(req.body); const expectedSignature = crypto .createHmac('sha256', process.env.WEBHOOK_SECRET) .update(payload) .digest('hex'); if (signature !== expectedSignature) { return res.status(401).json({ error: 'Invalid signature' }); } // Process webhook event const { event, data } = req.body; switch (event) { case 'order.created': await handleOrderCreated(data); break; case 'order.fulfilled': await handleOrderFulfilled(data); break; case 'inventory.low': await handleLowInventory(data); break; case 'order.delivered': await handleOrderDelivered(data); break; default: logger.info(`Unhandled event: ${event}`); } res.status(200).json({ received: true }); } catch (error) { logger.error('Webhook error:', error); res.status(500).json({ error: 'Webhook processing failed' }); } }); // Event handlers async function handleOrderCreated(order) { logger.info('New order created:', order.id); // Send order confirmation await sendOrderConfirmation(order); // Update external systems await updateCRM(order); // Start fulfillment process await initiateFulfillment(order); } async function handleOrderFulfilled(data) { logger.info('Order fulfilled:', data.order_id); // Update inventory counts await updateInventoryCounts(data.items); // Trigger shipping workflow await createShippingLabel(data); // Notify customer await sendShippingNotification(data); } async function handleLowInventory(data) { logger.info('Low inventory alert:', data); // Check if reorder needed if (data.available < data.reorder_point) { await createPurchaseOrder(data.product_id, data.reorder_quantity); } // Alert operations team await notifyOperationsTeam(data); } async function handleOrderDelivered(data) { logger.info('Order delivered:', data.order_id); // Request customer feedback await sendFeedbackRequest(data); // Update customer lifetime value await updateCustomerMetrics(data); } app.listen(3000, () => { logger.info('Webhook server running on port 3000'); }); ``` ## Error Recovery Patterns Implement robust error handling and recovery: ```javascript theme={null} class OrderErrorRecovery { constructor(client) { this.client = client; this.retryQueue = []; } async handleOrderError(order, error) { const errorHandlers = { 'INSUFFICIENT_INVENTORY': this.handleInsufficientInventory, 'PAYMENT_FAILED': this.handlePaymentFailure, 'INVALID_ADDRESS': this.handleInvalidAddress, 'CARRIER_ERROR': this.handleCarrierError, 'SYSTEM_ERROR': this.handleSystemError }; const handler = errorHandlers[error.code] || this.handleGenericError; return await handler.call(this, order, error); } async handleInsufficientInventory(order, error) { logger.info('Handling insufficient inventory for order:', order.id); // Option 1: Try to allocate from multiple locations const multiLocationAllocation = await this.attemptMultiLocationFulfillment(order); if (multiLocationAllocation.success) { return multiLocationAllocation; } // Option 2: Create backorder const backorder = await this.createBackorder(order, error.items); // Notify customer of delay await this.notifyCustomerOfDelay(order, backorder.estimated_restock_date); return { success: true, type: 'backorder', backorder }; } async handlePaymentFailure(order, error) { logger.info('Handling payment failure for order:', order.id); // Retry payment with fallback method const retryResult = await this.retryPayment(order); if (retryResult.success) { return retryResult; } // Put order on hold await this.client.orders.update(order.id, { status: 'payment_pending', payment_retry_count: (order.payment_retry_count || 0) + 1 }); // Send payment failure notification await this.sendPaymentFailureNotification(order); // Schedule retry this.schedulePaymentRetry(order); return { success: false, type: 'payment_pending' }; } async handleInvalidAddress(order, error) { logger.info('Handling invalid address for order:', order.id); // Try to validate/correct address const correctedAddress = await this.validateAndCorrectAddress(order.shipping_address); if (correctedAddress.valid) { // Update order with corrected address await this.client.orders.update(order.id, { shipping_address: correctedAddress.address }); return { success: true, type: 'address_corrected' }; } // Request address update from customer await this.requestAddressUpdate(order); return { success: false, type: 'awaiting_address_update' }; } async attemptMultiLocationFulfillment(order) { const locations = await this.client.locations.list({ type: 'fulfillment' }); const allocations = []; for (const item of order.items) { const itemAllocations = await this.findInventoryAcrossLocations(item, locations); if (itemAllocations.length === 0) { return { success: false, missing_item: item }; } allocations.push(...itemAllocations); } // Create split fulfillment orders const fulfillmentOrders = await this.createSplitFulfillmentOrders(order, allocations); return { success: true, fulfillment_orders: fulfillmentOrders }; } schedulePaymentRetry(order) { // Add to retry queue this.retryQueue.push({ order_id: order.id, retry_at: new Date(Date.now() + 2 * 60 * 60 * 1000), // 2 hours attempt: order.payment_retry_count || 1 }); } } ``` ## Performance Monitoring Track and optimize your order management performance: ```javascript theme={null} class OrderPerformanceMonitor { constructor(client) { this.client = client; this.metrics = new Map(); } async trackOrderMetrics(order, stage, data = {}) { const metric = { order_id: order.id, stage, timestamp: Date.now(), ...data }; // Store in memory (in production, use a proper metrics service) const key = `${order.id}-${stage}`; this.metrics.set(key, metric); // Send to analytics await this.client.analytics.track({ event: `order.${stage}`, properties: metric }); } async generatePerformanceReport(startDate, endDate) { const report = { period: { start: startDate, end: endDate }, summary: {}, bottlenecks: [], recommendations: [] }; // Get all orders in period const orders = await this.client.orders.list({ created_after: startDate, created_before: endDate }); // Calculate key metrics report.summary = { total_orders: orders.length, average_fulfillment_time: this.calculateAverageFulfillmentTime(orders), on_time_delivery_rate: this.calculateOnTimeDeliveryRate(orders), order_accuracy_rate: this.calculateOrderAccuracyRate(orders), inventory_turnover: await this.calculateInventoryTurnover(startDate, endDate) }; // Identify bottlenecks report.bottlenecks = await this.identifyBottlenecks(orders); // Generate recommendations report.recommendations = this.generateRecommendations(report); return report; } calculateAverageFulfillmentTime(orders) { const fulfilledOrders = orders.filter(o => o.fulfilled_at); if (fulfilledOrders.length === 0) return 0; const totalTime = fulfilledOrders.reduce((sum, order) => { const created = new Date(order.created_at); const fulfilled = new Date(order.fulfilled_at); return sum + (fulfilled - created); }, 0); return totalTime / fulfilledOrders.length / (1000 * 60 * 60); // Hours } async identifyBottlenecks(orders) { const bottlenecks = []; // Check for slow fulfillment locations const locationPerformance = await this.analyzeLocationPerformance(orders); locationPerformance.forEach((perf, location) => { if (perf.avg_fulfillment_time > 48) { // 48 hours bottlenecks.push({ type: 'slow_fulfillment', location, avg_time: perf.avg_fulfillment_time, impact: 'high' }); } }); // Check for inventory issues const inventoryIssues = await this.analyzeInventoryIssues(orders); if (inventoryIssues.stockout_rate > 0.05) { // 5% bottlenecks.push({ type: 'inventory_stockouts', rate: inventoryIssues.stockout_rate, affected_skus: inventoryIssues.affected_skus, impact: 'critical' }); } return bottlenecks; } generateRecommendations(report) { const recommendations = []; // Based on bottlenecks report.bottlenecks.forEach(bottleneck => { if (bottleneck.type === 'slow_fulfillment') { recommendations.push({ priority: 'high', action: 'Optimize fulfillment center operations', location: bottleneck.location, expected_impact: '20-30% reduction in fulfillment time' }); } if (bottleneck.type === 'inventory_stockouts') { recommendations.push({ priority: 'critical', action: 'Adjust reorder points and safety stock levels', affected_skus: bottleneck.affected_skus, expected_impact: '90% reduction in stockouts' }); } }); // Based on general metrics if (report.summary.on_time_delivery_rate < 0.95) { recommendations.push({ priority: 'medium', action: 'Review carrier performance and consider alternatives', current_rate: report.summary.on_time_delivery_rate, target_rate: 0.98 }); } return recommendations; } } // Usage const monitor = new OrderPerformanceMonitor(client); const report = await monitor.generatePerformanceReport( new Date('2024-01-01'), new Date('2024-01-31') ); logger.info('Performance Report:', report); ``` ## Best Practices 1. **Always use idempotency keys** to prevent duplicate orders 2. **Implement proper retry logic** with exponential backoff 3. **Use webhooks** for real-time updates instead of polling 4. **Batch operations** when processing multiple orders 5. **Monitor performance** and set up alerts for anomalies 6. **Validate all input data** before processing 7. **Log everything** for debugging and audit trails 8. **Handle errors gracefully** with customer-friendly messages 9. **Test edge cases** including partial fulfillment and backorders 10. **Keep your integration secure** with proper authentication ## Troubleshooting and Maintenance ### Common Issues and Solutions **Symptoms**: API calls failing with 401 status code **Possible Causes**: * Invalid or expired API key * API key not properly set in environment variables * Using sandbox key in production environment **Solutions**: ```javascript theme={null} // Verify API key is loaded correctly if (!process.env.STATESET_API_KEY) { throw new Error('STATESET_API_KEY environment variable not set'); } // Check API key format const apiKey = process.env.STATESET_API_KEY; if (!apiKey.startsWith('sk_')) { logger.error('Invalid API key format. Keys should start with sk_'); } // Test connection try { const health = await client.health.check(); logger.info('API connection verified', { status: health.status }); } catch (error) { logger.error('API connection failed', { error: error.message }); } ``` **Symptoms**: Unable to create orders **Possible Causes**: * Missing required fields * Duplicate order prevention * Invalid customer data * Invalid shipping address format **Solutions**: * Verify all required fields are provided * Check for duplicate order prevention * Ensure customer data is valid * Validate shipping address format **Symptoms**: Inventory allocation failures **Possible Causes**: * Insufficient inventory * Slow inventory updates * Inaccurate inventory data **Solutions**: * Check real-time inventory levels * Review safety stock settings * Consider enabling backorders * Implement split fulfillment logic **Symptoms**: Slow fulfillment process **Possible Causes**: * Fulfillment center capacity * Inefficient routing algorithm * Carrier API issues * Peak time patterns **Solutions**: * Monitor fulfillment center capacity * Review routing algorithm efficiency * Check for carrier API issues * Analyze peak time patterns **Symptoms**: Webhook events not received **Possible Causes**: * Webhook endpoint not accessible * Incorrect webhook secret configuration * Webhook event logs not available **Solutions**: * Verify webhook endpoint is accessible * Check webhook secret configuration * Review webhook event logs * Implement webhook retry logic ### Performance Debugging **Diagnostic Tools**: ```javascript theme={null} // Performance monitoring class OrderPerformanceMonitor { constructor() { this.metrics = new Map(); } startTimer(operation, orderId) { const key = `${operation}:${orderId}`; this.metrics.set(key, { start: process.hrtime.bigint(), operation, orderId }); return key; } endTimer(key) { const metric = this.metrics.get(key); if (!metric) return; const duration = Number(process.hrtime.bigint() - metric.start) / 1000000; logger.info('Operation completed', { operation: metric.operation, orderId: metric.orderId, duration: `${duration.toFixed(2)}ms` }); // Alert on slow operations if (duration > 5000) { logger.warn('Slow operation detected', { operation: metric.operation, duration: `${duration.toFixed(2)}ms`, threshold: '5000ms' }); } this.metrics.delete(key); return duration; } } ``` **Monitoring and Optimization**: ```javascript theme={null} // Memory monitoring function monitorMemoryUsage() { const usage = process.memoryUsage(); const memoryUsageMB = { rss: Math.round(usage.rss / 1024 / 1024), heapTotal: Math.round(usage.heapTotal / 1024 / 1024), heapUsed: Math.round(usage.heapUsed / 1024 / 1024), external: Math.round(usage.external / 1024 / 1024) }; logger.info('Memory usage', memoryUsageMB); // Alert on high memory usage if (memoryUsageMB.heapUsed > 512) { // 512MB threshold logger.warn('High memory usage detected', memoryUsageMB); // Force garbage collection if available if (global.gc) { global.gc(); logger.info('Forced garbage collection'); } } return memoryUsageMB; } // Schedule memory monitoring setInterval(monitorMemoryUsage, 30000); // Every 30 seconds ``` ## Next Steps * **Implement error handling and logging** to ensure smooth operation and easy troubleshooting * **Set up performance monitoring** to identify bottlenecks and optimize your order management system * **Test your integration thoroughly** to ensure it meets your business needs * **Stay updated** with the latest features and improvements from StateSet ## Troubleshooting and Maintenance ### Common Issues and Solutions **Symptoms**: API calls failing with 401 status code **Possible Causes**: * Invalid or expired API key * API key not properly set in environment variables * Using sandbox key in production environment **Solutions**: ```javascript theme={null} // Verify API key is loaded correctly if (!process.env.STATESET_API_KEY) { throw new Error('STATESET_API_KEY environment variable not set'); } // Check API key format const apiKey = process.env.STATESET_API_KEY; if (!apiKey.startsWith('sk_')) { logger.error('Invalid API key format. Keys should start with sk_'); } // Test connection try { const health = await client.health.check(); logger.info('API connection verified', { status: health.status }); } catch (error) { logger.error('API connection failed', { error: error.message }); } ``` **Symptoms**: Orders failing validation during creation **Common Validation Issues**: * Missing required fields (customer\_email, items, shipping\_address) * Invalid product SKUs or quantities * Incorrect address format * Invalid payment information **Solutions**: ```javascript theme={null} // Comprehensive order validation function validateOrderData(orderData) { const errors = []; // Required fields validation const required = ['customer_email', 'items', 'shipping_address']; required.forEach(field => { if (!orderData[field]) { errors.push(`Missing required field: ${field}`); } }); // Email validation if (orderData.customer_email && !isValidEmail(orderData.customer_email)) { errors.push('Invalid email format'); } // Items validation if (orderData.items && Array.isArray(orderData.items)) { orderData.items.forEach((item, index) => { if (!item.sku) errors.push(`Item ${index}: Missing SKU`); if (!item.quantity || item.quantity < 1) { errors.push(`Item ${index}: Invalid quantity`); } if (!item.price || item.price < 0) { errors.push(`Item ${index}: Invalid price`); } }); } // Address validation if (orderData.shipping_address) { const addr = orderData.shipping_address; const addrRequired = ['line1', 'city', 'state', 'postal_code', 'country']; addrRequired.forEach(field => { if (!addr[field]) { errors.push(`Shipping address missing: ${field}`); } }); } return errors; } function isValidEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); } ``` **Symptoms**: Orders failing due to insufficient inventory **Debugging Steps**: ```javascript theme={null} // Check inventory levels before order creation async function validateInventoryAvailability(items) { const inventoryChecks = await Promise.all( items.map(async (item) => { try { const inventory = await client.inventory.get(item.sku); return { sku: item.sku, requested: item.quantity, available: inventory.available_quantity, sufficient: inventory.available_quantity >= item.quantity }; } catch (error) { return { sku: item.sku, error: error.message, sufficient: false }; } }) ); const insufficient = inventoryChecks.filter(check => !check.sufficient); if (insufficient.length > 0) { logger.warn('Insufficient inventory detected', { insufficient }); throw new Error(`Insufficient inventory for SKUs: ${insufficient.map(i => i.sku).join(', ')}`); } return inventoryChecks; } ``` **Symptoms**: Orders created but payment failing **Common Payment Issues**: * Invalid payment method details * Insufficient funds * Payment processor connectivity issues * Currency mismatch **Debugging and Recovery**: ```javascript theme={null} async function handlePaymentFailure(order, paymentError) { logger.error('Payment processing failed', { orderId: order.id, error: paymentError.message, paymentMethod: order.payment_method?.type }); // Hold the order for manual review await client.orders.update(order.id, { status: 'payment_failed', notes: `Payment failed: ${paymentError.message}`, hold_reason: 'payment_processing_error' }); // Send notification to customer service team await client.notifications.send({ type: 'internal', channel: 'slack', message: `Order ${order.number} payment failed. Requires manual review.`, metadata: { orderId: order.id, customerEmail: order.customer_email, errorCode: paymentError.code } }); // Attempt to retry payment with exponential backoff if (paymentError.retryable) { await schedulePaymentRetry(order.id, paymentError.retryAfter || 300); } } ``` **Symptoms**: Missing or delayed webhook notifications **Debugging Steps**: ```javascript theme={null} // Webhook health check async function verifyWebhookHealth() { try { // Check webhook endpoint status const webhooks = await client.webhooks.list(); for (const webhook of webhooks.data) { logger.info('Webhook status', { id: webhook.id, url: webhook.url, status: webhook.status, lastDelivery: webhook.last_successful_delivery, failureCount: webhook.consecutive_failures }); // Test webhook delivery const testResult = await client.webhooks.test(webhook.id); if (!testResult.success) { logger.warn('Webhook test failed', { webhookId: webhook.id, error: testResult.error }); } } } catch (error) { logger.error('Webhook health check failed', { error: error.message }); } } // Webhook signature verification function verifyWebhookSignature(payload, signature, secret) { const crypto = require('crypto'); const expectedSignature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature, 'hex'), Buffer.from(expectedSignature, 'hex') ); } ``` **Symptoms**: Requests failing with 429 status code **Solutions**: ```javascript theme={null} // Implement intelligent retry with exponential backoff async function makeRequestWithRetry(requestFn, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await requestFn(); } catch (error) { if (error.status === 429) { const retryAfter = parseInt(error.headers['retry-after']) || Math.pow(2, attempt); logger.warn('Rate limit hit, retrying', { attempt, retryAfter, rateLimitRemaining: error.headers['x-ratelimit-remaining'] }); if (attempt === maxRetries) { throw new Error(`Rate limit exceeded after ${maxRetries} attempts`); } await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); } else { throw error; } } } } // Monitor rate limit usage function monitorRateLimit(response) { const remaining = parseInt(response.headers['x-ratelimit-remaining']); const limit = parseInt(response.headers['x-ratelimit-limit']); const resetTime = parseInt(response.headers['x-ratelimit-reset']); const usage = ((limit - remaining) / limit) * 100; if (usage > 80) { logger.warn('High rate limit usage', { usage: `${usage.toFixed(1)}%`, remaining, limit, resetTime: new Date(resetTime * 1000) }); } } ``` **Symptoms**: Order data appearing inconsistent across different API calls **Common Causes**: * Race conditions in concurrent updates * Caching issues * Event ordering problems **Solutions**: ```javascript theme={null} // Implement optimistic locking async function updateOrderWithLocking(orderId, updateData) { const maxRetries = 5; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { // Get current order with version const currentOrder = await client.orders.get(orderId); // Include version in update const updatedOrder = await client.orders.update(orderId, { ...updateData, version: currentOrder.version }); return updatedOrder; } catch (error) { if (error.code === 'VERSION_CONFLICT' && attempt < maxRetries) { // Version conflict - retry with exponential backoff const delay = Math.pow(2, attempt) * 100; await new Promise(resolve => setTimeout(resolve, delay)); continue; } throw error; } } throw new Error(`Failed to update order after ${maxRetries} attempts due to version conflicts`); } // Implement idempotency for critical operations async function createOrderIdempotent(orderData) { const idempotencyKey = `order-${orderData.customer_email}-${Date.now()}`; try { return await client.orders.create(orderData, { headers: { 'Idempotency-Key': idempotencyKey } }); } catch (error) { if (error.code === 'DUPLICATE_REQUEST') { // Return the existing order return await client.orders.get(error.existingResourceId); } throw error; } } ``` ### Performance Debugging **Diagnostic Tools**: ```javascript theme={null} // Performance monitoring class OrderPerformanceMonitor { constructor() { this.metrics = new Map(); } startTimer(operation, orderId) { const key = `${operation}:${orderId}`; this.metrics.set(key, { start: process.hrtime.bigint(), operation, orderId }); return key; } endTimer(key) { const metric = this.metrics.get(key); if (!metric) return; const duration = Number(process.hrtime.bigint() - metric.start) / 1000000; logger.info('Operation completed', { operation: metric.operation, orderId: metric.orderId, duration: `${duration.toFixed(2)}ms` }); // Alert on slow operations if (duration > 5000) { logger.warn('Slow operation detected', { operation: metric.operation, duration: `${duration.toFixed(2)}ms`, threshold: '5000ms' }); } this.metrics.delete(key); return duration; } } ``` **Monitoring and Optimization**: ```javascript theme={null} // Memory monitoring function monitorMemoryUsage() { const usage = process.memoryUsage(); const memoryUsageMB = { rss: Math.round(usage.rss / 1024 / 1024), heapTotal: Math.round(usage.heapTotal / 1024 / 1024), heapUsed: Math.round(usage.heapUsed / 1024 / 1024), external: Math.round(usage.external / 1024 / 1024) }; logger.info('Memory usage', memoryUsageMB); // Alert on high memory usage if (memoryUsageMB.heapUsed > 512) { // 512MB threshold logger.warn('High memory usage detected', memoryUsageMB); // Force garbage collection if available if (global.gc) { global.gc(); logger.info('Forced garbage collection'); } } return memoryUsageMB; } // Schedule memory monitoring setInterval(monitorMemoryUsage, 30000); // Every 30 seconds ``` ### Debug Mode and Logging Enable comprehensive logging for troubleshooting: ```javascript theme={null} // Enhanced debug configuration const debugConfig = { logLevel: process.env.NODE_ENV === 'production' ? 'info' : 'debug', enableRequestLogging: true, enableResponseLogging: true, enablePerformanceLogging: true, sensitiveFields: ['password', 'credit_card', 'ssn'] // Fields to redact }; // Create debug-enabled client const debugClient = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, debug: debugConfig.enableRequestLogging, logger: (message, data) => { // Redact sensitive information const sanitized = redactSensitiveData(data, debugConfig.sensitiveFields); logger.debug(message, sanitized); } }); function redactSensitiveData(data, sensitiveFields) { if (!data || typeof data !== 'object') return data; const sanitized = { ...data }; sensitiveFields.forEach(field => { if (sanitized[field]) { sanitized[field] = '[REDACTED]'; } }); return sanitized; } ``` ### Getting Help If you continue to experience issues: 1. **Check Service Status**: Visit [status.StateSet.com](https://status.StateSet.com) for service health 2. **Review Logs**: Enable debug logging and review application logs 3. **Test in Sandbox**: Reproduce issues in sandbox environment first 4. **Contact Support**: Email [support@StateSet.com](mailto:support@StateSet.com) with: * Error messages and stack traces * Request/response examples * Order IDs and timestamps * Steps to reproduce the issue ## Next Steps Learn advanced inventory management techniques Handle returns and refunds efficiently Optimize your order processing performance Implement robust error handling patterns ## Conclusion Congratulations! You now have a comprehensive understanding of order management with StateSet. You've learned how to: * ✅ Handle the complete order lifecycle * ✅ Implement robust error handling and recovery * ✅ Set up real-time webhook notifications * ✅ Monitor and optimize performance * ✅ Handle complex scenarios like split fulfillment Continue exploring our [API documentation](https://docs.StateSet.com) and join our [community](https://StateSet.com/community) for support and best practices. # Performance Optimization Guide Source: https://docs.stateset.com/guides/performance-optimization Advanced strategies for optimizing StateSet API integrations for maximum performance, scalability, and reliability # Performance Optimization Guide This guide covers advanced strategies for optimizing your StateSet API integrations to achieve maximum performance, scalability, and reliability in production environments. ## Performance Fundamentals Minimize API calls through intelligent batching and caching Optimize HTTP connections and connection pooling Reduce payload sizes and implement smart filtering ## Connection Optimization ### HTTP/2 and Connection Pooling StateSet APIs support HTTP/2 for improved performance. Configure your HTTP client appropriately: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import { Agent } from 'https'; // Configure connection pooling const httpsAgent = new Agent({ keepAlive: true, keepAliveMsecs: 30000, maxSockets: 50, maxFreeSockets: 10, timeout: 30000, freeSocketTimeout: 30000 }); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, httpAgent: httpsAgent, timeout: 30000, // Enable HTTP/2 http2: true, // Connection reuse keepAlive: true }); ``` ```python theme={null} import httpx from StateSet import StateSetClient # Configure connection pooling limits = httpx.Limits( max_keepalive_connections=20, max_connections=100, keepalive_expiry=30.0 ) # Use HTTP/2 for better performance transport = httpx.HTTPTransport( limits=limits, http2=True, retries=3 ) client = StateSetClient( api_key=os.getenv('STATESET_API_KEY'), transport=transport, timeout=30.0 ) ``` ```ruby theme={null} require 'net/http' require 'StateSet' # Configure connection pooling StateSet.configure do |config| config.api_key = ENV['STATESET_API_KEY'] config.timeout = 30 config.open_timeout = 10 # Connection pool settings config.connection_pool_size = 25 config.connection_pool_timeout = 5 config.keep_alive_timeout = 30 end ``` ### DNS Optimization Optimize DNS resolution for faster connection establishment: ```javascript theme={null} import dns from 'dns'; // Use faster DNS resolvers dns.setServers([ '1.1.1.1', // Cloudflare '8.8.8.8', // Google '208.67.222.222' // OpenDNS ]); // Enable DNS caching const dnsCache = new Map(); const originalLookup = dns.lookup; dns.lookup = (hostname, options, callback) => { const cacheKey = `${hostname}:${JSON.stringify(options)}`; if (dnsCache.has(cacheKey)) { const cached = dnsCache.get(cacheKey); if (Date.now() - cached.timestamp < 300000) { // 5 minutes TTL return callback(null, cached.address, cached.family); } } originalLookup(hostname, options, (err, address, family) => { if (!err) { dnsCache.set(cacheKey, { address, family, timestamp: Date.now() }); } callback(err, address, family); }); }; ``` ## Request Optimization Strategies ### 1. Intelligent Batching Combine multiple operations into single requests: ```javascript theme={null} class BatchProcessor { constructor(client, options = {}) { this.client = client; this.batchSize = options.batchSize || 100; this.flushInterval = options.flushInterval || 1000; this.batches = new Map(); // Auto-flush timer setInterval(() => this.flushAll(), this.flushInterval); } async addToBatch(operation, data, priority = 0) { if (!this.batches.has(operation)) { this.batches.set(operation, { items: [], promise: null, resolver: null }); } const batch = this.batches.get(operation); return new Promise((resolve, reject) => { batch.items.push({ data, priority, resolve, reject, timestamp: Date.now() }); // Auto-flush when batch is full if (batch.items.length >= this.batchSize) { this.flush(operation); } }); } async flush(operation) { const batch = this.batches.get(operation); if (!batch || batch.items.length === 0) return; const items = batch.items.splice(0); try { const results = await this.executeBatch(operation, items); items.forEach((item, index) => { item.resolve(results[index]); }); } catch (error) { items.forEach(item => { item.reject(error); }); } } async executeBatch(operation, items) { const data = items.map(item => item.data); switch (operation) { case 'orders.update': return this.client.orders.batchUpdate(data); case 'customers.create': return this.client.customers.batchCreate(data); case 'inventory.update': return this.client.inventory.batchUpdate(data); default: throw new Error(`Unsupported batch operation: ${operation}`); } } async flushAll() { const operations = Array.from(this.batches.keys()); await Promise.all(operations.map(op => this.flush(op))); } } // Usage const batcher = new BatchProcessor(client, { batchSize: 50, flushInterval: 2000 }); // These will be automatically batched const results = await Promise.all([ batcher.addToBatch('orders.update', { id: '1', status: 'shipped' }), batcher.addToBatch('orders.update', { id: '2', status: 'delivered' }), batcher.addToBatch('orders.update', { id: '3', status: 'returned' }) ]); ``` ### 2. Smart Field Selection Only request the data you need: ```javascript theme={null} // ❌ Inefficient - Downloads unnecessary data const orders = await client.orders.list(); // ✅ Efficient - Only essential fields const orders = await client.orders.list({ fields: ['id', 'status', 'total', 'customer_id', 'created_at'], limit: 100 }); // ✅ Even better - Use sparse fieldsets for different views const orderSummaries = await client.orders.list({ fields: ['id', 'status', 'total'], // Minimal for dashboard limit: 500 }); const orderDetails = await client.orders.get(orderId, { expand: ['customer', 'line_items', 'shipping_address'] // Full details when needed }); ``` ### 3. Parallel Processing with Concurrency Control ```javascript theme={null} import pLimit from 'p-limit'; class ConcurrentProcessor { constructor(client, maxConcurrency = 10) { this.client = client; this.limit = pLimit(maxConcurrency); this.metrics = { processed: 0, errors: 0, startTime: Date.now() }; } async processOrders(orderIds, processFn) { const startTime = Date.now(); // Process in chunks to avoid memory issues const chunkSize = 100; const chunks = this.chunk(orderIds, chunkSize); const results = []; for (const chunk of chunks) { const chunkResults = await Promise.allSettled( chunk.map(orderId => this.limit(() => this.processWithRetry(orderId, processFn)) ) ); results.push(...chunkResults); // Log progress const processed = results.length; const rate = processed / ((Date.now() - startTime) / 1000); logger.info('Processing progress', { processed, total: orderIds.length, rate: `${rate.toFixed(2)}/sec`, errors: this.metrics.errors }); } return results; } async processWithRetry(orderId, processFn, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const result = await processFn(orderId); this.metrics.processed++; return result; } catch (error) { if (attempt === maxRetries) { this.metrics.errors++; throw error; } // Exponential backoff await this.sleep(Math.pow(2, attempt) * 1000); } } } chunk(array, size) { return Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size) ); } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } getMetrics() { const duration = Date.now() - this.metrics.startTime; return { ...this.metrics, duration, rate: this.metrics.processed / (duration / 1000) }; } } // Usage const processor = new ConcurrentProcessor(client, 15); await processor.processOrders(orderIds, async (orderId) => { const order = await client.orders.get(orderId); return await client.orders.update(orderId, { tags: [...order.tags, 'processed'] }); }); ``` ## Advanced Caching Strategies ### 1. Multi-Level Caching ```javascript theme={null} import Redis from 'ioredis'; import NodeCache from 'node-cache'; class MultiLevelCache { constructor(options = {}) { // L1: In-memory cache (fastest) this.l1Cache = new NodeCache({ stdTTL: options.l1TTL || 60, maxKeys: options.l1MaxKeys || 1000 }); // L2: Redis cache (shared across instances) this.l2Cache = new Redis({ host: process.env.REDIS_HOST, port: process.env.REDIS_PORT, retryDelayOnFailover: 100, maxRetriesPerRequest: 3 }); this.defaultTTL = options.defaultTTL || 300; } async get(key, fetchFunction, ttl = this.defaultTTL) { // Check L1 cache first const l1Value = this.l1Cache.get(key); if (l1Value !== undefined) { logger.debug('L1 cache hit', { key }); return l1Value; } // Check L2 cache try { const l2Value = await this.l2Cache.get(key); if (l2Value !== null) { const parsed = JSON.parse(l2Value); // Populate L1 cache this.l1Cache.set(key, parsed, ttl); logger.debug('L2 cache hit', { key }); return parsed; } } catch (error) { logger.warn('L2 cache error', { error: error.message, key }); } // Cache miss - fetch from source logger.debug('Cache miss, fetching', { key }); const value = await fetchFunction(); // Store in both caches this.l1Cache.set(key, value, ttl); try { await this.l2Cache.setex(key, ttl, JSON.stringify(value)); } catch (error) { logger.warn('L2 cache set error', { error: error.message, key }); } return value; } async invalidate(pattern) { // Invalidate L1 cache if (pattern.includes('*')) { const keys = this.l1Cache.keys().filter(key => this.matchPattern(key, pattern) ); this.l1Cache.del(keys); } else { this.l1Cache.del(pattern); } // Invalidate L2 cache try { if (pattern.includes('*')) { const keys = await this.l2Cache.keys(pattern); if (keys.length > 0) { await this.l2Cache.del(...keys); } } else { await this.l2Cache.del(pattern); } } catch (error) { logger.warn('L2 cache invalidation error', { error: error.message, pattern }); } } matchPattern(str, pattern) { return new RegExp('^' + pattern.split('*').map( part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') ).join('.*') + '$').test(str); } } // Usage with StateSet client const cache = new MultiLevelCache({ l1TTL: 60, // 1 minute in memory defaultTTL: 300 // 5 minutes in Redis }); class CachedStateSetClient { constructor(client, cache) { this.client = client; this.cache = cache; } async getCustomer(customerId) { return this.cache.get( `customer:${customerId}`, () => this.client.customers.get(customerId), 600 // 10 minutes TTL for customer data ); } async getOrder(orderId) { return this.cache.get( `order:${orderId}`, () => this.client.orders.get(orderId), 300 // 5 minutes TTL for order data ); } async invalidateCustomer(customerId) { await this.cache.invalidate(`customer:${customerId}`); await this.cache.invalidate(`customer:${customerId}:*`); } } ``` ### 2. Cache Warming and Background Refresh ```javascript theme={null} class CacheWarmer { constructor(client, cache) { this.client = client; this.cache = cache; this.warmingSchedules = new Map(); } scheduleWarming(key, fetchFunction, interval = 240000) { // 4 minutes if (this.warmingSchedules.has(key)) { clearInterval(this.warmingSchedules.get(key)); } const warmCache = async () => { try { logger.debug('Warming cache', { key }); await this.cache.get(key, fetchFunction); } catch (error) { logger.error('Cache warming failed', { key, error: error.message }); } }; // Initial warm warmCache(); // Schedule periodic warming const intervalId = setInterval(warmCache, interval); this.warmingSchedules.set(key, intervalId); } stopWarming(key) { if (this.warmingSchedules.has(key)) { clearInterval(this.warmingSchedules.get(key)); this.warmingSchedules.delete(key); } } // Warm frequently accessed data async warmFrequentData() { // Popular products this.scheduleWarming( 'popular:products', () => this.client.products.list({ sort: 'popularity', limit: 100 }), 300000 // 5 minutes ); // Active customers this.scheduleWarming( 'active:customers', () => this.client.customers.list({ active: true, limit: 500 }), 600000 // 10 minutes ); } } ``` ## Database and Query Optimization ### 1. Efficient Pagination ```javascript theme={null} class EfficientPaginator { constructor(client) { this.client = client; } async *paginateAll(endpoint, params = {}) { let cursor = null; let hasMore = true; while (hasMore) { const response = await endpoint({ ...params, cursor, limit: 100 }); yield* response.data; cursor = response.next_cursor; hasMore = response.has_more; // Small delay to respect rate limits await this.sleep(50); } } async *paginateWindow(endpoint, params = {}, windowSize = 1000) { let processed = 0; const buffer = []; for await (const item of this.paginateAll(endpoint, params)) { buffer.push(item); processed++; if (buffer.length >= windowSize) { yield buffer.splice(0); } // Progress logging if (processed % 10000 === 0) { logger.info('Pagination progress', { processed }); } } // Yield remaining items if (buffer.length > 0) { yield buffer; } } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Usage for processing large datasets const paginator = new EfficientPaginator(client); for await (const orderBatch of paginator.paginateWindow( client.orders.list.bind(client.orders), { status: 'pending' }, 500 )) { await processBatch(orderBatch); } ``` ### 2. Query Optimization ```javascript theme={null} class QueryOptimizer { constructor(client) { this.client = client; this.queryCache = new Map(); } // Optimize list queries with intelligent filtering async optimizedList(endpoint, filters = {}, options = {}) { const cacheKey = this.generateCacheKey(endpoint.name, filters, options); // Check if we have a cached result if (this.queryCache.has(cacheKey)) { const cached = this.queryCache.get(cacheKey); if (Date.now() - cached.timestamp < 60000) { // 1 minute cache return cached.data; } } // Optimize filters const optimizedFilters = this.optimizeFilters(filters); // Use compound queries when beneficial const result = await this.executeOptimizedQuery( endpoint, optimizedFilters, options ); // Cache the result this.queryCache.set(cacheKey, { data: result, timestamp: Date.now() }); return result; } optimizeFilters(filters) { const optimized = { ...filters }; // Convert date ranges to indexed queries if (filters.created_after && filters.created_before) { optimized.created_range = { start: filters.created_after, end: filters.created_before }; delete optimized.created_after; delete optimized.created_before; } // Optimize status filters if (Array.isArray(filters.status) && filters.status.length > 1) { optimized.status_in = filters.status; delete optimized.status; } return optimized; } async executeOptimizedQuery(endpoint, filters, options) { // Add performance hints const queryOptions = { ...options, hint: 'use_index', explain: process.env.NODE_ENV === 'development' }; const result = await endpoint(filters, queryOptions); // Log slow queries in development if (process.env.NODE_ENV === 'development' && result.execution_time > 1000) { logger.warn('Slow query detected', { endpoint: endpoint.name, filters, executionTime: result.execution_time }); } return result; } generateCacheKey(endpoint, filters, options) { return `${endpoint}:${JSON.stringify(filters)}:${JSON.stringify(options)}`; } } ``` ## Memory and Resource Management ### 1. Streaming for Large Datasets ```javascript theme={null} import { Readable } from 'stream'; class DataStream extends Readable { constructor(client, endpoint, params = {}) { super({ objectMode: true, highWaterMark: 100 }); this.client = client; this.endpoint = endpoint; this.params = params; this.cursor = null; this.hasMore = true; this.buffer = []; this.fetching = false; } async _read() { if (this.buffer.length > 0) { return this.push(this.buffer.shift()); } if (!this.hasMore) { return this.push(null); } if (this.fetching) { return; } this.fetching = true; try { const response = await this.endpoint({ ...this.params, cursor: this.cursor, limit: 100 }); this.buffer.push(...response.data); this.cursor = response.next_cursor; this.hasMore = response.has_more; if (this.buffer.length > 0) { this.push(this.buffer.shift()); } else if (!this.hasMore) { this.push(null); } } catch (error) { this.emit('error', error); } finally { this.fetching = false; } } } // Usage for memory-efficient processing const orderStream = new DataStream( client, client.orders.list.bind(client.orders), { status: 'pending' } ); orderStream.on('data', async (order) => { await processOrder(order); }); orderStream.on('end', () => { logger.info('Finished processing all orders'); }); orderStream.on('error', (error) => { logger.error('Stream error', { error: error.message }); }); ``` ### 2. Memory Pool Management ```javascript theme={null} class MemoryPool { constructor(maxSize = 100 * 1024 * 1024) { // 100MB default this.maxSize = maxSize; this.currentSize = 0; this.pools = new Map(); this.lastCleanup = Date.now(); } allocate(key, size) { if (this.currentSize + size > this.maxSize) { this.cleanup(); if (this.currentSize + size > this.maxSize) { throw new Error(`Memory pool exhausted. Current: ${this.currentSize}, Requested: ${size}, Max: ${this.maxSize}`); } } const buffer = Buffer.allocUnsafe(size); this.pools.set(key, { buffer, size, lastAccess: Date.now() }); this.currentSize += size; return buffer; } get(key) { const entry = this.pools.get(key); if (entry) { entry.lastAccess = Date.now(); return entry.buffer; } return null; } release(key) { const entry = this.pools.get(key); if (entry) { this.currentSize -= entry.size; this.pools.delete(key); } } cleanup() { const now = Date.now(); const maxAge = 300000; // 5 minutes for (const [key, entry] of this.pools) { if (now - entry.lastAccess > maxAge) { this.release(key); } } // Force garbage collection if available if (global.gc) { global.gc(); } this.lastCleanup = now; } getStats() { return { currentSize: this.currentSize, maxSize: this.maxSize, utilizationPct: (this.currentSize / this.maxSize) * 100, poolCount: this.pools.size, lastCleanup: this.lastCleanup }; } } ``` ## Performance Monitoring ### 1. Comprehensive Metrics Collection ```javascript theme={null} class PerformanceMonitor { constructor() { this.metrics = { requests: new Map(), latency: new Map(), errors: new Map(), cache: new Map() }; this.startTime = Date.now(); } startTimer(operation) { return { operation, startTime: process.hrtime.bigint(), startCpu: process.cpuUsage() }; } endTimer(timer) { const endTime = process.hrtime.bigint(); const endCpu = process.cpuUsage(timer.startCpu); const duration = Number(endTime - timer.startTime) / 1000000; // Convert to ms const cpuTime = (endCpu.user + endCpu.system) / 1000; // Convert to ms this.recordMetric('latency', timer.operation, { duration, cpuTime, timestamp: Date.now() }); return { duration, cpuTime }; } recordMetric(type, key, value) { if (!this.metrics[type]) { this.metrics[type] = new Map(); } const bucket = this.metrics[type]; const timeWindow = Math.floor(Date.now() / 60000); // 1-minute buckets const bucketKey = `${key}:${timeWindow}`; if (!bucket.has(bucketKey)) { bucket.set(bucketKey, []); } bucket.get(bucketKey).push(value); // Clean old buckets this.cleanOldBuckets(bucket); } cleanOldBuckets(bucket, maxAge = 3600000) { // 1 hour const cutoff = Date.now() - maxAge; for (const [key] of bucket) { const [, timestamp] = key.split(':'); if (parseInt(timestamp) * 60000 < cutoff) { bucket.delete(key); } } } getPerformanceReport() { const report = { uptime: Date.now() - this.startTime, latency: this.calculateLatencyStats(), requests: this.calculateRequestStats(), errors: this.calculateErrorStats(), cache: this.calculateCacheStats(), memory: process.memoryUsage(), cpu: process.cpuUsage() }; return report; } calculateLatencyStats() { const stats = {}; for (const [key, values] of this.metrics.latency) { const [operation] = key.split(':'); if (!stats[operation]) { stats[operation] = { durations: [], cpuTimes: [] }; } values.forEach(v => { stats[operation].durations.push(v.duration); stats[operation].cpuTimes.push(v.cpuTime); }); } // Calculate percentiles Object.keys(stats).forEach(operation => { const durations = stats[operation].durations.sort((a, b) => a - b); const cpuTimes = stats[operation].cpuTimes.sort((a, b) => a - b); stats[operation] = { count: durations.length, latency: { min: durations[0] || 0, max: durations[durations.length - 1] || 0, p50: this.percentile(durations, 0.5), p95: this.percentile(durations, 0.95), p99: this.percentile(durations, 0.99), avg: durations.reduce((a, b) => a + b, 0) / durations.length || 0 }, cpu: { avg: cpuTimes.reduce((a, b) => a + b, 0) / cpuTimes.length || 0, max: cpuTimes[cpuTimes.length - 1] || 0 } }; }); return stats; } percentile(arr, p) { if (arr.length === 0) return 0; const index = Math.ceil(arr.length * p) - 1; return arr[Math.max(0, index)]; } // Real-time alerting checkPerformanceAlerts() { const report = this.getPerformanceReport(); Object.entries(report.latency).forEach(([operation, stats]) => { // Alert on high latency if (stats.latency.p95 > 5000) { // 5 seconds logger.warn('High latency detected', { operation, p95: stats.latency.p95, threshold: 5000 }); } // Alert on high error rate if (stats.errorRate > 0.05) { // 5% logger.error('High error rate detected', { operation, errorRate: stats.errorRate, threshold: 0.05 }); } }); // Alert on high memory usage const memoryUsage = report.memory.heapUsed / report.memory.heapTotal; if (memoryUsage > 0.9) { logger.warn('High memory usage detected', { usage: memoryUsage, heapUsed: report.memory.heapUsed, heapTotal: report.memory.heapTotal }); } } } // Usage with StateSet client const monitor = new PerformanceMonitor(); const monitoredClient = new Proxy(client, { get(target, prop) { const original = target[prop]; if (typeof original === 'object' && original !== null) { return new Proxy(original, { get(apiTarget, apiProp) { const apiMethod = apiTarget[apiProp]; if (typeof apiMethod === 'function') { return async (...args) => { const operation = `${prop}.${apiProp}`; const timer = monitor.startTimer(operation); try { const result = await apiMethod.apply(apiTarget, args); const timing = monitor.endTimer(timer); monitor.recordMetric('requests', operation, { success: true, timestamp: Date.now(), ...timing }); return result; } catch (error) { monitor.endTimer(timer); monitor.recordMetric('errors', operation, { error: error.message, status: error.status, timestamp: Date.now() }); throw error; } }; } return apiMethod; } }); } return original; } }); // Schedule performance checks setInterval(() => { monitor.checkPerformanceAlerts(); }, 30000); // Every 30 seconds ``` ## Load Testing and Benchmarking ```javascript theme={null} import { performance } from 'perf_hooks'; class LoadTester { constructor(client) { this.client = client; } async runLoadTest(config) { const { operation, concurrency = 10, duration = 60000, // 1 minute rampUp = 5000 // 5 seconds } = config; logger.info('Starting load test', config); const results = { requests: 0, errors: 0, latencies: [], startTime: Date.now() }; // Ramp up workers gradually const workers = []; const workerInterval = rampUp / concurrency; for (let i = 0; i < concurrency; i++) { setTimeout(() => { workers.push(this.createWorker(operation, results)); }, i * workerInterval); } // Wait for test duration await new Promise(resolve => setTimeout(resolve, duration)); // Stop all workers workers.forEach(worker => worker.stop()); // Wait for workers to finish await Promise.all(workers.map(w => w.promise)); return this.calculateResults(results); } createWorker(operation, results) { let running = true; const worker = { stop: () => { running = false; }, promise: this.runWorker(operation, results, () => running) }; return worker; } async runWorker(operation, results, isRunning) { while (isRunning()) { const start = performance.now(); try { await operation(); const latency = performance.now() - start; results.requests++; results.latencies.push(latency); } catch (error) { results.errors++; logger.debug('Load test error', { error: error.message }); } // Small delay to prevent overwhelming await new Promise(resolve => setTimeout(resolve, 10)); } } calculateResults(results) { const duration = Date.now() - results.startTime; const latencies = results.latencies.sort((a, b) => a - b); return { duration, totalRequests: results.requests, totalErrors: results.errors, successRate: (results.requests - results.errors) / results.requests, requestsPerSecond: results.requests / (duration / 1000), errorRate: results.errors / results.requests, latency: { min: latencies[0] || 0, max: latencies[latencies.length - 1] || 0, avg: latencies.reduce((a, b) => a + b, 0) / latencies.length || 0, p50: this.percentile(latencies, 0.5), p95: this.percentile(latencies, 0.95), p99: this.percentile(latencies, 0.99) } }; } percentile(arr, p) { if (arr.length === 0) return 0; const index = Math.ceil(arr.length * p) - 1; return arr[Math.max(0, index)]; } } // Usage const loadTester = new LoadTester(client); const results = await loadTester.runLoadTest({ operation: async () => { await client.orders.list({ limit: 10 }); }, concurrency: 20, duration: 120000, // 2 minutes rampUp: 10000 // 10 seconds }); logger.info('Load test results', results); ``` ## Performance Best Practices Summary * Use HTTP/2 and connection pooling * Configure DNS caching * Implement keep-alive connections * Optimize TLS handshakes * Batch operations when possible * Use field selection and sparse responses * Implement intelligent pagination * Leverage parallel processing with limits * Multi-level caching (memory + Redis) * Cache warming and background refresh * Smart invalidation patterns * TTL optimization by data type * Stream large datasets * Implement memory pools * Monitor and alert on metrics * Regular performance testing ## Next Steps 1. **Implement monitoring** using the performance monitoring tools 2. **Establish baselines** with load testing 3. **Set up alerting** for performance degradation 4. **Regular optimization** based on production metrics For more advanced optimization techniques, see: * [API Rate Limiting Guide](/guides/api-rate-limiting) * [Error Handling Best Practices](/guides/error-handling-best-practices) * [Webhook Security](/guides/webhook-security) # RAG Quickstart Source: https://docs.stateset.com/guides/rag-quickstart Getting started with RAG ## Prerequisites Before implementing RAG, ensure you have: * StateSet account with API access * API credentials from the [StateSet Dashboard](https://app.StateSet.com/settings/api-keys) * ResponseCX enabled in your workspace * Vector database setup * Database index configured with appropriate dimensions (1536 for OpenAI) * Understanding of vector embeddings and similarity search * OpenAI API key for embeddings generation * Understanding of machine learning concepts (helpful) * Familiarity with natural language processing * Node.js 16+ installed * Basic understanding of REST APIs and JavaScript * GraphQL endpoint configured (for messaging interface) * Document corpus ready for ingestion # RAG Overview Retrieval Augmented Generation (RAG) is a powerful approach that combines the strengths of neural language models with retrieval from a large corpus of documents to produce more accurate and informed outputs. The RAG system enables the retrieval of highly relevant documents using natural language search, and it is scalable to billions of records, functioning much like a traditional database. A key advantage of RAG is that it does not require context stuffing, meaning that the relevant context is pulled from the extensive database rather than being fed into the model in advance. RAG RAG can be particularly effective in addressing issues like hallucinations in large language models (LLMs), which are instances where the model generates factually incorrect or nonsensical information. By using vector databases that store embeddings of texts, RAG can provide an anchor to the "real world" and structured data. When a query is made, the system retrieves semantically relevant content from the vector database, which is then used by the LLM to generate responses. This ensures that the information is grounded in the content that has been previously validated and stored in the database. The architecture of RAG involves several components working together. An application sends a query to an embedding model, which converts the query into a vector representation. This vector is then matched against a vector database via an API to find the most relevant documents or chunks of text. The results are filtered through metadata to ensure relevance and compliance with access controls. The selected content is streamed into the LLM's context window, providing a foundation for it to generate informed responses. Embeddings Additionally, RAG incorporates a continuous cycle of ingestion and updating. New documents are crawled, chunked, and their embeddings are addei to the vector database, which ensures that the knowledge base is constantly expanding and staying up-to-date with the latest information. This dynamic nature of RAG makes it a robust system for applications requiring access to a vast, evolving pool of data and the ability to provide accurate, context-aware responses. ### Messaging Interface We have worked hard on providing the ultimate communication interface for developing RAG AI Agents. Each channel has a subscription to a GraphQL API that allows you to query and mutate data in the RAG system. You can use this API to build your own custom UI or integrate with your existing systems. ```graphQL theme={null} let GET_MY_CHANNEL_MESSAGES = gql` subscription ( $last_received_id: String $last_received_ts: String $first_received_date: date $chat_id: uuid ) { message( order_by: { date: asc, timestamp: asc } where: { _and: { id: { _neq: $last_received_id } timestamp: { _gte: $last_received_ts } date: { _gte: $first_received_date } _and: { user: { username: { _neq: "null" } } _and: { chat_id: { _eq: $chat_id } } } } } limit: 200 ) { id body username from time timestamp date created_at isCode likes channel_id isCommerce isReason chartContent image_url agent_id voice_model_id user { id username avatar } } } `; ``` ### Get Returns Embeddings from StateSet API ```javascript theme={null} // Main function to create returns feed const createReturnsFeed = async (req, res) => { async function getReturns(offset, token) { const DOCUMENT_UPSERT_BATCH_SIZE = 3; var token; var limit = 1; logger.info(offset); logger.info(limit); try { const response = await axios.post(`https://api.StateSet.com/api/get-returns`, { limit: limit, offset: offset, "order_direction": "desc" }, { headers: { 'Content-Type': 'application/json', 'token': "Bearer " + token, }, }); var returns = response.data; if (returns) { const documents = []; for (const item of returns) { try { const returnId = item.id || null; const orderId = item.order_id || null; const actionNeeded = item.action_needed || null; const description = item.description || null; const status = item.status || null; const customerEmail = item.customerEmail || null; const customerEmailNormalized = item.customer_email_normalized || null; const zendeskNumber = item.zendesk_number || null; const serialNumber = item.serial_number || null; const reportedCondition = item.reported_condition || null; const trackingNumber = item.tracking_number || null; const rma = item.rma || null; const reasonCategory = item.reason_category || null; const country = item.country || null; const ssoId = item.sso_id || null; const enteredBy = item.entered_by || null; const scannedSerialNumber = item.scanned_serial_number || null; const issue = item.issue || null; const condition = item.condition || null; const amount = item.amount || null; const taxRefunded = item.tax_refunded || null; const totalRefunded = item.total_refunded || null; const createdDate = item.created_date || null; const orderDate = item.order_date || null; const shippedDate = item.shipped_date || null; const requestedDate = item.requested_date || null; const flatRateShipping = item.flat_rate_shipping || null; const warehouseReceivedDate = item.warehouse_received_date || null; const warehouseConditionDate = item.warehouse_condition_date || null; let metadata = { returnId, orderId, actionNeeded, description, status, customerEmail, customerEmailNormalized, zendeskNumber, serialNumber, reportedCondition, trackingNumber, rma, reasonCategory, country, ssoId, enteredBy, scannedSerialNumber, issue, condition, amount, taxRefunded, totalRefunded, createdDate, orderDate, shippedDate, requestedDate, flatRateShipping, warehouseReceivedDate, warehouseConditionDate, }; const document = { id: uuid(), returnId, metadata, }; documents.push(document); } catch (error) { logger.info(`Error processing item: ${JSON.stringify(item);}`); logger.info(error); } for (let i = 0; i < documents.length; i += DOCUMENT_UPSERT_BATCH_SIZE) { // Split documents into batches var batchDocuments = documents.slice(i, i + DOCUMENT_UPSERT_BATCH_SIZE); logger.info(batchDocuments); // Convert batchDocuments to string var batchDocumentString = JSON.stringify(batchDocuments) // Remove commas from string logger.info(batchDocumentString); // Create Embeddings logger.info('Looping through documents...'); const user_id = "domsteil"; // OpenAI Request Body var raw = JSON.stringify({ "input": batchDocumentString, "model": "text-embedding-3-large", "user": user_id }); // OpenAI Request Options var requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': process.env.OPEN_AI }, body: raw, redirect: 'follow' }; // Make Callout to OpenAI to get Embeddings logger.info('Creating Embedding...'); // Make Callout to OpenAI let embeddings_response = await fetch("https://api.openai.com/v1/embeddings", requestOptions) // Create Pinecone Request Body const vectors_embeddings = await embeddings_response.json(); logger.info(vectors_embeddings); // Create Pinecone Request Body var vectors_object = { id: uuid(), values: vectors_embeddings.data[0].embedding, metadata: { "text": batchDocumentString, "user": user_id } }; logger.info(vectors_object); var raw = JSON.stringify({ "vectors": vectors_object, "namespace": `return_data` }); var pineconeRequestOptions = { method: "POST", headers: { "Content-Type": "application/json", "Host": pinecone_index, "Content-Length": 60, "Api-Key": pinecone_api_key, }, body: raw, redirect: "follow", }; // Make Callout to Pinecone // Pinecone Upsert logger.info('Upserting Pinecone...'); let pinecone_query_response = await fetch(`https://${pinecone_index}/vectors/upsert`, pineconeRequestOptions) .then(response => response.text()) .then(json => { logger.info(json); }) .catch(error => { logger.error(error); }); } } await getReturns(offset + 3, token); } } catch (error) { logger.info(offset); logger.error(error); } } // Start at offset 0 with limit of 100 await getReturns(0, access_token); } ``` ### Stream Object Interface Now that we have the embeddings stored in the vector database, we can use the Stream Object API to generate the returns object details for a returns management system. This will allow us to retrieve the relevant information from the vector database and generate the return object details using a language model. ```javascript theme={null} export type Return = { returnId: string | null; orderId: string | null; actionNeeded: string | null; description: string | null; status: string | null; customerEmail: string | null; customerEmailNormalized: string | null; zendeskNumber: string | null; serialNumber: string | null; reportedCondition: string | null; trackingNumber: string | null; rma: string | null; reasonCategory: string | null; country: string | null; ssoId: string | null; enteredBy: string | null; scannedSerialNumber: string | null; issue: string | null; condition: string | null; amount: string | null; taxRefunded: string | null; totalRefunded: string | null; createdDate: string | null; orderDate: string | null; shippedDate: string | null; requestedDate: string | null; flatRateShipping: string | null; warehouseReceivedDate: string | null; warehouseConditionDate: string | null; }; export async function generate(input: string) { 'use server'; const stream = createStreamableValue(); let contexts = []; try { const pinecone_query_response = await fetch( `https://${process.env.PINECONE_INDEX}/query`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ topK: 1, vector: input, includeMetadata: true, }), } ) .then((response) => response.json()) .then((json) => { contexts = json.matches.map((x) => x.metadata.text); }) .catch((error) => { logger.error(error); throw new Error("An error occurred while querying Pinecone"); }); } catch (error) { logger.error("Error fetching context:", error); return { error: "An error occurred while querying Pinecone" }; } const promptWithContext = `Context: ${contexts.join(' ')}, Query: ${input}`; (async () => { const { partialObjectStream } = await streamObject({ model: openai('gpt-4-turbo'), system: 'You generate return object details for a returns management system', prompt: promptWithContext, schema: z.object({ returns: z.array( z.object({ returnId: z.string().nullable().describe('ID of the return.'), orderId: z.string().nullable().describe('ID of the order.'), actionNeeded: z.string().nullable().describe('Action needed for the return.'), description: z.string().nullable().describe('Description of the return.'), status: z.string().nullable().describe('Status of the return.'), customerEmail: z.string().nullable().describe('Email of the customer.'), customerEmailNormalized: z.string().nullable().describe('Normalized email of the customer.'), zendeskNumber: z.string().nullable().describe('Zendesk ticket number.'), serialNumber: z.string().nullable().describe('Serial number of the returned item.'), reportedCondition: z.string().nullable().describe('Reported condition of the returned item.'), trackingNumber: z.string().nullable().describe('Tracking number for the return shipment.'), rma: z.string().nullable().describe('Return Merchandise Authorization number.'), reasonCategory: z.string().nullable().describe('Category of the return reason.'), country: z.string().nullable().describe('Country of the return.'), ssoId: z.string().nullable().describe('SSO ID associated with the return.'), enteredBy: z.string().nullable().describe('User who entered the return.'), scannedSerialNumber: z.string().nullable().describe('Scanned serial number of the returned item.'), issue: z.string().nullable().describe('Issue reported with the returned item.'), condition: z.string().nullable().describe('Condition of the returned item.'), amount: z.string().nullable().describe('Amount refunded for the return.'), taxRefunded: z.string().nullable().describe('Tax refunded for the return.'), totalRefunded: z.string().nullable().describe('Total amount refunded for the return.'), createdDate: z.string().nullable().describe('Date the return was created.'), orderDate: z.string().nullable().describe('Date the order was placed.'), shippedDate: z.string().nullable().describe('Date the order was shipped.'), requestedDate: z.string().nullable().describe('Date the return was requested.'), flatRateShipping: z.string().nullable().describe('Flat rate shipping cost for the return.'), warehouseReceivedDate: z.string().nullable().describe('Date the return was received at the warehouse.'), warehouseConditionDate: z.string().nullable().describe('Date the return condition was assessed at the warehouse.'), }), ), }), }); for await (const partialObject of partialObjectStream) { stream.update(partialObject); } stream.done(); })(); return { object: stream.value }; } ``` ### Conclusion RAG is a powerful approach that combines the strengths of neural language models with retrieval from a large corpus of documents to produce more accurate and informed outputs. By leveraging the capabilities of vector databases and dynamic ingestion, RAG can provide context-aware responses grounded in validated information. This makes it an ideal solution for applications requiring access to vast, evolving pools of data and the ability to generate accurate, context-aware responses. With the right architecture and components in place, RAG can be a game-changer for AI applications that need to deliver reliable, fact-based information to users. # Reinforcement Learning Platform Overview Source: https://docs.stateset.com/guides/reinforcement-learning-platform Transform AI training with Group Relative Policy Optimization (GRPO) - the next evolution in model training ## Introduction Welcome to StateSet's revolutionary Reinforcement Learning platform, powered by **Group Relative Policy Optimization (GRPO)**. This represents a fundamental shift in how we train AI models - moving beyond simple next-word prediction to models that learn through exploration, evaluation, and optimization toward specific goals. **Key Insight**: Traditional fine-tuning maximizes next-word prediction probability. GRPO maximizes reward functions - teaching models not just what to say, but how to achieve optimal outcomes. ## Why Reinforcement Learning? Models learn to maximize specific objectives rather than just mimicking training data Models generate multiple solutions and learn from comparing outcomes Every interaction becomes a learning opportunity through reward optimization ## How GRPO Trains Your Model ### The Training Process ```mermaid theme={null} graph LR A[Input Question] --> B[Generate Multiple Responses] B --> C[Evaluate Each Response] C --> D[Calculate Rewards] D --> E[Update Model Weights] E --> F[Improved Model] F --> A ``` ### Step-by-Step Breakdown For each question-answer pair, the model generates multiple possible responses (e.g., 8-16 variations) ```python theme={null} # Example: Model generates variations for "How to handle a refund?" responses = [ "I'd be happy to help with your refund...", "Let me process that refund for you...", "I understand you need a refund...", # ... 5-13 more variations ] ``` Each response is evaluated using sophisticated reward functions ```python theme={null} rewards = [] for response in responses: reward = evaluate_response(response, criteria={ 'helpfulness': 0.4, 'accuracy': 0.3, 'tone': 0.2, 'efficiency': 0.1 }) rewards.append(reward) ``` The average reward serves as a baseline for comparison ```python theme={null} baseline = sum(rewards) / len(rewards) relative_rewards = [r - baseline for r in rewards] ``` Model weights are updated to reinforce above-average responses ```python theme={null} # Responses better than average get reinforced # Responses worse than average get discouraged model.update_weights(responses, relative_rewards) ``` ### Training Scale **300 rows × 1 epoch = 300 training steps** * Quick iteration * Rapid prototyping * Initial model validation **300 rows × 3 epochs = 900 training steps** * Balanced approach * Good convergence * Production-ready models **300 rows × 3 epochs × 16 responses = 14,400 evaluations** * Maximum exploration * Best performance * Complex task mastery ## Understanding Reward Functions & Verifiers ### The Distinction **Binary Evaluation** * Determines correct/incorrect * No numerical scoring * Can execute code for validation ```python theme={null} def verify_math(question, answer): if question == "2+2" and answer == "4": return True return False ``` **Numerical Scoring** * Assigns scores (-∞ to +∞) * Considers multiple criteria * Guides optimization direction ```python theme={null} def reward_function(question, answer, verified): score = 0 if verified: score += 2 if len(answer) < 100: # Brevity bonus score += 0.5 return score ``` ### Reward Function Design The power of GRPO lies in well-designed reward functions that capture your exact objectives: ```python theme={null} class CustomerServiceReward: def __init__(self): self.criteria = { 'resolution': 0.35, # Did it solve the problem? 'empathy': 0.25, # Was it understanding? 'clarity': 0.20, # Was it clear? 'efficiency': 0.10, # Was it concise? 'policy_compliance': 0.10 # Did it follow rules? } def calculate(self, response, context): scores = {} # Resolution scoring scores['resolution'] = self.check_resolution(response, context) # Empathy detection scores['empathy'] = self.measure_empathy(response) # Clarity assessment scores['clarity'] = self.evaluate_clarity(response) # Length efficiency scores['efficiency'] = min(1.0, 50 / len(response.split())) # Policy adherence scores['policy_compliance'] = self.check_policies(response, context) # Weighted sum total = sum(scores[k] * self.criteria[k] for k in scores) return total, scores # Return total and breakdown ``` **Critical**: Poorly designed reward functions can degrade model performance. Always test reward functions thoroughly before full-scale training. ## Group Relative Policy Optimization (GRPO) ### The Innovation Traditional RL algorithms like PPO require training a separate "critic" model to estimate value. GRPO eliminates this overhead: ```mermaid theme={null} graph TD A[Actor Model] --> B[Generate Action] C[Critic Model] --> D[Estimate Value] B --> E[Calculate Advantage] D --> E E --> F[Update Both Models] ``` **Drawbacks:** * Train two models * More memory usage * Slower convergence ```mermaid theme={null} graph TD A[Single Model] --> B[Generate Multiple Responses] B --> C[Calculate Group Rewards] C --> D[Use Average as Baseline] D --> E[Update Model Once] ``` **Benefits:** * Single model training * 50% less memory * Faster iterations ### How GRPO Works Generate multiple solutions for each problem ```python theme={null} # Instead of one response per prompt responses = model.generate( prompt="How should I handle an angry customer?", num_returns=8 # Generate 8 variations ) ``` Evaluate each solution's quality ```python theme={null} rewards = [] for response in responses: reward = reward_function(response) rewards.append(reward) # rewards = [0.8, 1.2, 0.6, 1.5, 0.9, 1.1, 0.7, 1.3] ``` Use group average as baseline ```python theme={null} baseline = sum(rewards) / len(rewards) # 1.0125 ``` Reinforce above-average, discourage below-average ```python theme={null} for response, reward in zip(responses, rewards): advantage = reward - baseline if advantage > 0: # Increase probability of this response pattern model.reinforce(response, advantage) else: # Decrease probability of this response pattern model.discourage(response, -advantage) ``` ## Configuration Deep Dive ### Key Parameters ```yaml theme={null} # GRPO Configuration actor_rollout: ref: rollout: n: 8 # Generate 8 responses per prompt (critical for GRPO) data: train_batch_size: 32 # Number of prompts per batch actor_rollout_ref: actor: ppo_mini_batch_size: 256 # Mini-batch for weight updates ppo_epochs: 4 # Update epochs per trajectory set clip_ratio: 0.2 # GRPO clip range for stable training # GRPO-specific settings use_kl_loss: true # Enable KL regularization kl_loss_coef: 0.001 # KL penalty strength kl_loss_type: "kl" # Options: kl, abs, mse, low_var_kl, full # Loss aggregation loss_agg_mode: "token-mean" # Stable for long responses algorithm: adv_estimator: "grpo" # Use GRPO instead of GAE ``` ### Configuration Profiles ```yaml theme={null} # For critical applications clip_ratio: 0.1 kl_loss_coef: 0.01 ppo_epochs: 2 rollout.n: 4 ``` ```yaml theme={null} # For most use cases clip_ratio: 0.2 kl_loss_coef: 0.001 ppo_epochs: 4 rollout.n: 8 ``` ```yaml theme={null} # For rapid learning clip_ratio: 0.3 kl_loss_coef: 0.0001 ppo_epochs: 6 rollout.n: 16 ``` ## Practical Implementation ### Example: Customer Service Agent ```python theme={null} from StateSet.rl import GRPOTrainer, RewardFunction from transformers import AutoModelForCausalLM, AutoTokenizer from peft import LoraConfig, get_peft_model, TaskType from trl import GRPOTrainer, GRPOConfig from datasets import Dataset from sklearn.model_selection import train_test_split # Model setup with LoRA for efficient training def setup_model(model_name="Qwen/Qwen2.5-7B-Instruct"): # Load tokenizer tokenizer = AutoTokenizer.from_pretrained( model_name, trust_remote_code=True, padding_side="left" # Critical for generation ) if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token # Load model with mixed precision model = AutoModelForCausalLM.from_pretrained( model_name, torch_dtype=torch.float16, device_map='auto', trust_remote_code=True ) # Add LoRA adapters for efficient training lora_config = LoraConfig( r=8, lora_alpha=16, target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], lora_dropout=0.05, bias="none", task_type=TaskType.CAUSAL_LM, ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() # Typically <1% of total return model, tokenizer # Define comprehensive reward function class CustomerServiceReward: def __init__(self, expected_responses=None): self.empathy_keywords = ['sorry', 'understand', 'help', 'happy', 'glad', 'assist'] self.action_keywords = ['visit', 'email', 'click', 'check', 'provide'] self.expected_responses = expected_responses or {} def compute_reward(self, query, response, expected=None): response_lower = response.lower() # Similarity to expected response (if available) similarity_reward = 0.0 if expected: import difflib similarity = difflib.SequenceMatcher(None, response_lower, expected.lower()).ratio() similarity_reward = similarity # Empathy score empathy_score = sum(1 for word in self.empathy_keywords if word in response_lower) / len(self.empathy_keywords) # Action-oriented score action_score = sum(1 for word in self.action_keywords if word in response_lower) / len(self.action_keywords) # Length penalty (concise but complete) word_count = len(response.split()) if word_count < 10: length_penalty = -0.5 elif word_count > 100: length_penalty = -0.3 else: length_penalty = 0.0 # Weighted combination total_reward = ( 0.4 * similarity_reward + 0.3 * empathy_score + 0.2 * action_score + 0.1 * (1.0 + length_penalty) ) return { "total": total_reward, "similarity": similarity_reward, "empathy": empathy_score, "action": action_score, "length_penalty": length_penalty } # Configure GRPO training training_config = GRPOConfig( output_dir="./checkpoints/grpo", per_device_train_batch_size=2, gradient_accumulation_steps=4, # Effective batch size = 8 learning_rate=1e-5, num_train_epochs=1, max_grad_norm=0.5, warmup_steps=50, fp16=True, # Mixed precision training logging_steps=10, save_steps=100, eval_steps=50, # GRPO specific parameters beta=0.0, # KL penalty coefficient num_generations=4, # Generate 4 responses per prompt num_iterations=1, # Generation parameters max_prompt_length=128, max_completion_length=128, temperature=0.7, top_p=0.9, # Reproducibility seed=42, ) # Train with proper data splitting def train_customer_service_model(data, eval_split=0.1): # Split data train_data, eval_data = train_test_split( data, test_size=eval_split, random_state=42, stratify=[d['task_type'] for d in data] # Maintain task distribution ) # Create datasets train_dataset = Dataset.from_list([ {"prompt": f"Customer: {d['query']}\nAssistant:"} for d in train_data ]) eval_dataset = Dataset.from_list([ {"prompt": f"Customer: {d['query']}\nAssistant:"} for d in eval_data ]) # Setup reward function with expected responses reward_model = CustomerServiceReward({ f"Customer: {d['query']}\nAssistant:": d['expected_response'] for d in train_data }) def reward_fn(completions, prompts): rewards = [] for completion, prompt in zip(completions, prompts): expected = reward_model.expected_responses.get(prompt) reward_dict = reward_model.compute_reward( prompt.split("Customer: ")[1].split("\nAssistant:")[0], completion, expected ) rewards.append(reward_dict["total"]) return rewards # Initialize trainer trainer = GRPOTrainer( model=model, args=training_config, train_dataset=train_dataset, eval_dataset=eval_dataset, reward_funcs=reward_fn, ) # Train trainer.train() return trainer.model ``` ### Real-World Training Pipeline ```python theme={null} # Complete training pipeline with evaluation import logging from pathlib import Path import torch import wandb # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(), logging.FileHandler('grpo_training.log') ] ) logger = logging.getLogger(__name__) # Environment configuration CONFIG = { 'max_examples': 5000, 'batch_size': 2, 'gradient_accumulation_steps': 4, 'learning_rate': 1e-5, 'num_epochs': 1, 'max_grad_norm': 0.5, 'warmup_steps': 50, 'checkpoint_dir': './checkpoints/grpo', 'use_mixed_precision': True, 'model_name': 'Qwen/Qwen2.5-7B-Instruct', 'max_length': 256, 'max_new_tokens': 128, 'lora_r': 8, 'lora_alpha': 16, 'lora_dropout': 0.05, 'num_generations': 4, 'eval_split_size': 0.1, 'seed': 42, } # Set random seeds for reproducibility def set_seed(seed: int): import random import numpy as np random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) # Post-training evaluation def run_post_training_evaluation(model, tokenizer, eval_examples, reward_model, num_samples=5): """Evaluate model performance on held-out examples""" logger.info("Running post-training evaluation...") eval_results = [] for i, example in enumerate(eval_examples[:num_samples]): prompt = f"Customer: {example['query']}\nAssistant:" inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=CONFIG['max_length']) inputs = {k: v.to(model.device) for k, v in inputs.items()} with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=CONFIG['max_new_tokens'], temperature=0.7, top_p=0.9, pad_token_id=tokenizer.pad_token_id, eos_token_id=tokenizer.eos_token_id, ) generated = tokenizer.decode(outputs[0][len(inputs['input_ids'][0]):], skip_special_tokens=True) reward_dict = reward_model.compute_reward(example['query'], generated, example['expected_response']) eval_results.append({ 'query': example['query'], 'generated': generated, 'expected': example['expected_response'], 'reward': reward_dict }) logger.info(f"Sample {i+1}:") logger.info(f" Query: {example['query']}") logger.info(f" Generated: {generated[:100]}...") logger.info(f" Reward: {reward_dict['total']:.4f} (similarity: {reward_dict['similarity']:.4f})") return eval_results # Main training function def main(): # Initialize wandb for experiment tracking wandb.init( project="customer-service-grpo", config=CONFIG, name=f"grpo-{datetime.now().strftime('%Y%m%d-%H%M%S')}" ) # Set seed set_seed(CONFIG['seed']) # Load and prepare data data = load_customer_service_data() # Your data loading function # Train model model = train_customer_service_model(data, eval_split=CONFIG['eval_split_size']) # Save model model.save_pretrained(CONFIG['checkpoint_dir']) tokenizer.save_pretrained(CONFIG['checkpoint_dir']) # Run evaluation eval_results = run_post_training_evaluation( model, tokenizer, eval_data, reward_model, num_samples=5 ) # Log results to wandb for i, result in enumerate(eval_results): wandb.log({ f"eval/sample_{i}/reward": result['reward']['total'], f"eval/sample_{i}/similarity": result['reward']['similarity'], }) logger.info("✨ Training completed successfully!") ``` ### Monitoring Training Progress ```python theme={null} # Real-time metrics during training trainer.on_step = lambda metrics: print(f""" Step {metrics.step}: Average Reward: {metrics.avg_reward:.3f} Reward Std: {metrics.reward_std:.3f} KL Divergence: {metrics.kl_div:.4f} Response Quality: {metrics.quality_score:.2%} """) # Track detailed metrics with wandb wandb.log({ "train/reward_mean": metrics.avg_reward, "train/reward_std": metrics.reward_std, "train/kl_divergence": metrics.kl_div, "train/learning_rate": trainer.optimizer.param_groups[0]['lr'], "train/gradient_norm": metrics.grad_norm, }) ``` ## Best Practices ### 1. Data Preparation Focus on high-quality, diverse examples ```python theme={null} def validate_conversation(conv): """Ensure data quality before training""" # Check structure if not isinstance(conv, dict) or 'messages' not in conv: return False messages = conv['messages'] if not isinstance(messages, list) or len(messages) < 2: return False # Validate each message for msg in messages: if not all(k in msg for k in ['role', 'content']): return False if msg['role'] not in ['user', 'assistant', 'system']: return False if not msg['content'].strip(): return False return True ``` Classify examples by task type for balanced training ```python theme={null} def classify_task_type(query, response): """Categorize customer service tasks""" query_lower = query.lower() task_mapping = { 'order_tracking': ['tracking', 'order', 'shipment', 'delivery'], 'returns': ['return', 'exchange', 'refund'], 'product_inquiry': ['shade', 'color', 'match', 'size'], 'technical_issue': ['damaged', 'broken', 'issue', 'problem'], 'general': [] # Default category } for task_type, keywords in task_mapping.items(): if any(word in query_lower for word in keywords): return task_type return 'general' ``` Always maintain a held-out evaluation set ```python theme={null} from sklearn.model_selection import train_test_split # Stratified split to maintain task distribution train_examples, eval_examples = train_test_split( examples, test_size=0.1, # 10% for evaluation random_state=42, stratify=[e.task_type for e in examples] ) ``` ### 2. Reward Function Design Begin with basic reward functions and gradually add complexity ```python theme={null} # Start with this def simple_reward(response): return 1.0 if is_correct(response) else -1.0 # Evolve to this def complex_reward(response, context): return weighted_sum([ correctness_score(response), style_score(response), efficiency_score(response), context_relevance(response, context) ]) ``` Validate reward functions before training ```python theme={null} def test_reward_function(reward_fn, test_cases): for prompt, good_response, bad_response in test_cases: good_score = reward_fn(prompt, good_response) bad_score = reward_fn(prompt, bad_response) assert good_score > bad_score, f"Reward function failed on {prompt}" ``` Avoid over-optimizing for single metrics ```python theme={null} # Bad: Single metric def bad_reward(response): return -len(response) # Only optimizes for brevity # Good: Balanced metrics def good_reward(response): return 0.6 * quality + 0.3 * brevity + 0.1 * style ``` ### 3. Performance Optimization ```python theme={null} # Memory-efficient training with gradient accumulation trainer = GRPOTrainer( gradient_accumulation_steps=4, # Simulate larger batch gradient_checkpointing=True, # Trade compute for memory fp16=True, # Mixed precision dataloader_num_workers=4, # Parallel data loading ) # Multi-GPU training if torch.cuda.device_count() > 1: # Automatically handled by trainer with proper config training_config.ddp_find_unused_parameters = False training_config.dataloader_num_workers = 4 ``` ### 4. Production Deployment ```python theme={null} # Load trained model for inference def load_trained_model(checkpoint_dir): from peft import PeftModel # Load base model base_model = AutoModelForCausalLM.from_pretrained( CONFIG['model_name'], torch_dtype=torch.float16, device_map='auto' ) # Load LoRA weights model = PeftModel.from_pretrained(base_model, checkpoint_dir) model = model.merge_and_unload() # Merge for faster inference # Load tokenizer tokenizer = AutoTokenizer.from_pretrained(checkpoint_dir) return model, tokenizer # Inference function def generate_response(model, tokenizer, query): prompt = f"Customer: {query}\nAssistant:" inputs = tokenizer(prompt, return_tensors="pt", truncation=True) inputs = {k: v.to(model.device) for k, v in inputs.items()} with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=128, temperature=0.7, top_p=0.9, do_sample=True, pad_token_id=tokenizer.pad_token_id, eos_token_id=tokenizer.eos_token_id, ) response = tokenizer.decode(outputs[0][len(inputs['input_ids'][0]):], skip_special_tokens=True) return response.strip() ``` ## Real-World Impact ### Case Study: Customer Support * Generic responses * 65% resolution rate * 3.2/5 satisfaction * High escalation rate * Context-aware responses * 89% resolution rate * 4.6/5 satisfaction * 40% fewer escalations ### Performance Metrics ```python theme={null} # Measure improvement baseline_model = load_model("base") grpo_model = load_model("grpo_trained") metrics = evaluate_models(baseline_model, grpo_model, test_set) print(f""" Performance Improvement: - Task Success: +{metrics.success_delta:.1%} - User Satisfaction: +{metrics.satisfaction_delta:.1%} - Response Quality: +{metrics.quality_delta:.1%} - Efficiency: +{metrics.efficiency_delta:.1%} """) ``` ## Getting Started What behavior do you want to optimize for? ```python theme={null} objective = "Maximize customer satisfaction while resolving issues efficiently" ``` Translate objectives into measurable rewards ```python theme={null} reward = CustomerSatisfactionReward( weights={'resolution': 0.5, 'tone': 0.3, 'efficiency': 0.2} ) ``` Collect quality examples (300+ recommended) ```python theme={null} data = prepare_training_data( source="support_tickets", min_quality_score=0.8 ) ``` Start with balanced settings ```python theme={null} model = train_grpo_model( data=data, reward_fn=reward, profile="balanced" ) ``` Test thoroughly before production ```python theme={null} if evaluate(model).meets_criteria(): deploy_to_production(model) ``` ## Advanced Topics ### Multi-Objective Optimization ```python theme={null} class MultiObjectiveReward: def __init__(self, objectives): self.objectives = objectives def compute(self, response, context): scores = {} for name, (weight, function) in self.objectives.items(): scores[name] = function(response, context) * weight # Pareto optimization if self.is_pareto_optimal(scores): bonus = 0.2 else: bonus = 0 return sum(scores.values()) + bonus ``` ### Curriculum Learning ```python theme={null} # Start with easy tasks, gradually increase difficulty curriculum = [ {"difficulty": "easy", "epochs": 1, "reward_scale": 1.0}, {"difficulty": "medium", "epochs": 2, "reward_scale": 0.8}, {"difficulty": "hard", "epochs": 3, "reward_scale": 0.6} ] for stage in curriculum: model = trainer.train( data=filter_by_difficulty(data, stage["difficulty"]), epochs=stage["epochs"], reward_scale=stage["reward_scale"] ) ``` ### Distributed Training ```python theme={null} # Setup for multi-GPU training import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP def setup_distributed_training(): """Initialize distributed training environment""" local_rank = int(os.environ.get("LOCAL_RANK", -1)) world_size = int(os.environ.get("WORLD_SIZE", 1)) if local_rank != -1: # Initialize process group torch.cuda.set_device(local_rank) dist.init_process_group(backend="nccl") logger.info(f"Initialized distributed training: rank {local_rank}/{world_size}") # Only log from main process if local_rank != 0: logging.getLogger().setLevel(logging.WARNING) return local_rank, world_size # Launch distributed training # torchrun --nproc_per_node=4 train_grpo.py ``` ### Error Handling & Robustness ```python theme={null} # Robust data loading with fallback def load_data_with_fallback(file_path: str, max_examples: int = None): """Load data with automatic fallback to sample data""" def get_fallback_data(): """Return sample data for testing/development""" return [ { "messages": [ {"role": "user", "content": "Where is my order?"}, {"role": "assistant", "content": "I'd be happy to help track your order. Could you please provide your order number?"} ] }, # Add more examples... ] # Try loading actual data if not os.path.exists(file_path): logger.warning(f"Data file not found: {file_path}, using fallback data") return get_fallback_data() try: data = [] with open(file_path, 'r', encoding='utf-8') as f: for line in f: if line.strip(): try: conv = json.loads(line) if validate_conversation(conv): data.append(conv) except json.JSONDecodeError: continue if max_examples and len(data) >= max_examples: break if not data: logger.warning("No valid data loaded, using fallback") return get_fallback_data() return data except Exception as e: logger.error(f"Error loading data: {e}") return get_fallback_data() # Model loading with automatic fallback class ModelManager: def __init__(self, model_name: str, fallback_model: str = "gpt2"): self.model_name = model_name self.fallback_model = fallback_model def load_model_and_tokenizer(self): try: # Try loading requested model return self._load_model(self.model_name) except Exception as e: logger.error(f"Failed to load {self.model_name}: {e}") if self.model_name != self.fallback_model: logger.info(f"Falling back to {self.fallback_model}") return self._load_model(self.fallback_model) else: raise ``` ### Advanced GRPO Configuration ```python theme={null} # Comprehensive GRPO configuration with all options advanced_config = GRPOConfig( # Basic training parameters output_dir="./checkpoints/grpo", per_device_train_batch_size=2, gradient_accumulation_steps=4, learning_rate=1e-5, num_train_epochs=1, # Optimization max_grad_norm=0.5, warmup_steps=50, weight_decay=0.01, adam_epsilon=1e-8, # Mixed precision & performance fp16=True, bf16=False, # Use FP16 instead of BF16 gradient_checkpointing=True, # Logging & checkpointing logging_steps=10, save_steps=100, eval_steps=50, save_total_limit=3, load_best_model_at_end=True, metric_for_best_model="eval_reward", # GRPO specific beta=0.0, # KL penalty (0 = no penalty) num_generations=4, # Responses per prompt num_iterations=1, # GRPO iterations per batch # Generation config max_prompt_length=128, max_completion_length=128, temperature=0.7, top_p=0.9, do_sample=True, # Advanced options use_liger_loss=False, # Experimental loss function ddp_find_unused_parameters=False, # For multi-GPU dataloader_num_workers=4, # Reproducibility seed=42, data_seed=42, ) # Dynamic configuration based on hardware def get_optimal_config(): """Automatically configure based on available hardware""" config = GRPOConfig() # Adjust batch size based on GPU memory if torch.cuda.is_available(): gpu_memory = torch.cuda.get_device_properties(0).total_memory if gpu_memory > 40 * 1024**3: # 40GB+ (A100) config.per_device_train_batch_size = 8 config.gradient_accumulation_steps = 1 elif gpu_memory > 20 * 1024**3: # 20GB+ (A6000) config.per_device_train_batch_size = 4 config.gradient_accumulation_steps = 2 else: # Smaller GPUs config.per_device_train_batch_size = 1 config.gradient_accumulation_steps = 8 # Enable mixed precision on capable GPUs if torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 7: config.fp16 = True return config ``` ### Experiment Tracking & Analysis ```python theme={null} # Comprehensive experiment tracking class ExperimentTracker: def __init__(self, project_name: str, use_wandb: bool = True): self.project_name = project_name self.use_wandb = use_wandb and self._init_wandb() self.metrics_history = [] def _init_wandb(self): try: import wandb wandb.login(key=os.getenv('WANDB_API_KEY')) wandb.init( project=self.project_name, config=CONFIG, name=f"grpo-{datetime.now().strftime('%Y%m%d-%H%M%S')}", tags=["grpo", "customer-service", CONFIG['model_name'].split('/')[-1]] ) return True except Exception as e: logger.warning(f"Wandb init failed: {e}") return False def log_metrics(self, step: int, metrics: dict): """Log training metrics""" self.metrics_history.append({"step": step, **metrics}) if self.use_wandb: import wandb wandb.log(metrics, step=step) # Also log to file for backup with open("metrics.jsonl", "a") as f: f.write(json.dumps({"step": step, **metrics}) + "\n") def log_generation_samples(self, samples: list): """Log example generations""" if self.use_wandb: import wandb table = wandb.Table(columns=["Query", "Generated", "Expected", "Reward"]) for sample in samples: table.add_data( sample['query'], sample['generated'], sample['expected'], sample['reward']['total'] ) wandb.log({"generation_samples": table}) def create_summary_report(self): """Generate training summary""" if not self.metrics_history: return import pandas as pd df = pd.DataFrame(self.metrics_history) summary = { "total_steps": len(df), "final_reward": df['reward'].iloc[-1], "max_reward": df['reward'].max(), "avg_reward": df['reward'].mean(), "reward_improvement": df['reward'].iloc[-1] - df['reward'].iloc[0], } logger.info("Training Summary:") for key, value in summary.items(): logger.info(f" {key}: {value:.4f}") return summary ``` ### Model Deployment Strategies ```python theme={null} # Production deployment with optimization class ProductionDeployment: def __init__(self, checkpoint_dir: str): self.checkpoint_dir = checkpoint_dir def prepare_for_deployment(self): """Optimize model for production inference""" from peft import PeftModel import torch.quantization as quantization # Load model base_model = AutoModelForCausalLM.from_pretrained( CONFIG['model_name'], torch_dtype=torch.float16, device_map='auto' ) # Merge LoRA weights model = PeftModel.from_pretrained(base_model, self.checkpoint_dir) model = model.merge_and_unload() # Optional: Quantization for faster inference if CONFIG.get('quantize_for_deployment', False): model = quantization.quantize_dynamic( model, {torch.nn.Linear}, dtype=torch.qint8 ) # Save optimized model output_dir = f"{self.checkpoint_dir}_production" model.save_pretrained(output_dir) # Also save tokenizer tokenizer = AutoTokenizer.from_pretrained(self.checkpoint_dir) tokenizer.save_pretrained(output_dir) return output_dir def create_inference_api(self, model_path: str): """Create FastAPI endpoint for model inference""" from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() # Load model once at startup model, tokenizer = load_trained_model(model_path) class Query(BaseModel): text: str max_length: int = 128 temperature: float = 0.7 @app.post("/generate") async def generate(query: Query): response = generate_response( model, tokenizer, query.text, max_length=query.max_length, temperature=query.temperature ) return {"response": response} return app ``` ## Troubleshooting Guide ```python theme={null} # Solutions for OOM errors # 1. Reduce batch size config.per_device_train_batch_size = 1 config.gradient_accumulation_steps = 8 # 2. Enable gradient checkpointing config.gradient_checkpointing = True # 3. Use LoRA with smaller rank lora_config.r = 4 # Instead of 8 or 16 # 4. Reduce max sequence length config.max_length = 128 # Instead of 256+ # 5. Use CPU offloading model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", offload_folder="offload", offload_state_dict=True ) ``` ```python theme={null} # Solutions for training instability # 1. Reduce learning rate config.learning_rate = 5e-6 # Instead of 1e-5 # 2. Increase warmup steps config.warmup_steps = 100 # Instead of 50 # 3. Add KL penalty config.beta = 0.01 # Instead of 0.0 # 4. Clip gradients more aggressively config.max_grad_norm = 0.3 # Instead of 0.5 # 5. Use smaller generation count config.num_generations = 2 # Instead of 4+ ``` ```python theme={null} # Improve generation quality # 1. Adjust generation parameters generation_config = { "temperature": 0.8, # Slightly higher for diversity "top_p": 0.95, # Broader sampling "top_k": 50, # Limit vocabulary "repetition_penalty": 1.1, # Reduce repetition } # 2. Improve reward function def enhanced_reward(response): # Add more nuanced scoring scores = { "relevance": check_relevance(response), "completeness": check_completeness(response), "tone": check_tone(response), "grammar": check_grammar(response), } return weighted_average(scores) # 3. Filter training data high_quality_data = [ ex for ex in data if len(ex['response'].split()) > 20 # Min length and len(ex['response'].split()) < 150 # Max length and validate_quality(ex) ] ``` ## Conclusion GRPO represents a paradigm shift in AI training - from passive learning to active optimization. By defining clear objectives through reward functions and allowing models to explore multiple solutions, we create AI systems that don't just mimic but genuinely optimize for desired outcomes. ### Key Implementation Insights Based on real-world GRPO training experience, here are the critical success factors: Training with LoRA adapters reduces memory usage by 90%+ while maintaining performance. Target the attention layers (q\_proj, k\_proj, v\_proj, o\_proj) for best results. Use stratified splitting to maintain task distribution. A 90/10 split provides enough evaluation data while maximizing training examples. Combine similarity, empathy, action-orientation, and length penalties. Weight them based on your specific use case (e.g., 40% similarity, 30% empathy). Begin with batch\_size=2, gradient\_accumulation=4, learning\_rate=1e-5. These settings work well across different model sizes and GPUs. ### Production Checklist * Validate all conversations have proper structure * Ensure minimum response length (>10 words) * Remove duplicates and low-quality examples * Classify by task type for balanced training * Use FP16 mixed precision (not BF16) * Enable gradient checkpointing for large models * Set padding\_side="left" for proper generation * Configure LoRA with r=8, alpha=16 as starting point * Implement robust error handling with fallbacks * Use wandb or similar for experiment tracking * Save checkpoints frequently (every 100 steps) * Monitor reward variance for stability * Run post-training evaluation on held-out data * Track multiple metrics (similarity, quality, length) * Generate sample outputs for manual review * Compare against baseline model performance * Merge LoRA weights for faster inference * Consider quantization for edge deployment * Implement proper error handling in API * Monitor inference latency and quality ### Quick Start Template #### Prerequisites Before starting, ensure you have: * Python 3.8+ * NVIDIA GPU with CUDA 11.0+ (for accelerated training) * Git installed * Optional: Weights & Biases account for experiment tracking Install core dependencies: ```bash theme={null} pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install transformers peft datasets trl scikit-learn wandb fastapi uvicorn ``` #### Step-by-Step Setup ```bash theme={null} # Clone the training template git clone https://github.com/StateSet/grpo-agent cd grpo-agent # Create and activate virtual environment (recommended) python -m venv venv source venv/bin/activate # On Linux/Mac # venv\Scripts\activate # On Windows # Install dependencies pip install -r requirements.txt # Prepare your data # Data should be in JSONL format with conversations: # {"messages": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]} python scripts/prepare_data.py --input your_raw_data.json --output data/training_data.jsonl --max-examples 5000 --validate # Configure training # Edit config.yaml or set environment variables export MODEL_NAME="Qwen/Qwen2.5-7B-Instruct" export BATCH_SIZE=2 export LEARNING_RATE=1e-5 export MAX_EXAMPLES=5000 export EVAL_SPLIT=0.1 export WANDB_API_KEY="your_key_here" # Optional # Run training # Use torchrun for multi-GPU: torchrun --nproc_per_node=2 train_grpo.py python train_grpo.py --data data/training_data.jsonl --config config.yaml # Monitor training # View logs: tail -f grpo_training.log # If using wandb: open the link provided in console # Evaluate results python evaluate.py --checkpoint checkpoints/grpo/final_model --num-samples 10 --output eval_results.json # Deploy as API python deploy.py --model checkpoints/grpo/final_model --port 8080 --host 0.0.0.0 # Test: curl -X POST https://yourapp.com:8080/generate -H "Content-Type: application/json" -d '{"text": "Where is my order?"}' ``` #### Customization Tips * **Small Datasets**: Set NUM\_EPOCHS=3 and NUM\_GENERATIONS=8 * **Large Models**: Enable gradient\_checkpointing in config.yaml * **Debug Mode**: Add --debug to train\_grpo.py for verbose logging * **Resume Training**: Use --resume\_from\_checkpoint checkpoints/grpo/checkpoint-100 ## Common Pitfalls & Solutions **Symptom**: "No valid data loaded" or JSON decode errors **Solutions**: * Ensure JSONL format (one JSON object per line) * Run validation: python scripts/validate\_data.py data.jsonl * Use fallback data for testing: --use-fallback * Check encoding: All files should be UTF-8 **Symptom**: CUDA OOM errors during training **Solutions**: * Reduce per\_device\_train\_batch\_size to 1 * Increase gradient\_accumulation\_steps to 8+ * Use smaller model (e.g., "Qwen/Qwen2.5-3B-Instruct") * Enable fp16 and gradient\_checkpointing * Monitor with: nvidia-smi -l 1 **Symptom**: Low/negative rewards or unstable training **Solutions**: * Normalize rewards to \[-1, 1] range * Test independently: python test\_reward.py --samples 10 * Add epsilon to divisions: score = sum / (len + 1e-5) * Balance weights: Start with equal weights and adjust * Monitor reward distribution in wandb **Symptom**: Repetitive or off-topic responses **Solutions**: * Adjust temperature (0.7-0.9) and top\_p (0.9-0.95) * Add repetition\_penalty=1.2 in generation config * Increase num\_generations to 8 for more exploration * Fine-tune prompt format: Add system instructions * Evaluate diversity: Compute unique n-grams in outputs **Symptom**: Inference fails or slow performance **Solutions**: * Merge LoRA weights before deployment * Use torch.compile(model) for PyTorch 2.0+ * Set device\_map='auto' for multi-GPU inference * Implement batching for multiple requests * Profile with: torch.profiler These pitfalls are based on real-world GRPO implementations - addressing them early will save significant time and resources. ## Getting Started What behavior do you want to optimize for? ```python theme={null} objective = "Maximize customer satisfaction while resolving issues efficiently" ``` Translate objectives into measurable rewards ```python theme={null} reward = CustomerSatisfactionReward( weights={'resolution': 0.5, 'tone': 0.3, 'efficiency': 0.2} ) ``` Collect quality examples (300+ recommended) ```python theme={null} data = prepare_training_data( source="support_tickets", min_quality_score=0.8 ) ``` Start with balanced settings ```python theme={null} model = train_grpo_model( data=data, reward_fn=reward, profile="balanced" ) ``` Test thoroughly before production ```python theme={null} if evaluate(model).meets_criteria(): deploy_to_production(model) ``` ## Advanced Topics ### Multi-Objective Optimization ```python theme={null} class MultiObjectiveReward: def __init__(self, objectives): self.objectives = objectives def compute(self, response, context): scores = {} for name, (weight, function) in self.objectives.items(): scores[name] = function(response, context) * weight # Pareto optimization if self.is_pareto_optimal(scores): bonus = 0.2 else: bonus = 0 return sum(scores.values()) + bonus ``` ### Curriculum Learning ```python theme={null} # Start with easy tasks, gradually increase difficulty curriculum = [ {"difficulty": "easy", "epochs": 1, "reward_scale": 1.0}, {"difficulty": "medium", "epochs": 2, "reward_scale": 0.8}, {"difficulty": "hard", "epochs": 3, "reward_scale": 0.6} ] for stage in curriculum: model = trainer.train( data=filter_by_difficulty(data, stage["difficulty"]), epochs=stage["epochs"], reward_scale=stage["reward_scale"] ) ``` ### Distributed Training ```python theme={null} # Setup for multi-GPU training import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP def setup_distributed_training(): """Initialize distributed training environment""" local_rank = int(os.environ.get("LOCAL_RANK", -1)) world_size = int(os.environ.get("WORLD_SIZE", 1)) if local_rank != -1: # Initialize process group torch.cuda.set_device(local_rank) dist.init_process_group(backend="nccl") logger.info(f"Initialized distributed training: rank {local_rank}/{world_size}") # Only log from main process if local_rank != 0: logging.getLogger().setLevel(logging.WARNING) return local_rank, world_size # Launch distributed training # torchrun --nproc_per_node=4 train_grpo.py ``` ### Error Handling & Robustness ```python theme={null} # Robust data loading with fallback def load_data_with_fallback(file_path: str, max_examples: int = None): """Load data with automatic fallback to sample data""" def get_fallback_data(): """Return sample data for testing/development""" return [ { "messages": [ {"role": "user", "content": "Where is my order?"}, {"role": "assistant", "content": "I'd be happy to help track your order. Could you please provide your order number?"} ] }, # Add more examples... ] # Try loading actual data if not os.path.exists(file_path): logger.warning(f"Data file not found: {file_path}, using fallback data") return get_fallback_data() try: data = [] with open(file_path, 'r', encoding='utf-8') as f: for line in f: if line.strip(): try: conv = json.loads(line) if validate_conversation(conv): data.append(conv) except json.JSONDecodeError: continue if max_examples and len(data) >= max_examples: break if not data: logger.warning("No valid data loaded, using fallback") return get_fallback_data() return data except Exception as e: logger.error(f"Error loading data: {e}") return get_fallback_data() # Model loading with automatic fallback class ModelManager: def __init__(self, model_name: str, fallback_model: str = "gpt2"): self.model_name = model_name self.fallback_model = fallback_model def load_model_and_tokenizer(self): try: # Try loading requested model return self._load_model(self.model_name) except Exception as e: logger.error(f"Failed to load {self.model_name}: {e}") if self.model_name != self.fallback_model: logger.info(f"Falling back to {self.fallback_model}") return self._load_model(self.fallback_model) else: raise ``` ### Advanced GRPO Configuration ```python theme={null} # Comprehensive GRPO configuration with all options advanced_config = GRPOConfig( # Basic training parameters output_dir="./checkpoints/grpo", per_device_train_batch_size=2, gradient_accumulation_steps=4, learning_rate=1e-5, num_train_epochs=1, # Optimization max_grad_norm=0.5, warmup_steps=50, weight_decay=0.01, adam_epsilon=1e-8, # Mixed precision & performance fp16=True, bf16=False, # Use FP16 instead of BF16 gradient_checkpointing=True, # Logging & checkpointing logging_steps=10, save_steps=100, eval_steps=50, save_total_limit=3, load_best_model_at_end=True, metric_for_best_model="eval_reward", # GRPO specific beta=0.0, # KL penalty (0 = no penalty) num_generations=4, # Responses per prompt num_iterations=1, # GRPO iterations per batch # Generation config max_prompt_length=128, max_completion_length=128, temperature=0.7, top_p=0.9, do_sample=True, # Advanced options use_liger_loss=False, # Experimental loss function ddp_find_unused_parameters=False, # For multi-GPU dataloader_num_workers=4, # Reproducibility seed=42, data_seed=42, ) # Dynamic configuration based on hardware def get_optimal_config(): """Automatically configure based on available hardware""" config = GRPOConfig() # Adjust batch size based on GPU memory if torch.cuda.is_available(): gpu_memory = torch.cuda.get_device_properties(0).total_memory if gpu_memory > 40 * 1024**3: # 40GB+ (A100) config.per_device_train_batch_size = 8 config.gradient_accumulation_steps = 1 elif gpu_memory > 20 * 1024**3: # 20GB+ (A6000) config.per_device_train_batch_size = 4 config.gradient_accumulation_steps = 2 else: # Smaller GPUs config.per_device_train_batch_size = 1 config.gradient_accumulation_steps = 8 # Enable mixed precision on capable GPUs if torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 7: config.fp16 = True return config ``` ### Experiment Tracking & Analysis ```python theme={null} # Comprehensive experiment tracking class ExperimentTracker: def __init__(self, project_name: str, use_wandb: bool = True): self.project_name = project_name self.use_wandb = use_wandb and self._init_wandb() self.metrics_history = [] def _init_wandb(self): try: import wandb wandb.login(key=os.getenv('WANDB_API_KEY')) wandb.init( project=self.project_name, config=CONFIG, name=f"grpo-{datetime.now().strftime('%Y%m%d-%H%M%S')}", tags=["grpo", "customer-service", CONFIG['model_name'].split('/')[-1]] ) return True except Exception as e: logger.warning(f"Wandb init failed: {e}") return False def log_metrics(self, step: int, metrics: dict): """Log training metrics""" self.metrics_history.append({"step": step, **metrics}) if self.use_wandb: import wandb wandb.log(metrics, step=step) # Also log to file for backup with open("metrics.jsonl", "a") as f: f.write(json.dumps({"step": step, **metrics}) + "\n") def log_generation_samples(self, samples: list): """Log example generations""" if self.use_wandb: import wandb table = wandb.Table(columns=["Query", "Generated", "Expected", "Reward"]) for sample in samples: table.add_data( sample['query'], sample['generated'], sample['expected'], sample['reward']['total'] ) wandb.log({"generation_samples": table}) def create_summary_report(self): """Generate training summary""" if not self.metrics_history: return import pandas as pd df = pd.DataFrame(self.metrics_history) summary = { "total_steps": len(df), "final_reward": df['reward'].iloc[-1], "max_reward": df['reward'].max(), "avg_reward": df['reward'].mean(), "reward_improvement": df['reward'].iloc[-1] - df['reward'].iloc[0], } logger.info("Training Summary:") for key, value in summary.items(): logger.info(f" {key}: {value:.4f}") return summary ``` ### Model Deployment Strategies ```python theme={null} # Production deployment with optimization class ProductionDeployment: def __init__(self, checkpoint_dir: str): self.checkpoint_dir = checkpoint_dir def prepare_for_deployment(self): """Optimize model for production inference""" from peft import PeftModel import torch.quantization as quantization # Load model base_model = AutoModelForCausalLM.from_pretrained( CONFIG['model_name'], torch_dtype=torch.float16, device_map='auto' ) # Merge LoRA weights model = PeftModel.from_pretrained(base_model, self.checkpoint_dir) model = model.merge_and_unload() # Optional: Quantization for faster inference if CONFIG.get('quantize_for_deployment', False): model = quantization.quantize_dynamic( model, {torch.nn.Linear}, dtype=torch.qint8 ) # Save optimized model output_dir = f"{self.checkpoint_dir}_production" model.save_pretrained(output_dir) # Also save tokenizer tokenizer = AutoTokenizer.from_pretrained(self.checkpoint_dir) tokenizer.save_pretrained(output_dir) return output_dir def create_inference_api(self, model_path: str): """Create FastAPI endpoint for model inference""" from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() # Load model once at startup model, tokenizer = load_trained_model(model_path) class Query(BaseModel): text: str max_length: int = 128 temperature: float = 0.7 @app.post("/generate") async def generate(query: Query): response = generate_response( model, tokenizer, query.text, max_length=query.max_length, temperature=query.temperature ) return {"response": response} return app ``` ## Troubleshooting Guide ```python theme={null} # Solutions for OOM errors # 1. Reduce batch size config.per_device_train_batch_size = 1 config.gradient_accumulation_steps = 8 # 2. Enable gradient checkpointing config.gradient_checkpointing = True # 3. Use LoRA with smaller rank lora_config.r = 4 # Instead of 8 or 16 # 4. Reduce max sequence length config.max_length = 128 # Instead of 256+ # 5. Use CPU offloading model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", offload_folder="offload", offload_state_dict=True ) ``` ```python theme={null} # Solutions for training instability # 1. Reduce learning rate config.learning_rate = 5e-6 # Instead of 1e-5 # 2. Increase warmup steps config.warmup_steps = 100 # Instead of 50 # 3. Add KL penalty config.beta = 0.01 # Instead of 0.0 # 4. Clip gradients more aggressively config.max_grad_norm = 0.3 # Instead of 0.5 # 5. Use smaller generation count config.num_generations = 2 # Instead of 4+ ``` ```python theme={null} # Improve generation quality # 1. Adjust generation parameters generation_config = { "temperature": 0.8, # Slightly higher for diversity "top_p": 0.95, # Broader sampling "top_k": 50, # Limit vocabulary "repetition_penalty": 1.1, # Reduce repetition } # 2. Improve reward function def enhanced_reward(response): # Add more nuanced scoring scores = { "relevance": check_relevance(response), "completeness": check_completeness(response), "tone": check_tone(response), "grammar": check_grammar(response), } return weighted_average(scores) # 3. Filter training data high_quality_data = [ ex for ex in data if len(ex['response'].split()) > 20 # Min length and len(ex['response'].split()) < 150 # Max length and validate_quality(ex) ] ``` ## Conclusion GRPO represents a paradigm shift in AI training - from passive learning to active optimization. By defining clear objectives through reward functions and allowing models to explore multiple solutions, we create AI systems that don't just mimic but genuinely optimize for desired outcomes. ### Key Implementation Insights Based on real-world GRPO training experience, here are the critical success factors: Training with LoRA adapters reduces memory usage by 90%+ while maintaining performance. Target the attention layers (q\_proj, k\_proj, v\_proj, o\_proj) for best results. Use stratified splitting to maintain task distribution. A 90/10 split provides enough evaluation data while maximizing training examples. Combine similarity, empathy, action-orientation, and length penalties. Weight them based on your specific use case (e.g., 40% similarity, 30% empathy). Begin with batch\_size=2, gradient\_accumulation=4, learning\_rate=1e-5. These settings work well across different model sizes and GPUs. ### Production Checklist * Validate all conversations have proper structure * Ensure minimum response length (>10 words) * Remove duplicates and low-quality examples * Classify by task type for balanced training * Use FP16 mixed precision (not BF16) * Enable gradient checkpointing for large models * Set padding\_side="left" for proper generation * Configure LoRA with r=8, alpha=16 as starting point * Implement robust error handling with fallbacks * Use wandb or similar for experiment tracking * Save checkpoints frequently (every 100 steps) * Monitor reward variance for stability * Run post-training evaluation on held-out data * Track multiple metrics (similarity, quality, length) * Generate sample outputs for manual review * Compare against baseline model performance * Merge LoRA weights for faster inference * Consider quantization for edge deployment * Implement proper error handling in API * Monitor inference latency and quality ### Quick Start Template #### Prerequisites Before starting, ensure you have: * Python 3.8+ * NVIDIA GPU with CUDA 11.0+ (for accelerated training) * Git installed * Optional: Weights & Biases account for experiment tracking Install core dependencies: ```bash theme={null} pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install transformers peft datasets trl scikit-learn wandb fastapi uvicorn ``` #### Step-by-Step Setup ```bash theme={null} # Clone the training template git clone https://github.com/StateSet/grpo-agent cd grpo-agent # Create and activate virtual environment (recommended) python -m venv venv source venv/bin/activate # On Linux/Mac # venv\Scripts\activate # On Windows # Install dependencies pip install -r requirements.txt # Prepare your data # Data should be in JSONL format with conversations: # {"messages": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]} python scripts/prepare_data.py --input your_raw_data.json --output data/training_data.jsonl --max-examples 5000 --validate # Configure training # Edit config.yaml or set environment variables export MODEL_NAME="Qwen/Qwen2.5-7B-Instruct" export BATCH_SIZE=2 export LEARNING_RATE=1e-5 export MAX_EXAMPLES=5000 export EVAL_SPLIT=0.1 export WANDB_API_KEY="your_key_here" # Optional # Run training # Use torchrun for multi-GPU: torchrun --nproc_per_node=2 train_grpo.py python train_grpo.py --data data/training_data.jsonl --config config.yaml # Monitor training # View logs: tail -f grpo_training.log # If using wandb: open the link provided in console # Evaluate results python evaluate.py --checkpoint checkpoints/grpo/final_model --num-samples 10 --output eval_results.json # Deploy as API python deploy.py --model checkpoints/grpo/final_model --port 8080 --host 0.0.0.0 # Test: curl -X POST https://yourapp.com:8080/generate -H "Content-Type: application/json" -d '{"text": "Where is my order?"}' ``` #### Customization Tips * **Small Datasets**: Set NUM\_EPOCHS=3 and NUM\_GENERATIONS=8 * **Large Models**: Enable gradient\_checkpointing in config.yaml * **Debug Mode**: Add --debug to train\_grpo.py for verbose logging * **Resume Training**: Use --resume\_from\_checkpoint checkpoints/grpo/checkpoint-100 ## Common Pitfalls & Solutions **Symptom**: "No valid data loaded" or JSON decode errors **Solutions**: * Ensure JSONL format (one JSON object per line) * Run validation: python scripts/validate\_data.py data.jsonl * Use fallback data for testing: --use-fallback * Check encoding: All files should be UTF-8 **Symptom**: CUDA OOM errors during training **Solutions**: * Reduce per\_device\_train\_batch\_size to 1 * Increase gradient\_accumulation\_steps to 8+ * Use smaller model (e.g., "Qwen/Qwen2.5-3B-Instruct") * Enable fp16 and gradient\_checkpointing * Monitor with: nvidia-smi -l 1 **Symptom**: Low/negative rewards or unstable training **Solutions**: * Normalize rewards to \[-1, 1] range * Test independently: python test\_reward.py --samples 10 * Add epsilon to divisions: score = sum / (len + 1e-5) * Balance weights: Start with equal weights and adjust * Monitor reward distribution in wandb **Symptom**: Repetitive or off-topic responses **Solutions**: * Adjust temperature (0.7-0.9) and top\_p (0.9-0.95) * Add repetition\_penalty=1.2 in generation config * Increase num\_generations to 8 for more exploration * Fine-tune prompt format: Add system instructions * Evaluate diversity: Compute unique n-grams in outputs **Symptom**: Inference fails or slow performance **Solutions**: * Merge LoRA weights before deployment * Use torch.compile(model) for PyTorch 2.0+ * Set device\_map='auto' for multi-GPU inference * Implement batching for multiple requests * Profile with: torch.profiler These pitfalls are based on real-world GRPO implementations - addressing them early will save significant time and resources. ### Quick Start Template ```bash theme={null} # Clone the training template git clone https://github.com/StateSet/grpo-agent cd grpo-agent # Install dependencies pip install transformers peft datasets trl scikit-learn wandb # Prepare your data (JSONL format with conversations) python prepare_data.py --input your_data.json --output training_data.jsonl # Configure environment export MODEL_NAME="Qwen/Qwen2.5-7B-Instruct" export BATCH_SIZE=2 export LEARNING_RATE=1e-5 export MAX_EXAMPLES=5000 export WANDB_API_KEY="your_key_here" # Run training python train_grpo.py --data training_data.jsonl # Evaluate results python evaluate.py --checkpoint ./checkpoints/grpo/final_model # Deploy model python deploy.py --model ./checkpoints/grpo/final_model --port 8080 ``` Deep dive into GRPO implementation Ready-to-run training scripts Get help with your implementation *** **Next Step**: Ready to implement GRPO? Check out our [GRPO Agent Framework](/guides/grpo-agent-framework) for a complete implementation guide. Transform your AI models from pattern matchers to goal achievers with StateSet's Reinforcement Learning platform powered by GRPO. # ResponseCX Source: https://docs.stateset.com/guides/response-quickstart An introductory guide to building powerful AI agents with ResponseCX. ## What is ResponseCX? ResponseCX is a platform for building and deploying autonomous AI agents, especially for e-commerce businesses using platforms like Shopify. These agents can handle customer service inquiries, answer questions by accessing knowledge bases and APIs, and provide 24/7 support to your customers. *** ## ✨ Key Features * **Autonomous Conversation Agents** – Multi‑turn agents that reason, call tools, and improve over time. * **Omni‑Channel Routing** – Unified inbox across web chat, email, SMS, WhatsApp, voice, and social. * **Grounded Knowledge** – Connect Sources (docs, FAQs, tickets) and external APIs/vector stores to ground responses. * **Tool‑Calling Workflows** – Agents take actions via StateSet One, Sync Server integrations, or your own webhooks. * **Cloud‑Native Scale** – Stateless, horizontally scalable runtime with streaming responses. * **Custom Training (Optional)** – Train specialized agents with the open‑source `StateSet-agents` RL framework. *** ## 🏗️ Architecture Overview ```mermaid theme={null} graph LR User[Customer Channels] --> RCX[ResponseCX Agent] RCX -->|tools| One[StateSet One API] RCX -->|explainable reasoning| NSR[NSR Engine] One --> Sync[Sync Server] Sync --> Ext[External Platforms] RCX --> Sources[Sources / KB / Vector Stores] ``` * **ResponseCX Agents** interpret intent, draft responses, and decide when to act. * **Sources** ground agents in your business knowledge. * **Tool Targets** include StateSet One, Sync Server integrations, NSR reasoning, and your own APIs. ## How It Works At its core, ResponseCX follows a simple but powerful process: 1. **Interpret:** It understands the customer's question, comment, or request. 2. **Generate:** It formulates the best response by consulting your company's knowledge, which can include FAQs, documents, and even external APIs. 3. **Respond:** It delivers the correct answer to the customer in real-time. ## Your First Steps in ResponseCX Ready to build your first agent? Follow these steps to get started. First, [sign in to ResponseCX](https://response.cx). Once you're in, create an Organization. Your current organization is displayed in the bottom-left corner. Navigate to the **Agents** tab and click the **Add New Agent** button. Give your agent a name and a purpose. For more details, see our [Agents Quickstart](/guides/agents-quickstart). Click the chat icon in the top-left corner to start a new conversation. Give your chat a name, and select the agent you just created. You can also choose the underlying language model. We support models like GPT-4o, Llama3-70b, and Claude 3.5 Sonnet. ## Building Your Agent's Knowledge An agent is only as smart as the information it has access to. You can build your agent's knowledge base directly from the chat interface. Use these chat commands to manage your agent's knowledge base. * `!add`: Adds a new piece of information. * `!update`: Modifies existing information. * `!delete`: Removes a piece of information. **Example:** > `!add The return policy is 30 days for a full refund.` After adding data, you can immediately test the agent by asking questions about it. For more advanced knowledge management, you can create **Sources**. Learn more in our [Sources Quickstart](/guides/sources-quickstart). ## Customizing Agent Behavior You can fine-tune your agent's personality and decision-making using Attributes and Rules. ### Agent Attributes Attributes define your agent's characteristics. Go to the **Agents** tab and select the agent you want to configure. Click on **Attributes** and then **Add Attribute**. Define its type, name, and description. Use the slider or input field to assign a value to the attribute. Click **Add Attribute** to save it. ### Agent Rules Rules are conditional statements that guide your agent's behavior. Go to the **Agents** tab and select the agent. Click on **Rules** and then **Add Rule**. Give the rule a name, a description, and define the condition that triggers it. Click **Add Rule** to save. ## Next Steps You've now learned the basics of creating and customizing an agent in ResponseCX. Here's what you can do next: * Dive deeper into [agent configuration](/guides/agents-quickstart). * Learn about connecting different [information sources](/guides/sources-quickstart). * Explore how to create complex [rules and schedules](/guides/rules-quickstart) for your agents. # Returns Quickstart Source: https://docs.stateset.com/guides/returns-quickstart Getting started with the StateSet Returns API - Complete guide to automating your returns process ## Introduction StateSet One provides a comprehensive REST and GraphQL API for Returns Management, enabling businesses to automate their entire returns process from initiation to refund. This guide will walk you through building a complete returns management system. The Returns Management module in StateSet includes various objects that facilitate the returns processes. These objects typically encompass: * Return * Return Line Items * Orders * Refunds ### Returns Management Overview Returns are an inevitable part of the eCommerce business. Customers may request returns for a variety of reasons, such as receiving a damaged or defective item, or simply changing their mind about a purchase. Regardless of the reason, it is important for businesses to have a streamlined process in place to manage returns efficiently and effectively. This helps in enhancing customer experience and building brand loyalty. #### Challenges with Returns Management Returns management can be a complex and time-consuming process. It involves multiple steps, such as generating return labels, creating returns in the system, and processing refunds. These steps are often manual and require significant time and effort. This can lead to delays in processing returns, resulting in customer dissatisfaction and loss of revenue. #### StateSet's Returns Management Solution StateSet's Returns Management solution automates the entire returns process, from generating return labels to processing refunds. This helps in streamlining the process and reducing the time and effort required to manage returns. The solution leverages the Temporal workflow orchestration framework to automate the various steps involved in returns management. This includes generating and emailing return labels, creating returns in StateSet, providing search capabilities for efficient record retrieval, updating customer support platforms with tracking information, and processing instant refunds. By automating the returns process, StateSet enables businesses to effectively manage and track returns, thereby enhancing customer experience and improving operational efficiency. ## Prerequisites Before you begin, ensure you have: * A StateSet account ([Sign up here](https://StateSet.com/sign-up)) * API credentials from the [StateSet Cloud Console](https://cloud.StateSet.com/api-keys) * Node.js 16+ installed (for SDK examples) * Basic understanding of REST APIs * Your eCommerce platform credentials (Shopify, WooCommerce, etc.) ## Quickstart Guide Install the StateSet-node SDK in your project: ```bash theme={null} npm install StateSet-node # or yarn add StateSet-node ``` Set up your StateSet client with proper error handling: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.NODE_ENV || 'production' }); ``` Create a new return with validation: ```javascript theme={null} async function createReturn(orderData) { try { // Validate input data if (!orderData.order_id || !orderData.items) { throw new Error('Missing required fields'); } const returnData = { order_id: orderData.order_id, customer_email: orderData.customer_email, items: orderData.items.map(item => ({ sku: item.sku, quantity: item.quantity, reason: item.reason, condition: item.condition || 'A' })), status: 'NEW', type: orderData.return_type || 'REPLACEMENT', notes: orderData.customer_notes }; const return = await client.returns.create(returnData); // Generate RMA number const rma = `RMA-${return.id}`; await client.returns.update(return.id, { rma }); return { success: true, return, rma }; } catch (error) { logger.error('Failed to create return:', error); throw new Error(`Return creation failed: ${error.message}`); } } ``` Automatically generate and email return shipping labels: ```javascript theme={null} async function generateReturnLabel(returnId, shippingAddress) { try { const label = await client.shipping.createReturnLabel({ return_id: returnId, carrier: 'fedex', service: 'FEDEX_GROUND', from_address: shippingAddress, to_address: { name: 'Returns Center', company: 'Your Company', street1: '123 Warehouse St', city: 'Los Angeles', state: 'CA', zip: '90001', country: 'US' } }); // Email label to customer await client.notifications.send({ type: 'return_label', return_id: returnId, attachments: [{ filename: `return-label-${returnId}.pdf`, content: label.label_pdf_base64, encoding: 'base64' }] }); return label; } catch (error) { logger.error('Label generation failed:', error); throw error; } } ``` #### Return Initiation When a customer requests a return, the Returns Management workflow in StateSet is triggered. The workflow captures the necessary information from the customer, such as order details, reason for return, and any supporting documentation. Return Record #### Return Label Generation and Emailing Using the captured information, the workflow generates a return label that includes the shipping address and other relevant details. The label is then emailed to the customer, providing clear instructions on how to return the item. #### Creation of a Return in StateSet Simultaneously, the workflow creates a new return in StateSet, associating it with the corresponding order and customer information. This allows for streamlined tracking and management of the return process within the StateSet platform. #### StateSet Workflow using Temporal Temporal is an open source programming model that can simplify your code, make your applications more reliable, and help you deliver more features faster. The temporal framework allows activities to be defined and workflows to execute them based on the state or specific signals. Temporal provides the workflow management engine to combine the power of serverless API calls with a deterministic scheduler for execution. By leveraging the Temporal workflow orchestration framework, StateSet automates the entire Returns Management (RMA) process. This includes generating and emailing return labels, creating returns in StateSet, providing search capabilities for efficient record retrieval, updating customer support platforms with tracking information, and processing instant refunds. This automation streamlines the return process, enhances customer experience, and enables businesses to effectively manage and track returns. Here is an example of StateSet's Return API using Temporal Worker & Workflow: ```jsx javascript theme={null} import { Worker } from '@temporalio/worker'; import { URL } from 'url'; import * as activities from './activities.js'; async function run() { const worker = await Worker.create({ workflowsPath: new URL('./workflows/return-ticket-approved.js', import.meta.url).pathname, activities, taskQueue: 'StateSet-returns-automation', namespace: 'StateSet' }); await worker.run(); } run().catch((err) => { logger.error(err); process.exit(1); }); ``` ```jsx javascript theme={null} import { proxyActivities } from '@temporalio/workflow'; import * as wf from '@temporalio/workflow'; // Proxy Activities const { generateResponse, createZendeskComment, createReturnRecord, generateUSLabel, generateCALabel, updateWorkflowId, updateMatch, cancelSubscription } = proxyActivities({ startToCloseTimeout: '1 minute', }); /** A workflow that simply calls an activity */ export async function returnApprovedWorkflow(body, ticket_id_int) { let workflow_state = []; var cancel_subscription = body.cancel_subscription; var condition = body.condition; var match = body.match; var country = body.country; // Generate Response await generateResponse(body); // Generate Label if (country = "US") { await generateUSLabel(ticket_id_int); } else { await generateCALabel(ticket_id_int); } // Create Return var return_id = await createReturnRecord(ticket_id_int); // Update Workflow Id await updateWorkflowId(return_id, wf.workflowInfo().workflowId); // Cance Subscription if (cancel_subscription) { await cancelSubscription(customer_email, ticket_id_int); }; // Sleep await wf.sleep('3 days'); // If Instant Refund and Conditon = A if (condition == "A" && match == true) { const matched_return = await updateMatch(return_id, wf.workflowInfo().workflowId); await refundOrder(order_id); await createZendeskComment(ticket_id_int, condition); return 'return_and_refund_processed'; } } ``` #### Search and Lookup Capabilities The Returns Management workflow in StateSet incorporates search functionality powered by Algolia that enables easy retrieval of return information. Users can search for returns based on various criteria, such as serial number, RMA number, or order ID. This helps in quickly locating specific return records and accessing relevant details. ```jsx javascript theme={null} // Save the Return Record to the Algolia Index index.saveObject({ objectID: return_record.insert_returns.returning[0].id, order_id: return_record.insert_returns.returning[0].order_id, description: return_record.insert_returns.returning[0].description, reported_condition: return_record.insert_returns.returning[0].reported_condition, status: return_record.insert_returns.returning[0].status, serial_number: return_record.insert_returns.returning[0].serial_number, tracking_number: return_record.insert_returns.returning[0].tracking_number, rma: return_record.insert_returns.returning[0].rma, country: return_record.insert_returns.returning[0].country }) ``` #### Instant Refunds Processing For eligible returns, the Returns Management workflow includes instant refund processing. Once the returned item is received and inspected, the workflow automatically initiates the refund process, facilitating timely and efficient reimbursement to the customer. This eliminates delays and enhances customer satisfaction by ensuring prompt resolution of return requests. #### Integration with Zendesk or Gorgias The workflow integrates with customer support platforms like Zendesk or Gorgias to streamline communication and updates. Upon generating the return label and initiating the return process, the workflow updates the respective ticketing system with tracking information. This ensures that customer support representatives have real-time visibility into the status of returns and can provide accurate updates to customers when needed. #### Aftership Tracking ```jsx javascript theme={null} export default async function (req, res) { var newReturn = req.body.event.data.new; var timestamp = req.body.created_at; var event_id = newReturn.id; var order_id = newReturn.order_id; var serial_number = newReturn.serial_number; var rma = newReturn.rma; var email = newReturn.customerEmail; var tracking_number = newReturn.tracking_number; var token = process.env.AFTERSHIP_TOKEN try { // Notification let aftership_tracking_response = await fetch('https://api.aftership.com/v4/trackings', { method: 'POST', headers: { 'Content-Type': 'application/json', 'aftership-api-key': token }, body: JSON.stringify({ "tracking" : { "tracking_number": tracking_number, "slug": "fedex", "title": rma, "emails": [ "customer@gmail.com" ], "order_id": order_id, "custom_fields": { "label_created_date": timestamp, "customer_email": email, "serial_number": serial_number, "workflow_event_id": event_id, } } }) }) logger.info(aftership_tracking_response); return res.status(200).json({ status: "AfterShip Tracking API Event Successfully Executed" }); } catch (error) { return res.status(500).json({ "error_code": "internal_error", "error_message": error.toString ? error.toString() : error }) }; }; ``` #### Refunds Refunds describes the general data about the goods or services being refunded to your customers. For example, you might have multiple line items on an order, each would be a separate Refund Line Item. The Refund is corresponding to the metadata regarding Refunde Items. The Refund resource has two major components: * Transaction records of money returned to the customer * The line items included in the refund, along with restocking instructions Before you create a refund, use the calculate endpoint to generate accurate refund transactions. Specify the line items that are being refunded, their quantity and restock instructions, and whether you're refunding shipping costs. You can then use the response of the calculate endpoint to create the actual refund. When you create a refund using the response from the calculate endpoint, you can set additional options, such as whether to notify the customer of the refund. You can refund less than the calculated amount for either shipping or the line items by setting a custom value for the amount property. #### Shopify refunds StateSet Returns Automation integrates with Shopify's native Return APIs. For more information see the StateSet Returns Automation App on the Shopify App Store: [https://apps.shopify.com/StateSet-returns-automation](https://apps.shopify.com/StateSet-returns-automation) Here is an example of how to process a Refund using the Shopify Returns API: ```jsx javascript theme={null} try { const suggestedRefund = await getSuggestedRefund( returnId, returnLineItems, shop, accessToken ); const returnQuery = gql` mutation returnRefundMutation( $returnLineItems: [ReturnRefundLineItemInput!]!, $refundShipping: RefundShippingInput, $orderTransactions: [ReturnRefundOrderTransactionInput!] ) { returnRefund( returnRefundInput: { returnId: "${returnId}", returnRefundLineItems: $returnLineItems, refundShipping: $refundShipping, orderTransactions: $orderTransactions } ) { refund { id } userErrors { field message } } }`; const returnResponseJson: any = await ShopifyClient( shop, accessToken, returnQuery, { returnLineItems, refundShipping: { fullRefund: true, shippingRefundAmount: { amount: suggestedRefund?.shipping?.maximumRefundableSet ?.shopMoney?.amount || 0, currencyCode: suggestedRefund?.shipping?.maximumRefundableSet ?.shopMoney?.currencyCode || 'USD' } }, orderTransactions: suggestedRefund?.suggestedTransactions?.map((item: any) => { return { transactionAmount: { amount: item.amountSet?.shopMoney?.amount || 0, currencyCode: item.amountSet?.shopMoney?.currencyCode || 'USD' }, parentId: item.parentTransaction.id }; }) || [] } ); logger.info( returnResponseJson.returnRefund.userErrors, returnResponseJson.returnRefund ); if (returnResponseJson.returnRefund.userErrors?.length) { const message = returnResponseJson.returnRefund.userErrors[0].message; res.status(500).send(message); return; } if (returnResponseJson?.returnRefund?.refund) { await updateReturn(id, { status: 'REFUNDED' }); return res.status(200).json({ ...returnResponseJson.returnRefund.refund, msg: 'Successful Refund Return' }); } res.status(500).send('There is no refund Transaction'); } catch (error: any) { logger.info(error); res.status(500).send(error.message); } }); ``` If a refund includes shipping costs, or if you choose to refund line items for less than their calculated amount, then an order adjustment is created automatically to account for the discrepancy in the store's financial reports. #### WooCommerce Refunds The return record in StateSet will include customer information such as the order id which is used to query the total order amount and tax amount. These values are used to calculate the total refund amount depending on the restocking fee. A refund can be placed via the Return record which will trigger a refund in WooCommerce and then Stripe. It may take a few days for the refund to appear on the customers debit card. The refund can be verified in StateSet by going to the Stripe returns list view. The condition and rationale from the return record can also be sent back to Zendesk from StateSet as a private message for the CSR. ```jsx javascript theme={null} // refund for the item being returned var refund_line_item = { "id": item_id, "quantity": 1, "refund_total": item_total - restocking_fee, "refund_tax": refund_tax_line_item_items }; // Process Refund Automatically // Automated Refund Data const data = { "api_refund": true, "reason": reason_category, "line_items": refund_line_items }; // POST Request Options var requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }; // Process Refund await fetch(`https://ecommerce.com/wp-json/wc/v3/orders/${order_id_int}/refunds`, requestOptions) .then(response => response.json()) .then(json => {}) ``` ## Complete Returns Workflow Implementation Here's a production-ready implementation of a complete returns management system: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import { TemporalClient } from '@temporalio/client'; class ReturnsManagementService { constructor(apiKey) { this.client = new StateSetClient({ apiKey }); this.temporal = new TemporalClient(); } /** * Complete returns workflow with all steps automated */ async processReturnRequest(request) { const workflow = { steps: [], errors: [], returnId: null }; try { // Step 1: Validate return eligibility const eligibility = await this.checkReturnEligibility(request.order_id); if (!eligibility.eligible) { throw new Error(`Return not eligible: ${eligibility.reason}`); } workflow.steps.push({ step: 'eligibility_check', status: 'completed' }); // Step 2: Create return record const return = await this.createReturnWithValidation(request); workflow.returnId = return.id; workflow.steps.push({ step: 'return_created', status: 'completed', returnId: return.id }); // Step 3: Generate return label const label = await this.generateAndSendLabel(return.id, request.shipping_address); workflow.steps.push({ step: 'label_generated', status: 'completed', trackingNumber: label.tracking_number }); // Step 4: Start Temporal workflow for automation const workflowHandle = await this.startReturnWorkflow(return.id); workflow.steps.push({ step: 'workflow_started', status: 'completed', workflowId: workflowHandle.workflowId }); // Step 5: Update support systems await this.updateSupportSystems(return.id, request.ticket_id); workflow.steps.push({ step: 'support_updated', status: 'completed' }); // Step 6: Set up tracking await this.setupReturnTracking(return.id, label.tracking_number); workflow.steps.push({ step: 'tracking_setup', status: 'completed' }); return { success: true, returnId: return.id, rma: return.rma, trackingNumber: label.tracking_number, workflow: workflow }; } catch (error) { workflow.errors.push({ step: workflow.steps.length, error: error.message, timestamp: new Date() }); // Attempt to clean up partial return if (workflow.returnId) { await this.client.returns.update(workflow.returnId, { status: 'ERROR', error_message: error.message }); } throw error; } } async checkReturnEligibility(orderId) { const order = await this.client.orders.get(orderId); const daysSincePurchase = Math.floor((Date.now() - new Date(order.created_at)) / (1000 * 60 * 60 * 24)); if (daysSincePurchase > 30) { return { eligible: false, reason: 'Outside 30-day return window' }; } if (order.status === 'RETURNED') { return { eligible: false, reason: 'Order already returned' }; } return { eligible: true }; } async createReturnWithValidation(request) { // Validate all items are from the same order const order = await this.client.orders.get(request.order_id); const validSkus = order.items.map(item => item.sku); for (const item of request.items) { if (!validSkus.includes(item.sku)) { throw new Error(`SKU ${item.sku} not found in order ${request.order_id}`); } } // Create return with enriched data const returnData = { order_id: request.order_id, customer_email: order.customer_email, items: request.items, status: 'NEW', type: request.return_type, reason_code: request.reason_code, customer_notes: request.notes, metadata: { ip_address: request.ip_address, user_agent: request.user_agent, created_via: 'api' } }; return await this.client.returns.create(returnData); } async generateAndSendLabel(returnId, customerAddress) { const label = await this.client.shipping.createReturnLabel({ return_id: returnId, from_address: customerAddress, carrier: this.selectOptimalCarrier(customerAddress), service: 'GROUND', insurance: true, reference_1: returnId }); // Send label via multiple channels await Promise.all([ this.client.notifications.email({ return_id: returnId, template: 'return_label', attachments: [label] }), this.client.notifications.sms({ return_id: returnId, message: `Your return label is ready. Tracking: ${label.tracking_number}` }) ]); return label; } async startReturnWorkflow(returnId) { return await this.temporal.workflow.start('returnApprovedWorkflow', { taskQueue: 'returns-automation', workflowId: `return-${returnId}`, args: [{ returnId }] }); } async updateSupportSystems(returnId, ticketId) { if (ticketId) { // Update Zendesk/Gorgias await this.client.support.updateTicket(ticketId, { status: 'pending', tags: ['return_initiated'], custom_fields: { return_id: returnId } }); } } async setupReturnTracking(returnId, trackingNumber) { // Set up webhook for tracking updates await this.client.webhooks.create({ url: `${process.env.WEBHOOK_URL}/returns/${returnId}/tracking`, events: ['tracking.updated'], filters: { tracking_number: trackingNumber } }); // Register with Aftership or similar await this.client.tracking.create({ tracking_number: trackingNumber, carrier: 'auto-detect', reference: returnId, notify_customer: true }); } selectOptimalCarrier(address) { // Logic to select best carrier based on location if (address.country === 'US') { return address.state === 'HI' || address.state === 'AK' ? 'usps' : 'fedex'; } return 'ups'; } } // Usage example const returnsService = new ReturnsManagementService(process.env.STATESET_API_KEY); // Express.js endpoint app.post('/api/returns', async (req, res) => { try { const result = await returnsService.processReturnRequest(req.body); res.json(result); } catch (error) { res.status(400).json({ error: error.message, code: error.code || 'RETURN_FAILED' }); } }); ``` ## Error Handling and Recovery ```javascript theme={null} class ReturnErrorHandler { static async handleReturnError(error, context) { const errorHandlers = { 'RATE_LIMIT': this.handleRateLimit, 'INVALID_ORDER': this.handleInvalidOrder, 'SHIPPING_FAILED': this.handleShippingFailure, 'REFUND_FAILED': this.handleRefundFailure }; const handler = errorHandlers[error.code] || this.handleGenericError; return await handler(error, context); } static async handleRateLimit(error, context) { // Implement exponential backoff const retryAfter = error.retryAfter || 60; await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); return { retry: true, delay: retryAfter }; } static async handleShippingFailure(error, context) { // Try alternative carrier const alternativeCarriers = ['ups', 'usps', 'fedex']; const failedCarrier = context.carrier; const nextCarrier = alternativeCarriers.find(c => c !== failedCarrier); return { retry: true, overrides: { carrier: nextCarrier } }; } static async handleRefundFailure(error, context) { // Queue for manual review await context.client.tasks.create({ type: 'manual_refund_review', priority: 'high', data: { return_id: context.returnId, error: error.message, attempted_at: new Date() } }); return { retry: false, escalate: true }; } } ``` ## Monitoring and Analytics ```javascript theme={null} class ReturnsAnalytics { constructor(client) { this.client = client; } async trackReturnMetrics(returnId, event, metadata = {}) { await this.client.analytics.track({ event: `return.${event}`, properties: { return_id: returnId, timestamp: new Date(), ...metadata } }); } async getReturnInsights(timeframe = '30d') { const metrics = await this.client.analytics.query({ metrics: [ 'returns.total', 'returns.by_reason', 'returns.processing_time', 'returns.refund_amount' ], timeframe, groupBy: ['reason_code', 'product_category'] }); return this.generateInsights(metrics); } generateInsights(metrics) { return { summary: { total_returns: metrics.returns.total, avg_processing_time: metrics.returns.processing_time.avg, total_refunded: metrics.returns.refund_amount.sum }, top_reasons: metrics.returns.by_reason.slice(0, 5), recommendations: this.generateRecommendations(metrics) }; } } ``` ## Best Practices 1. **Always validate return eligibility** before creating a return 2. **Use idempotency keys** to prevent duplicate returns 3. **Implement proper error handling** with retry logic 4. **Track all return events** for analytics and debugging 5. **Automate refunds** for qualified returns to improve customer satisfaction 6. **Integrate with your support platform** for seamless customer service 7. **Monitor return patterns** to identify product issues 8. **Use webhooks** for real-time status updates ## Troubleshooting * Verify order exists and is eligible for return * Check API key permissions * Ensure all required fields are provided * Validate SKUs match the original order * Confirm shipping address is valid * Check carrier API credentials * Verify account has sufficient shipping balance * Try alternative carrier if primary fails * Ensure payment gateway credentials are configured * Verify refund amount doesn't exceed original payment * Check for partial refunds on the order * Review payment processor logs ## Support For additional help with returns management: * 📧 Email: [support@StateSet.com](mailto:support@StateSet.com) * 📚 Documentation: [docs.StateSet.com/returns](https://docs.StateSet.com/returns) * 💬 Community: [community.StateSet.com](https://community.StateSet.com) * 🎫 Submit a ticket: [support.StateSet.com](https://support.StateSet.com) # Agent Rules Quickstart Source: https://docs.stateset.com/guides/rules-quickstart Create intelligent, context-aware behaviors for your AI agents with powerful rule-based automation ## Introduction Agent Rules are the decision-making engine of your StateSet agents. They enable sophisticated, context-aware behaviors that adapt to customer needs, business policies, and real-time conditions. This guide will show you how to create rules that make your agents truly intelligent. ## What are Agent Rules? Rules define how your agents respond to specific situations. They work on an "if-then" basis but can incorporate complex logic, multiple conditions, and sophisticated actions. Think of rules as your agent's decision tree—guiding every interaction toward the best possible outcome. ### How Rules Work ```mermaid theme={null} graph TD A[Customer Message] --> B{Evaluate Rules} B --> C{Condition 1?} C -->|Yes| D[Execute Action 1] C -->|No| E{Condition 2?} E -->|Yes| F[Execute Action 2] E -->|No| G{Condition 3?} G -->|Yes| H[Execute Action 3] G -->|No| I[Default Response] D --> J[Continue Conversation] F --> J H --> J I --> J ``` ## Why Rules Matter Ensure every customer gets the right answer, every time Embed your policies and procedures directly into agent behavior Adjust responses based on context, customer history, and real-time data ## Getting Started ### Prerequisites 1. StateSet account with API access 2. At least one agent created 3. Understanding of your business rules and policies Code examples focus on core API calls. For production-ready patterns (structured logging, retries, and error handling), see [Error Handling Best Practices](/guides/error-handling-best-practices). ### Installation ```bash npm theme={null} npm install StateSet-node ``` ```bash yarn theme={null} yarn add StateSet-node ``` ```bash pip theme={null} pip install StateSet ``` ## Creating Rules ### Basic Rule Structure Every rule consists of: * **Name**: Unique identifier * **Conditions**: When the rule should trigger * **Actions**: What should happen * **Priority**: Order of execution * **Scope**: Where the rule applies ### Simple Rule Example Let's start with a basic rule for handling refund inquiries: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); async function createRefundRule(agentId) { const rule = await client.rules.create({ agent_id: agentId, name: 'refund_inquiry_handler', description: 'Handles customer refund inquiries with appropriate care', priority: 100, // Higher priority executes first conditions: { any: [ { field: 'message.text', operator: 'contains', value: 'refund' }, { field: 'message.text', operator: 'contains', value: 'money back' }, { field: 'message.text', operator: 'matches', value: '/return.*money/i' } ] }, actions: [ { type: 'set_attribute', attribute: 'conversation_tone', value: 'empathetic_professional' }, { type: 'add_context', context: { topic: 'refund', sensitivity: 'high', require_order_lookup: true } }, { type: 'send_message', message: 'I understand you have questions about a refund. I\'d be happy to help you with that. Could you please provide your order number?' } ], metadata: { category: 'customer_service', compliance: 'required', last_reviewed: new Date().toISOString() } }); return rule; } ``` ### Complex Rule with Multiple Conditions Here's a more sophisticated rule that considers customer history and order value: ```javascript theme={null} async function createVIPCustomerRule(agentId) { const vipRule = await client.rules.create({ agent_id: agentId, name: 'vip_customer_treatment', description: 'Provides premium service to VIP customers', priority: 200, // Executes before standard rules conditions: { all: [ { any: [ { field: 'customer.lifetime_value', operator: 'greater_than', value: 5000 }, { field: 'customer.tier', operator: 'equals', value: 'platinum' }, { field: 'customer.orders_count', operator: 'greater_than', value: 50 } ] }, { field: 'conversation.sentiment', operator: 'in', value: ['negative', 'very_negative'] } ] }, actions: [ { type: 'escalate', target: 'vip_support_team', priority: 'immediate' }, { type: 'set_attribute', attribute: 'service_level', value: 'white_glove' }, { type: 'apply_discount', discount_type: 'percentage', value: 10, code: 'VIP_CARE' }, { type: 'send_message', message: 'I sincerely apologize for any inconvenience. As one of our valued customers, I\'m immediately escalating this to our VIP support team who will assist you right away.' }, { type: 'log_event', event: 'vip_escalation', data: { customer_id: '{{customer.id}}', reason: 'negative_sentiment', automated: true } } ] }); return vipRule; } ``` ## Advanced Rule Patterns ### Time-Based Rules Create rules that adapt based on time of day, business hours, or dates: ```javascript theme={null} const afterHoursRule = await client.rules.create({ agent_id: agentId, name: 'after_hours_support', conditions: { any: [ { field: 'current_time', operator: 'outside_range', value: { start: '09:00', end: '17:00', timezone: 'America/New_York' } }, { field: 'current_day', operator: 'in', value: ['Saturday', 'Sunday'] }, { field: 'current_date', operator: 'in', value: ['2024-12-25', '2024-01-01'] // Holidays } ] }, actions: [ { type: 'set_expectation', message: 'Thanks for reaching out! Our team is currently offline, but I can still help with many requests.' }, { type: 'limit_functions', allowed: ['order_status', 'track_package', 'faq_lookup'], message_on_restricted: 'For this request, our human team will need to assist you. They\'ll respond within one business day.' } ] }); ``` ### Dynamic Routing Rules Route conversations based on content and context: ```javascript theme={null} const routingRule = await client.rules.create({ agent_id: agentId, name: 'intelligent_routing', priority: 300, conditions: { evaluate: 'routing_logic' }, routing_logic: ` // Technical issues go to tech support if (message.text.match(/error|bug|crash|not working/i)) { return 'technical_support'; } // Billing issues to finance team if (message.text.match(/charge|bill|payment|invoice/i)) { return 'billing_team'; } // Sales inquiries to sales team if (message.text.match(/pricing|discount|upgrade|plan/i) && !customer.is_existing) { return 'sales_team'; } // VIP customers always get premium support if (customer.tier === 'vip' || customer.lifetime_value > 10000) { return 'vip_support'; } // Default to general support return 'general_support'; `, actions: [ { type: 'route_to_team', team: '{{routing_result}}', transfer_context: true, message: 'I\'m connecting you with our {{routing_result.friendly_name}} team who can best assist with your request.' } ] }); ``` ### Compliance and Security Rules Ensure sensitive data is handled appropriately: ```javascript theme={null} const complianceRule = await client.rules.create({ agent_id: agentId, name: 'pii_protection', priority: 500, // Highest priority conditions: { any: [ { field: 'message.text', operator: 'matches', value: '/\\b\\d{3}-\\d{2}-\\d{4}\\b/' // SSN pattern }, { field: 'message.text', operator: 'matches', value: '/\\b(?:\\d{4}[\\s-]?){3}\\d{4}\\b/' // Credit card pattern } ] }, actions: [ { type: 'mask_sensitive_data', patterns: ['ssn', 'credit_card'], replacement: '[REDACTED]' }, { type: 'send_message', message: 'For your security, please don\'t share sensitive information like SSN or credit card numbers in chat. I can help you without this information.' }, { type: 'log_security_event', event_type: 'pii_attempted', severity: 'medium' } ] }); ``` ## Rule Conditions ### Condition Operators StateSet supports a comprehensive set of operators: ```javascript theme={null} // Comparison operators { field: 'order.total', operator: 'greater_than', value: 100 } { field: 'customer.age', operator: 'between', value: { min: 18, max: 65 } } // String operators { field: 'message.text', operator: 'contains', value: 'urgent' } { field: 'customer.email', operator: 'ends_with', value: '@company.com' } { field: 'product.sku', operator: 'matches', value: '/^PROD-\\d{6}$/' } // Array operators { field: 'customer.tags', operator: 'includes', value: 'vip' } { field: 'order.items', operator: 'includes_any', value: ['electronics', 'computers'] } // Date operators { field: 'customer.created_at', operator: 'before', value: '2024-01-01' } { field: 'order.date', operator: 'within_last', value: { amount: 30, unit: 'days' } } // Null checks { field: 'customer.phone', operator: 'is_null', value: true } { field: 'order.discount_code', operator: 'is_not_null', value: true } ``` ### Complex Condition Logic Combine conditions with AND/OR logic: ```javascript theme={null} const complexRule = await client.rules.create({ conditions: { all: [ // AND logic { any: [ // OR logic { field: 'customer.status', operator: 'equals', value: 'gold' }, { field: 'customer.lifetime_value', operator: 'greater_than', value: 1000 } ] }, { field: 'current_promotion.active', operator: 'equals', value: true }, { not: { // NOT logic field: 'customer.flags', operator: 'includes', value: 'promotional_opt_out' } } ] } }); ``` ## Rule Actions ### Available Action Types ```javascript theme={null} // Conversation Control { type: 'set_attribute', attribute: 'tone', value: 'formal' } { type: 'add_tag', tag: 'urgent_issue' } { type: 'set_priority', level: 'high' } // Message Actions { type: 'send_message', message: 'Your custom message here' } { type: 'send_template', template_id: 'welcome_back_vip' } { type: 'suggest_responses', options: ['Yes', 'No', 'Tell me more'] } // Function Execution { type: 'execute_function', function: 'check_inventory', params: { sku: '{{product.sku}}' } } { type: 'disable_function', function: 'process_payment', reason: 'after_hours' } // Routing and Escalation { type: 'route_to_team', team: 'technical_support' } { type: 'escalate_to_human', priority: 'immediate', reason: '{{escalation_reason}}' } // Data Operations { type: 'update_customer', fields: { last_contact: '{{current_timestamp}}' } } { type: 'create_ticket', priority: 'medium', category: 'billing' } { type: 'log_event', event: 'rule_triggered', data: { rule_id: '{{rule.id}}' } } ``` ### Action Sequencing Control the flow of actions: ```javascript theme={null} const sequencedRule = await client.rules.create({ actions: [ { type: 'execute_function', function: 'check_order_status', store_result: 'order_status' }, { type: 'conditional_action', condition: 'order_status.status === "shipped"', then: { type: 'send_message', message: 'Great news! Your order has shipped and is on its way.' }, else: { type: 'send_message', message: 'Your order is being prepared and will ship soon.' } } ] }); ``` ## Testing Rules ### Rule Testing Framework ```javascript theme={null} async function testRule(ruleId, testCases) { const results = await client.rules.test({ rule_id: ruleId, test_cases: testCases }); results.forEach(result => { logger.info(`Test Case: ${result.name}`); logger.info(`Expected: ${result.expected}`); logger.info(`Actual: ${result.actual}`); logger.info(`Passed: ${result.passed}`); }); return results; } // Define test cases const testCases = [ { name: 'VIP customer with complaint', input: { message: { text: 'This service is terrible!' }, customer: { tier: 'vip', lifetime_value: 15000 }, conversation: { sentiment: 'very_negative' } }, expected_actions: ['escalate', 'apply_discount'] }, { name: 'Regular customer inquiry', input: { message: { text: 'What are your business hours?' }, customer: { tier: 'standard' }, conversation: { sentiment: 'neutral' } }, expected_actions: ['send_message'] } ]; await testRule(vipRule.id, testCases); ``` ## Rule Management ### Rule Versioning Keep track of rule changes: ```javascript theme={null} const ruleWithVersion = await client.rules.create({ agent_id: agentId, name: 'return_policy_v2', version: '2.0.0', changelog: 'Updated return window from 30 to 60 days', replaces: 'rule_abc123', // ID of previous version effective_date: '2024-02-01', actions: [ { type: 'send_message', message: 'Our return policy allows returns within 60 days of purchase.' } ] }); ``` ### Bulk Rule Operations Manage multiple rules efficiently: ```javascript theme={null} // Import rules from configuration async function importRules(agentId, rulesConfig) { const imported = await client.rules.bulkCreate({ agent_id: agentId, rules: rulesConfig, conflict_resolution: 'skip', // or 'overwrite' validate_before_import: true }); logger.info(`Imported ${imported.success.length} rules`); if (imported.failures.length > 0) { logger.error('Failed imports:', imported.failures); } } // Export rules for backup async function exportRules(agentId) { const rules = await client.rules.export({ agent_id: agentId, format: 'json', include_disabled: false }); // Save to file or version control fs.writeFileSync('rules-backup.json', JSON.stringify(rules, null, 2)); } ``` ## Monitoring & Analytics ### Rule Performance Tracking ```javascript theme={null} // Get rule analytics const analytics = await client.rules.getAnalytics({ rule_id: ruleId, timeframe: '30d', metrics: ['trigger_count', 'success_rate', 'avg_execution_time'] }); logger.info(`Rule Performance: Triggered: ${analytics.trigger_count} times Success Rate: ${analytics.success_rate}% Avg Execution: ${analytics.avg_execution_time}ms Most Common Trigger: ${analytics.top_trigger_condition} `); // Set up alerts await client.rules.createAlert({ rule_id: ruleId, alert_conditions: [ { metric: 'error_rate', threshold: 5, window: '1h', notification: 'email' } ] }); ``` ## Best Practices ### 1. Rule Priority and Order ```javascript theme={null} // Good: Clear priority hierarchy const rules = [ { name: 'security_check', priority: 1000 }, // Always first { name: 'compliance_filter', priority: 900 }, // Before business logic { name: 'vip_treatment', priority: 500 }, // Special handling { name: 'standard_routing', priority: 100 }, // Normal flow { name: 'fallback_handler', priority: 1 } // Catch-all ]; ``` ### 2. Performance Optimization ```javascript theme={null} // Optimize condition checking const efficientRule = await client.rules.create({ conditions: { // Check simple conditions first all: [ { field: 'message.length', operator: 'less_than', value: 10 }, // Fast { field: 'customer.tier', operator: 'equals', value: 'vip' }, // Fast { field: 'message.text', operator: 'matches', value: '/complex.*regex/i' } // Slower ] }, // Cache results for repeated checks cache_ttl: 300 // 5 minutes }); ``` ### 3. Error Handling ```javascript theme={null} const robustRule = await client.rules.create({ error_handling: { on_condition_error: 'skip_rule', on_action_error: 'continue_next_action', fallback_message: 'I encountered an issue, but I\'m still here to help!', log_errors: true } }); ``` ## Common Patterns ### Customer Segmentation Rules ```javascript theme={null} const segmentationRules = [ { name: 'new_customer_welcome', conditions: { field: 'customer.orders_count', operator: 'equals', value: 0 }, actions: [{ type: 'send_template', template: 'first_time_buyer_welcome' }] }, { name: 'loyal_customer_perks', conditions: { field: 'customer.orders_count', operator: 'greater_than', value: 10 }, actions: [{ type: 'apply_loyalty_discount', percentage: 15 }] }, { name: 'win_back_inactive', conditions: { field: 'customer.last_order_date', operator: 'before', value: '90_days_ago' }, actions: [{ type: 'send_template', template: 'we_miss_you_offer' }] } ]; ``` ### Contextual Help Rules ```javascript theme={null} const contextualHelpRule = await client.rules.create({ name: 'smart_help_suggestions', conditions: { evaluate: ` const keywords = message.text.toLowerCase(); const page = context.current_page; if (page === 'checkout' && keywords.includes('coupon')) { return 'show_coupon_help'; } else if (page === 'product' && keywords.includes('size')) { return 'show_size_guide'; } else if (keywords.includes('ship')) { return 'show_shipping_info'; } return null; ` }, actions: [ { type: 'dynamic_action', action: '{{evaluation_result}}' } ] }); ``` ## Troubleshooting ### Common Issues 1. **Rules Not Triggering** * Check rule priority and order * Verify conditions are correctly formatted * Ensure rule is enabled and not expired 2. **Conflicting Rules** * Use priority levels to control execution order * Implement exclusive rule groups * Add conflict detection in conditions 3. **Performance Issues** * Optimize complex regex patterns * Use caching for expensive operations * Limit the number of active rules ## Next Steps Pre-built rules for common scenarios Master complex rule logic *** **Pro Tip**: Start with simple rules and gradually add complexity. Use the testing framework to validate rules before deploying to production. For support and examples, visit our [GitHub repository](https://github.com/StateSet/rule-examples) or contact [support@StateSet.com](mailto:support@StateSet.com). # Agent Schedules & Automation Source: https://docs.stateset.com/guides/schedules-quickstart Build powerful time-based automation workflows for your StateSet agents ## Introduction StateSet Schedules transform your agents from reactive responders to proactive assistants. By automating time-based actions, your agents can anticipate needs, follow up on conversations, perform routine maintenance, and ensure nothing falls through the cracks. This guide shows you how to build sophisticated scheduling systems that work 24/7. ## What are Agent Schedules? Agent Schedules are intelligent automation rules that trigger actions based on time. Unlike simple cron jobs, StateSet Schedules are context-aware, can adapt to business logic, and integrate seamlessly with your agent's capabilities. ### Key Features Cron expressions, intervals, or business calendar rules Conditional logic, timezone awareness, and holiday handling Guaranteed execution with retry logic and monitoring ## Use Cases * Follow up 24 hours after purchase * Check in weekly with VIP customers * Send satisfaction surveys after support tickets close * Remind about expiring subscriptions * Daily inventory checks * Hourly order status updates * Weekly performance reports * Monthly billing reconciliation * Monitor for abandoned carts * Check unresolved tickets * Escalate aging issues * Perform health checks ## Getting Started ### Prerequisites 1. StateSet account with scheduling enabled 2. At least one configured agent 3. Understanding of cron expressions (optional) Code examples focus on core API calls. For production-ready patterns (structured logging, retries, and error handling), see [Error Handling Best Practices](/guides/error-handling-best-practices). ### Installation ```bash npm theme={null} npm install StateSet-node @StateSet/scheduler ``` ```bash yarn theme={null} yarn add StateSet-node @StateSet/scheduler ``` ```bash pip theme={null} pip install StateSet StateSet-scheduler ``` ## Creating Schedules ### Basic Schedule Example ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); async function createDailyCheckIn() { const schedule = await client.schedules.create({ agent_id: 'agent_123', name: 'daily_customer_check_in', description: 'Check in with customers who have open issues', schedule: { type: 'cron', expression: '0 9 * * 1-5', // 9 AM weekdays timezone: 'America/New_York' }, action: { type: 'function', function: 'check_open_issues', parameters: { priority: 'high', age_days: 2 } }, enabled: true, metadata: { category: 'customer_success', owner: 'support_team' } }); logger.info('Schedule created:', schedule.id); return schedule; } ``` ### Advanced Schedule with Conditions ```javascript theme={null} async function createSmartFollowUp() { const schedule = await client.schedules.create({ agent_id: 'agent_123', name: 'smart_purchase_follow_up', description: 'Intelligent post-purchase follow-up based on order value and customer type', // Complex scheduling rules schedule: { type: 'event_based', trigger: 'order.completed', delay: { unit: 'hours', value: 24, business_hours_only: true }, conditions: [ { field: 'order.total', operator: 'greater_than', value: 100 }, { field: 'customer.lifetime_value', operator: 'greater_than', value: 500 } ] }, // Dynamic action based on context action: { type: 'workflow', steps: [ { type: 'evaluate', condition: 'order.total > 1000', true_action: { type: 'send_message', template: 'vip_thank_you', channel: 'email' }, false_action: { type: 'send_message', template: 'standard_thank_you', channel: 'email' } }, { type: 'wait', duration: '7d' }, { type: 'send_message', template: 'product_review_request', channel: 'sms' } ] }, // Error handling error_handling: { retry_attempts: 3, retry_delay: '5m', on_failure: 'create_ticket' } }); return schedule; } ``` ## Schedule Types ### 1. Cron-Based Schedules ```javascript theme={null} // Common cron patterns const cronPatterns = { // Every hour hourly: '0 * * * *', // Every day at 9 AM daily_morning: '0 9 * * *', // Every Monday at 10 AM weekly_monday: '0 10 * * 1', // First day of month at midnight monthly_start: '0 0 1 * *', // Every 15 minutes during business hours business_quarter_hour: '*/15 9-17 * * 1-5', // Last Friday of month at 5 PM monthly_last_friday: '0 17 * * 5L' }; // Create schedule with cron const cronSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'hourly_metrics_check', schedule: { type: 'cron', expression: cronPatterns.hourly, timezone: 'UTC' }, action: { type: 'function', function: 'collect_hourly_metrics' } }); ``` ### 2. Interval-Based Schedules ```javascript theme={null} const intervalSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'continuous_monitoring', schedule: { type: 'interval', every: { unit: 'minutes', value: 30 }, start_time: '2024-01-01T00:00:00Z', end_time: '2024-12-31T23:59:59Z' }, action: { type: 'function', function: 'monitor_system_health' } }); ``` ### 3. Event-Triggered Schedules ```javascript theme={null} const eventSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'abandoned_cart_recovery', schedule: { type: 'event_based', trigger: 'cart.abandoned', delay: { unit: 'hours', value: 2 }, conditions: [ { field: 'cart.value', operator: 'greater_than', value: 50 } ] }, action: { type: 'workflow', workflow_id: 'abandoned_cart_recovery_flow' } }); ``` ### 4. Business Calendar Schedules ```javascript theme={null} const businessSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'quarterly_business_review', schedule: { type: 'business_calendar', calendar: 'fiscal_2024', events: [ 'quarter_end', 'quarter_start' ], offset: { days: -5, business_days_only: true } }, action: { type: 'function', function: 'prepare_quarterly_report' }, notifications: { on_start: ['email:manager@company.com'], on_complete: ['slack:#reports'] } }); ``` ## Complex Workflows ### Multi-Step Customer Journey ```javascript theme={null} async function createCustomerJourneySchedule() { const journey = await client.schedules.create({ agent_id: 'agent_123', name: 'new_customer_onboarding', description: 'Automated 30-day onboarding journey', schedule: { type: 'journey', trigger: 'customer.created', steps: [ { delay: '1h', action: 'send_welcome_email' }, { delay: '1d', action: 'check_first_login', condition: 'customer.logins == 0', true_action: 'send_login_reminder' }, { delay: '3d', action: 'send_getting_started_guide' }, { delay: '7d', action: 'schedule_onboarding_call', condition: 'customer.plan == "enterprise"' }, { delay: '14d', action: 'send_feature_highlights' }, { delay: '30d', action: 'send_feedback_survey' } ] }, tracking: { metrics: ['completion_rate', 'engagement_score'], report_to: 'customer_success_dashboard' } }); return journey; } ``` ### Intelligent Escalation System ```javascript theme={null} async function createEscalationSchedule() { const escalation = await client.schedules.create({ agent_id: 'agent_123', name: 'ticket_escalation_system', schedule: { type: 'continuous', check_interval: '15m' }, rules: [ { name: 'urgent_escalation', condition: { all: [ { field: 'ticket.priority', operator: 'equals', value: 'urgent' }, { field: 'ticket.age_minutes', operator: 'greater_than', value: 30 }, { field: 'ticket.status', operator: 'not_equals', value: 'resolved' } ] }, action: { type: 'escalate', to: 'senior_support', notification: 'immediate' } }, { name: 'standard_escalation', condition: { all: [ { field: 'ticket.priority', operator: 'equals', value: 'normal' }, { field: 'ticket.age_hours', operator: 'greater_than', value: 4 } ] }, action: { type: 'escalate', to: 'support_lead', notification: 'email' } }, { name: 'vip_escalation', condition: { all: [ { field: 'customer.tier', operator: 'equals', value: 'vip' }, { field: 'ticket.age_minutes', operator: 'greater_than', value: 15 } ] }, action: { type: 'escalate', to: 'vip_support', notification: 'phone' } } ] }); return escalation; } ``` ## Schedule Management ### Monitoring and Analytics ```javascript theme={null} class ScheduleMonitor { async getScheduleMetrics(scheduleId, timeframe = '7d') { const metrics = await client.schedules.getMetrics({ schedule_id: scheduleId, timeframe: timeframe, metrics: [ 'execution_count', 'success_rate', 'average_duration', 'failure_reasons' ] }); return { health: this.calculateHealth(metrics), performance: { executions: metrics.execution_count, success_rate: `${metrics.success_rate}%`, avg_duration: `${metrics.average_duration}ms`, reliability: this.calculateReliability(metrics) }, issues: this.identifyIssues(metrics), recommendations: this.generateRecommendations(metrics) }; } calculateHealth(metrics) { if (metrics.success_rate >= 99) return 'excellent'; if (metrics.success_rate >= 95) return 'good'; if (metrics.success_rate >= 90) return 'fair'; return 'poor'; } identifyIssues(metrics) { const issues = []; if (metrics.success_rate < 95) { issues.push({ type: 'reliability', severity: 'high', message: `Success rate ${metrics.success_rate}% is below threshold` }); } if (metrics.average_duration > 5000) { issues.push({ type: 'performance', severity: 'medium', message: 'Schedule execution taking longer than expected' }); } return issues; } } ``` ### Bulk Schedule Operations ```javascript theme={null} // Pause all schedules for maintenance async function pauseAllSchedules(reason) { const schedules = await client.schedules.list({ filter: { enabled: true } }); const results = await Promise.all( schedules.map(schedule => client.schedules.update({ id: schedule.id, enabled: false, pause_reason: reason, paused_at: new Date().toISOString() }) ) ); logger.info(`Paused ${results.length} schedules`); return results; } // Migrate schedules to new timezone async function migrateScheduleTimezones(fromTz, toTz) { const schedules = await client.schedules.list({ filter: { 'schedule.timezone': fromTz, 'schedule.type': 'cron' } }); for (const schedule of schedules) { const updatedCron = convertCronTimezone( schedule.schedule.expression, fromTz, toTz ); await client.schedules.update({ id: schedule.id, schedule: { ...schedule.schedule, expression: updatedCron, timezone: toTz } }); } } ``` ## Testing Schedules ### Test Framework ```javascript theme={null} class ScheduleTester { async testSchedule(scheduleId, options = {}) { const testRun = await client.schedules.test({ schedule_id: scheduleId, mode: options.mode || 'dry_run', test_data: options.testData || {}, simulate_time: options.simulateTime || new Date() }); return { would_execute: testRun.would_execute, execution_time: testRun.execution_time, action_preview: testRun.action_preview, validation_errors: testRun.validation_errors, estimated_duration: testRun.estimated_duration }; } async simulateScheduleRun(scheduleId, days = 7) { const simulations = []; const schedule = await client.schedules.get(scheduleId); for (let i = 0; i < days * 24; i++) { const simulatedTime = new Date(); simulatedTime.setHours(simulatedTime.getHours() + i); const wouldRun = this.evaluateCron( schedule.schedule.expression, simulatedTime, schedule.schedule.timezone ); if (wouldRun) { simulations.push({ time: simulatedTime, action: schedule.action }); } } return { schedule_id: scheduleId, simulation_period: `${days} days`, expected_runs: simulations.length, run_times: simulations }; } } // Usage const tester = new ScheduleTester(); const results = await tester.simulateScheduleRun('schedule_123', 30); logger.info(`Schedule would run ${results.expected_runs} times in 30 days`); ``` ## Error Handling & Recovery ### Robust Error Handling ```javascript theme={null} const resilientSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'critical_daily_task', schedule: { type: 'cron', expression: '0 2 * * *' // 2 AM daily }, action: { type: 'function', function: 'process_daily_reports' }, error_handling: { retry_strategy: { max_attempts: 5, delays: [30, 60, 300, 900, 1800], // seconds backoff_type: 'exponential' }, failure_actions: [ { after_attempts: 3, action: { type: 'notify', channel: 'email', recipients: ['oncall@company.com'], template: 'schedule_failure_warning' } }, { after_attempts: 5, action: { type: 'escalate', create_incident: true, severity: 'high', assign_to: 'oncall_engineer' } } ], recovery: { type: 'compensating_action', action: 'run_backup_process', notify_on_recovery: true } }, monitoring: { alert_on_miss: true, alert_on_delay: { threshold_minutes: 15 }, health_check_endpoint: 'https://status.company.com/schedules/daily_task' } }); ``` ### Schedule Dependencies ```javascript theme={null} async function createDependentSchedules() { // Parent schedule const parentSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'data_collection', schedule: { type: 'cron', expression: '0 1 * * *' }, action: { type: 'function', function: 'collect_daily_data' } }); // Child schedule that depends on parent const childSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'data_processing', schedule: { type: 'dependent', depends_on: parentSchedule.id, trigger: 'on_success', delay: '30m' }, action: { type: 'function', function: 'process_collected_data' } }); // Grandchild schedule const reportSchedule = await client.schedules.create({ agent_id: 'agent_123', name: 'report_generation', schedule: { type: 'dependent', depends_on: childSchedule.id, trigger: 'on_complete', conditions: [ { field: 'output.record_count', operator: 'greater_than', value: 0 } ] }, action: { type: 'function', function: 'generate_report' } }); return { parentSchedule, childSchedule, reportSchedule }; } ``` ## Best Practices ### 1. Design for Reliability ```javascript theme={null} // Good: Idempotent actions with proper error handling const reliableSchedule = { action: { type: 'function', function: 'process_orders', parameters: { mode: 'idempotent', check_processed: true, batch_size: 100 } }, error_handling: { retry_attempts: 3, alert_on_failure: true } }; // Bad: Non-idempotent actions without safeguards const unreliableSchedule = { action: { type: 'function', function: 'send_emails', parameters: { send_all: true // Could send duplicates } } }; ``` ### 2. Timezone Awareness ```javascript theme={null} // Good: Explicit timezone handling const timezoneAwareSchedule = { schedule: { type: 'cron', expression: '0 9 * * 1-5', timezone: 'America/New_York', observe_dst: true }, metadata: { business_hours: '9 AM - 5 PM EST/EDT', skip_holidays: true } }; // Bad: Ambiguous timing const ambiguousSchedule = { schedule: { type: 'cron', expression: '0 9 * * *' // Which 9 AM? } }; ``` ### 3. Performance Optimization ```javascript theme={null} class ScheduleOptimizer { // Batch similar schedules async optimizeSchedules() { const schedules = await client.schedules.list(); // Group schedules by execution time const grouped = this.groupByExecutionTime(schedules); // Create batch processors for (const [time, group] of Object.entries(grouped)) { if (group.length > 5) { await this.createBatchSchedule(time, group); } } } async createBatchSchedule(time, schedules) { return client.schedules.create({ name: `batch_processor_${time}`, schedule: { type: 'cron', expression: time }, action: { type: 'batch', actions: schedules.map(s => s.action), parallel: true, max_concurrent: 10 } }); } } ``` ## Troubleshooting ### Common Issues 1. **Schedule Not Executing** * Verify timezone settings * Check schedule is enabled * Validate cron expression * Review execution logs 2. **Missed Executions** * Check system time sync * Review resource limits * Verify agent availability * Check for conflicting schedules 3. **Performance Issues** * Batch similar operations * Optimize action execution * Use appropriate intervals * Monitor resource usage ### Debug Tools ```javascript theme={null} // Schedule debugger async function debugSchedule(scheduleId) { const debug = await client.schedules.debug({ schedule_id: scheduleId, include: ['execution_history', 'next_runs', 'conflicts'] }); logger.info('Schedule Debug Info:'); logger.info('- Status:', debug.status); logger.info('- Last run:', debug.last_execution); logger.info('- Next 5 runs:', debug.next_runs.slice(0, 5);); logger.info('- Conflicts:', debug.conflicts); logger.info('- Error rate:', debug.error_rate); return debug; } ``` ## Next Steps Build complex multi-step automated processes Create reactive systems with event-based scheduling *** **Pro Tip**: Start with simple schedules and gradually add complexity. Always test schedules in a staging environment before deploying to production. For schedule templates and examples, visit our [GitHub repository](https://github.com/StateSet/schedule-examples) or contact [support@StateSet.com](mailto:support@StateSet.com). # SDK Installation & Setup Guide Source: https://docs.stateset.com/guides/sdk-installation Complete guide for installing and configuring StateSet SDKs across different programming languages and environments # SDK Installation & Setup Guide Get up and running with StateSet SDKs in minutes. This guide covers everything from installation to advanced configuration across all supported languages and frameworks. **New to StateSet?** Start with our [5-minute quickstart](/quickstart) to understand the basics before diving into SDK installation. ## 🚀 Quick Start Choose your language and get started in under 5 minutes: ```bash Node.js theme={null} npm install StateSet-node ``` ```bash Python theme={null} pip install StateSet-python ``` ```bash Ruby theme={null} gem install StateSet-ruby ``` ```bash PHP theme={null} composer require StateSet/StateSet-php ``` ## 📦 Supported SDKs StateSet provides official SDKs for the following languages: Most Popular Full TypeScript support with async/await AI/ML Ready Perfect for data science and backend APIs Rails Optimized Native Rails and Sinatra integration WordPress Ready Compatible with Laravel and WordPress ## 🎯 Which SDK Should I Use? **Recommended: Node.js/TypeScript SDK** * ✅ Best for React, Next.js, Vue, Angular * ✅ Full TypeScript support * ✅ Excellent async/await handling * ✅ Largest community and ecosystem **Recommended: Python SDK** * ✅ Best for data processing and analytics * ✅ Native pandas/numpy integration * ✅ Perfect for Jupyter notebooks * ✅ Great for FastAPI/Django backends **Recommended: Ruby SDK** * ✅ Native Rails integration * ✅ ActiveRecord-style syntax * ✅ Sidekiq/Resque job support * ✅ Convention over configuration **Recommended: PHP SDK** * ✅ PSR-compliant implementation * ✅ WordPress plugin ready * ✅ Laravel service provider included * ✅ Composer autoloading *** ## Node.js SDK ### Prerequisites ```bash theme={null} node --version # Should output v16.0.0 or higher ``` Node.js 16+ is required. For older versions, use `StateSet-node@legacy` ```bash theme={null} npm --version # Should be 7.0.0+ # OR yarn --version # Should be 1.22.0+ # OR pnpm --version # Should be 6.0.0+ ``` ```bash theme={null} tsc --version # Should output Version 4.5.0 or higher ``` ### Installation ```bash theme={null} # Install the main SDK npm install StateSet-node # Install type definitions (if using TypeScript) npm install --save-dev @types/node # Install recommended utilities npm install dotenv winston axios-retry ``` ```bash theme={null} # Install the main SDK yarn add StateSet-node # Install type definitions (if using TypeScript) yarn add --dev @types/node # Install recommended utilities yarn add dotenv winston axios-retry ``` ```bash theme={null} # Install the main SDK pnpm add StateSet-node # Install type definitions (if using TypeScript) pnpm add --save-dev @types/node # Install recommended utilities pnpm add dotenv winston axios-retry ``` ### Quick Setup ```bash theme={null} mkdir my-StateSet-app && cd my-StateSet-app npm init -y npm install StateSet-node dotenv # Create project structure mkdir -p src/{services,utils,config} touch .env .env.example .gitignore ``` ```bash theme={null} # .env STATESET_API_KEY=sk_live_your_actual_key_here STATESET_ENVIRONMENT=production STATESET_WEBHOOK_SECRET=whsec_3rK9pL7nQ2xS5mT8... STATESET_LOG_LEVEL=info STATESET_TIMEOUT=30000 STATESET_MAX_RETRIES=3 ``` ```bash theme={null} # .env.example (commit this to git) STATESET_API_KEY=your_api_key_here STATESET_ENVIRONMENT=sandbox STATESET_WEBHOOK_SECRET=your_webhook_secret_here STATESET_LOG_LEVEL=info STATESET_TIMEOUT=30000 STATESET_MAX_RETRIES=3 ``` ```bash theme={null} # .gitignore node_modules/ .env .env.local dist/ *.log ``` ```javascript theme={null} // src/config/StateSet.js import { StateSetClient } from 'StateSet-node'; import dotenv from 'dotenv'; dotenv.config(); // Validate required environment variables const requiredEnvVars = ['STATESET_API_KEY']; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } } // Create and export configured client export const StateSet = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.STATESET_ENVIRONMENT || 'sandbox', timeout: parseInt(process.env.STATESET_TIMEOUT || '30000'), maxRetries: parseInt(process.env.STATESET_MAX_RETRIES || '3'), telemetry: true // Help us improve the SDK }); // Export configuration for reference export const config = { environment: process.env.STATESET_ENVIRONMENT || 'sandbox', logLevel: process.env.STATESET_LOG_LEVEL || 'info', webhookSecret: process.env.STATESET_WEBHOOK_SECRET }; ``` ### Basic Configuration ```javascript theme={null} // app.js import { StateSet, config } from './src/config/StateSet.js'; // Test the connection with proper error handling async function testConnection() { try { const health = await StateSet.health.check(); logger.info('✅ Connected to StateSet:', { status: health.status, environment: config.environment, version: health.version }); // Test basic API access const { data: orders } = await StateSet.orders.list({ limit: 1 }); logger.info('✅ API Access verified:', orders.length, 'orders found'); } catch (error) { logger.error('❌ Connection failed:', { message: error.message, code: error.code, statusCode: error.statusCode }); process.exit(1); } } // Run tests testConnection(); ``` ```typescript theme={null} // app.ts import { StateSetClient, StateSetConfig, StateSetError } from 'StateSet-node'; import dotenv from 'dotenv'; dotenv.config(); // Type-safe configuration interface AppConfig { StateSet: StateSetConfig; app: { environment: 'development' | 'staging' | 'production'; logLevel: 'debug' | 'info' | 'warn' | 'error'; }; } const config: AppConfig = { StateSet: { apiKey: process.env.STATESET_API_KEY!, environment: (process.env.STATESET_ENVIRONMENT as 'sandbox' | 'production') || 'sandbox', timeout: parseInt(process.env.STATESET_TIMEOUT || '30000'), maxRetries: parseInt(process.env.STATESET_MAX_RETRIES || '3'), telemetry: true }, app: { environment: (process.env.NODE_ENV as any) || 'development', logLevel: (process.env.LOG_LEVEL as any) || 'info' } }; const client = new StateSetClient(config.StateSet); // Type-safe error handling async function testConnection(): Promise { try { const health = await client.health.check(); logger.info('✅ Connected to StateSet:', health); // Test with proper types const { data: orders } = await client.orders.list({ limit: 1, status: 'pending' }); logger.info(`✅ Found ${orders.length} orders`); } catch (error) { if (error instanceof StateSetError) { logger.error('StateSet API Error:', { message: error.message, code: error.code, statusCode: error.statusCode, requestId: error.requestId }); } else { logger.error('Unexpected error:', error); } process.exit(1); } } testConnection(); ``` ```javascript theme={null} // app.js const { StateSetClient } = require('StateSet-node'); require('dotenv').config(); // Create client with error handling let client; try { client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.STATESET_ENVIRONMENT || 'sandbox', timeout: 30000, maxRetries: 3 }); } catch (error) { logger.error('Failed to initialize StateSet client:', error.message); process.exit(1); } // Test the connection client.health.check() .then(health => { logger.info('✅ Connected to StateSet:', health.status); return client.orders.list({ limit: 1 }); }) .then(({ data: orders }) => { logger.info('✅ API Access verified:', orders.length, 'orders found'); }) .catch(error => { logger.error('❌ Connection failed:', error.message); process.exit(1); }); ``` ### Advanced Configuration ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import axios from 'axios'; import axiosRetry from 'axios-retry'; // Create custom axios instance const httpClient = axios.create({ timeout: 60000, headers: { 'User-Agent': 'MyApp/1.0.0' } }); // Configure retry logic axiosRetry(httpClient, { retries: 5, retryDelay: axiosRetry.exponentialDelay, retryCondition: (error) => { return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 429; // Retry on rate limit } }); // Use custom HTTP client const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, httpClient: httpClient }); ``` ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import { HttpsProxyAgent } from 'https-proxy-agent'; const proxyAgent = new HttpsProxyAgent('http://proxy.company.com:8080'); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, httpAgent: proxyAgent, httpsAgent: proxyAgent }); ``` ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import winston from 'winston'; // Create Winston logger const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), transports: [ new winston.transports.Console({ format: winston.format.simple() }), new winston.transports.File({ filename: 'StateSet-errors.log', level: 'error' }) ] }); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, logger: logger }); ``` ### Framework Integration ```javascript theme={null} // server.js import express from 'express'; import { StateSetClient } from 'StateSet-node'; import morgan from 'morgan'; import helmet from 'helmet'; const app = express(); // Security and logging middleware app.use(helmet()); app.use(morgan('combined')); app.use(express.json()); // Initialize StateSet client const StateSet = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox' }); // StateSet middleware app.use((req, res, next) => { req.StateSet = StateSet; next(); }); // Error handling middleware const asyncHandler = (fn) => (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; // Routes app.get('/api/orders', asyncHandler(async (req, res) => { const { page = 1, limit = 20, status } = req.query; const { data: orders, pagination } = await req.StateSet.orders.list({ page: parseInt(page), limit: parseInt(limit), status: status }); res.json({ success: true, data: orders, pagination }); })); app.post('/api/orders', asyncHandler(async (req, res) => { const order = await req.StateSet.orders.create({ customer_id: req.body.customer_id, items: req.body.items, shipping_address: req.body.shipping_address }); res.status(201).json({ success: true, data: order }); })); // Global error handler app.use((err, req, res, next) => { logger.error('Error:', err); if (err.name === 'StateSetError') { return res.status(err.statusCode || 400).json({ success: false, error: { message: err.message, code: err.code, requestId: err.requestId } }); } res.status(500).json({ success: false, error: { message: 'Internal server error' } }); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { logger.info(`Server running on port ${PORT}`); }); ``` ```typescript theme={null} // lib/StateSet.ts import { StateSetClient } from 'StateSet-node'; // Singleton pattern for client-side usage let client: StateSetClient; export function getStateSetClient() { if (!client) { client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY!, environment: process.env.NEXT_PUBLIC_STATESET_ENV as 'sandbox' | 'production' || 'sandbox' }); } return client; } // Server-side client (for API routes) export const serverClient = new StateSetClient({ apiKey: process.env.STATESET_API_KEY!, environment: process.env.STATESET_ENVIRONMENT as 'sandbox' | 'production' || 'sandbox' }); // Type-safe API wrapper export async function apiWrapper( apiCall: () => Promise ): Promise<{ data?: T; error?: string }> { try { const data = await apiCall(); return { data }; } catch (error: any) { logger.error('StateSet API Error:', error); return { error: error.message || 'An unexpected error occurred' }; } } ``` ```typescript theme={null} // pages/api/orders/index.ts import type { NextApiRequest, NextApiResponse } from 'next'; import { serverClient, apiWrapper } from '../../../lib/StateSet'; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { // Enable CORS if needed res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); if (req.method === 'OPTIONS') { return res.status(200).end(); } switch (req.method) { case 'GET': { const { page = '1', limit = '20', status } = req.query; const result = await apiWrapper(() => serverClient.orders.list({ page: parseInt(page as string), limit: parseInt(limit as string), status: status as string }) ); if (result.error) { return res.status(400).json({ error: result.error }); } return res.status(200).json(result.data); } case 'POST': { const result = await apiWrapper(() => serverClient.orders.create(req.body) ); if (result.error) { return res.status(400).json({ error: result.error }); } return res.status(201).json(result.data); } default: res.setHeader('Allow', ['GET', 'POST']); return res.status(405).json({ error: `Method ${req.method} Not Allowed` }); } } ``` ```typescript theme={null} // hooks/useStateSet.ts (React Hook) import { useState, useEffect } from 'react'; import { getStateSetClient } from '../lib/StateSet'; export function useOrders(options = {}) { const [orders, setOrders] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchOrders = async () => { try { const client = getStateSetClient(); const { data } = await client.orders.list(options); setOrders(data); } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchOrders(); }, []); return { orders, loading, error }; } ``` ```typescript theme={null} // StateSet/StateSet.module.ts import { Module, DynamicModule, Global } from '@nestjs/common'; import { StateSetClient } from 'StateSet-node'; import { STATESET_CLIENT } from './StateSet.constants'; import { StateSetService } from './StateSet.service'; export interface StateSetModuleOptions { apiKey: string; environment?: 'sandbox' | 'production'; isGlobal?: boolean; } @Module({}) export class StateSetModule { static forRoot(options: StateSetModuleOptions): DynamicModule { const providers = [ { provide: STATESET_CLIENT, useFactory: () => new StateSetClient({ apiKey: options.apiKey, environment: options.environment || 'sandbox' }) }, StateSetService ]; return { module: StateSetModule, global: options.isGlobal ?? true, providers, exports: [STATESET_CLIENT, StateSetService] }; } static forRootAsync(options: { useFactory: (...args: any[]) => Promise | StateSetModuleOptions; inject?: any[]; isGlobal?: boolean; }): DynamicModule { const providers = [ { provide: STATESET_CLIENT, useFactory: async (...args: any[]) => { const config = await options.useFactory(...args); return new StateSetClient({ apiKey: config.apiKey, environment: config.environment || 'sandbox' }); }, inject: options.inject || [] }, StateSetService ]; return { module: StateSetModule, global: options.isGlobal ?? true, providers, exports: [STATESET_CLIENT, StateSetService] }; } } ``` ```typescript theme={null} // StateSet/StateSet.service.ts import { Injectable, Inject, Logger } from '@nestjs/common'; import { StateSetClient } from 'StateSet-node'; import { STATESET_CLIENT } from './StateSet.constants'; @Injectable() export class StateSetService { private readonly logger = new Logger(StateSetService.name); constructor( @Inject(STATESET_CLIENT) private readonly client: StateSetClient ) {} async createOrder(data: any) { try { this.logger.log('Creating order', { customerId: data.customer_id }); const order = await this.client.orders.create(data); this.logger.log('Order created successfully', { orderId: order.id }); return order; } catch (error) { this.logger.error('Failed to create order', error); throw error; } } async getOrders(filters = {}) { return this.client.orders.list(filters); } async getOrder(id: string) { return this.client.orders.retrieve(id); } async updateOrder(id: string, data: any) { return this.client.orders.update(id, data); } } ``` ```typescript theme={null} // app.module.ts import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { StateSetModule } from './StateSet/StateSet.module'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), StateSetModule.forRootAsync({ inject: [ConfigService], useFactory: (config: ConfigService) => ({ apiKey: config.get('STATESET_API_KEY'), environment: config.get('STATESET_ENVIRONMENT', 'sandbox') }) }) ] }) export class AppModule {} ``` ```typescript theme={null} // orders/orders.controller.ts import { Controller, Get, Post, Body, Param, Query, UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common'; import { StateSetService } from '../StateSet/StateSet.service'; @Controller('orders') @UseInterceptors(ClassSerializerInterceptor) export class OrdersController { constructor(private readonly StateSetService: StateSetService) {} @Get() async getOrders( @Query('page') page = 1, @Query('limit') limit = 20, @Query('status') status?: string ) { return this.StateSetService.getOrders({ page: Number(page), limit: Number(limit), status }); } @Get(':id') async getOrder(@Param('id') id: string) { return this.StateSetService.getOrder(id); } @Post() async createOrder(@Body() createOrderDto: any) { return this.StateSetService.createOrder(createOrderDto); } } ``` *** ## Python SDK ### Prerequisites ```bash theme={null} python --version # Should output Python 3.8.0 or higher # Check pip version pip --version # Should be version 20.0 or higher ``` Python 3.8+ is required. For older versions, use `StateSet-python==1.x` ```bash venv theme={null} # Create virtual environment python -m venv StateSet-env # Activate on macOS/Linux source StateSet-env/bin/activate # Activate on Windows StateSet-env\Scripts\activate ``` ```bash conda theme={null} # Create conda environment conda create -n StateSet-env python=3.9 conda activate StateSet-env ``` ```bash poetry theme={null} # Initialize poetry project poetry new my-StateSet-app cd my-StateSet-app ``` ### Installation ```bash theme={null} # Install StateSet SDK with all optional dependencies pip install "StateSet-python[all]" # Or install core SDK only pip install StateSet-python # Install specific extras pip install "StateSet-python[async]" # For async support pip install "StateSet-python[pandas]" # For data analysis ``` ```bash theme={null} # Add StateSet SDK poetry add StateSet-python # Add with extras poetry add "StateSet-python[async,pandas]" # Add development dependencies poetry add --group dev pytest pytest-asyncio black mypy ``` ```bash theme={null} # Install via pip in conda environment pip install StateSet-python # Install conda dependencies first conda install pandas numpy requests pip install "StateSet-python[async]" ``` ```txt theme={null} # requirements.txt StateSet-python>=2.0.0 python-dotenv>=0.19.0 requests>=2.28.0 # Optional: async support httpx>=0.23.0 # Optional: data analysis pandas>=1.3.0 numpy>=1.21.0 ``` ```bash theme={null} pip install -r requirements.txt ``` ### Quick Setup ```bash theme={null} # Create project structure mkdir my-StateSet-app && cd my-StateSet-app python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # Install dependencies pip install StateSet-python python-dotenv # Create project files mkdir -p src/{services,utils,config} touch .env .env.example .gitignore README.md touch src/__init__.py src/config/__init__.py ``` ```bash theme={null} # .env STATESET_API_KEY=sk_live_your_actual_key_here STATESET_ENVIRONMENT=production STATESET_WEBHOOK_SECRET=whsec_3rK9pL7nQ2xS5mT8... STATESET_LOG_LEVEL=INFO STATESET_TIMEOUT=30 STATESET_MAX_RETRIES=3 ``` ```bash theme={null} # .gitignore __pycache__/ *.py[cod] *$py.class .env .venv/ venv/ .pytest_cache/ .mypy_cache/ *.log ``` ```python theme={null} # src/config/StateSet.py import os import logging from typing import Optional from StateSet import StateSetClient, AsyncStateSetClient from dotenv import load_dotenv # Load environment variables load_dotenv() # Configure logging logging.basicConfig( level=getattr(logging, os.getenv('STATESET_LOG_LEVEL', 'INFO')), format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # Validate required environment variables REQUIRED_ENV_VARS = ['STATESET_API_KEY'] for var in REQUIRED_ENV_VARS: if not os.getenv(var): raise ValueError(f"Missing required environment variable: {var}") # Configuration class Config: API_KEY = os.getenv('STATESET_API_KEY') ENVIRONMENT = os.getenv('STATESET_ENVIRONMENT', 'sandbox') WEBHOOK_SECRET = os.getenv('STATESET_WEBHOOK_SECRET') TIMEOUT = int(os.getenv('STATESET_TIMEOUT', '30')) MAX_RETRIES = int(os.getenv('STATESET_MAX_RETRIES', '3')) # Create client instances def get_client() -> StateSetClient: """Get configured StateSet client""" return StateSetClient( api_key=Config.API_KEY, environment=Config.ENVIRONMENT, timeout=Config.TIMEOUT, max_retries=Config.MAX_RETRIES ) def get_async_client() -> AsyncStateSetClient: """Get configured async StateSet client""" return AsyncStateSetClient( api_key=Config.API_KEY, environment=Config.ENVIRONMENT, timeout=Config.TIMEOUT, max_retries=Config.MAX_RETRIES ) # Export configured client client = get_client() async_client = get_async_client() ``` ### Basic Configuration ```python theme={null} # app.py from src.config.StateSet import client, Config, logger def test_connection(): """Test StateSet connection and basic API access""" try: # Test health check health = client.health.check() logger.info(f"✅ Connected to StateSet: {health}") # Test API access orders = client.orders.list(limit=1) logger.info(f"✅ API Access verified: {len(orders.data)} orders found") # Display configuration logger.info(f"Environment: {Config.ENVIRONMENT}") logger.info(f"Timeout: {Config.TIMEOUT}s") return True except Exception as e: logger.error(f"❌ Connection failed: {str(e)}") if hasattr(e, 'status_code'): logger.error(f"Status Code: {e.status_code}") if hasattr(e, 'request_id'): logger.error(f"Request ID: {e.request_id}") return False if __name__ == "__main__": if test_connection(): logger.info("StateSet SDK is properly configured!") else: exit(1) ``` ```python theme={null} # app_async.py import asyncio from src.config.StateSet import async_client, Config, logger async def test_connection(): """Test StateSet async connection""" try: # Test health check health = await async_client.health.check() logger.info(f"✅ Connected to StateSet: {health}") # Test parallel API calls tasks = [ async_client.orders.list(limit=5), async_client.customers.list(limit=5), async_client.products.list(limit=5) ] results = await asyncio.gather(*tasks, return_exceptions=True) for i, result in enumerate(results): if isinstance(result, Exception): logger.error(f"Task {i} failed: {result}") else: logger.info(f"Task {i} succeeded: {len(result.data)} items") return True except Exception as e: logger.error(f"❌ Connection failed: {str(e)}") return False finally: await async_client.close() if __name__ == "__main__": asyncio.run(test_connection()) ``` ```python theme={null} # app_typed.py from typing import List, Optional, Dict, Any from dataclasses import dataclass from src.config.StateSet import client, logger from StateSet.models import Order, Customer, Product @dataclass class OrderService: """Type-safe order service""" client: Any def get_orders( self, status: Optional[str] = None, limit: int = 20 ) -> List[Order]: """Get orders with optional filtering""" try: response = self.client.orders.list( status=status, limit=limit ) return response.data except Exception as e: logger.error(f"Failed to fetch orders: {e}") raise def create_order(self, order_data: Dict[str, Any]) -> Order: """Create a new order""" try: return self.client.orders.create(**order_data) except Exception as e: logger.error(f"Failed to create order: {e}") raise def get_order_summary(self, order_id: str) -> Dict[str, Any]: """Get comprehensive order summary""" order = self.client.orders.retrieve(order_id) customer = self.client.customers.retrieve(order.customer_id) return { "order": order, "customer": customer, "total_amount": order.total, "status": order.status } # Usage service = OrderService(client=client) orders = service.get_orders(status="pending", limit=10) print(f"Found {len(orders)} pending orders") ``` ### Framework Integration ```python theme={null} # app.py from flask import Flask, jsonify, request, g from functools import wraps from src.config.StateSet import client, Config, logger import traceback app = Flask(__name__) app.config['JSON_SORT_KEYS'] = False # Error handling decorator def handle_errors(f): @wraps(f) def decorated_function(*args, **kwargs): try: return f(*args, **kwargs) except Exception as e: logger.error(f"Error in {f.__name__}: {str(e)}") logger.error(traceback.format_exc()) if hasattr(e, 'status_code'): status_code = e.status_code else: status_code = 500 return jsonify({ 'success': False, 'error': { 'message': str(e), 'type': type(e).__name__ } }), status_code return decorated_function # Routes @app.route('/api/orders', methods=['GET']) @handle_errors def get_orders(): page = int(request.args.get('page', 1)) limit = int(request.args.get('limit', 20)) status = request.args.get('status') orders = client.orders.list( page=page, limit=limit, status=status ) return jsonify({ 'success': True, 'data': orders.data, 'pagination': { 'page': orders.page, 'limit': orders.limit, 'total': orders.total } }) @app.route('/api/orders', methods=['POST']) @handle_errors def create_order(): data = request.get_json() # Validate required fields required_fields = ['customer_id', 'items'] for field in required_fields: if field not in data: return jsonify({ 'success': False, 'error': f'Missing required field: {field}' }), 400 order = client.orders.create(**data) return jsonify({ 'success': True, 'data': order }), 201 @app.route('/api/orders/', methods=['GET']) @handle_errors def get_order(order_id): order = client.orders.retrieve(order_id) return jsonify({ 'success': True, 'data': order }) @app.route('/api/health', methods=['GET']) def health_check(): try: health = client.health.check() return jsonify({ 'status': 'healthy', 'StateSet': health, 'environment': Config.ENVIRONMENT }) except Exception as e: return jsonify({ 'status': 'unhealthy', 'error': str(e) }), 503 if __name__ == '__main__': app.run(debug=True, port=5000) ``` ```python theme={null} # main.py from fastapi import FastAPI, HTTPException, Query, Depends from fastapi.responses import JSONResponse from pydantic import BaseModel, Field from typing import Optional, List, Dict, Any from src.config.StateSet import async_client, Config, logger import uvicorn app = FastAPI(title="StateSet API", version="1.0.0") # Pydantic models class OrderCreate(BaseModel): customer_id: str items: List[Dict[str, Any]] shipping_address: Dict[str, str] metadata: Optional[Dict[str, Any]] = None class OrderResponse(BaseModel): id: str customer_id: str status: str total: float created_at: str class PaginatedResponse(BaseModel): data: List[Any] pagination: Dict[str, int] # Dependency for StateSet client async def get_StateSet_client(): return async_client # Exception handler @app.exception_handler(Exception) async def StateSet_exception_handler(request, exc): logger.error(f"StateSet error: {exc}") if hasattr(exc, 'status_code'): status_code = exc.status_code else: status_code = 500 return JSONResponse( status_code=status_code, content={ "detail": str(exc), "type": type(exc).__name__ } ) # Routes @app.get("/api/orders", response_model=PaginatedResponse) async def get_orders( page: int = Query(1, ge=1), limit: int = Query(20, ge=1, le=100), status: Optional[str] = None, client = Depends(get_StateSet_client) ): """Get paginated list of orders""" response = await client.orders.list( page=page, limit=limit, status=status ) return { "data": response.data, "pagination": { "page": response.page, "limit": response.limit, "total": response.total } } @app.post("/api/orders", response_model=OrderResponse, status_code=201) async def create_order( order: OrderCreate, client = Depends(get_StateSet_client) ): """Create a new order""" result = await client.orders.create(**order.dict()) return result @app.get("/api/orders/{order_id}", response_model=OrderResponse) async def get_order( order_id: str, client = Depends(get_StateSet_client) ): """Get order by ID""" order = await client.orders.retrieve(order_id) if not order: raise HTTPException(status_code=404, detail="Order not found") return order @app.get("/api/health") async def health_check(client = Depends(get_StateSet_client)): """Health check endpoint""" try: health = await client.health.check() return { "status": "healthy", "StateSet": health, "environment": Config.ENVIRONMENT } except Exception as e: raise HTTPException(status_code=503, detail=str(e)) # Startup/shutdown events @app.on_event("startup") async def startup_event(): logger.info("Starting up StateSet FastAPI app") @app.on_event("shutdown") async def shutdown_event(): logger.info("Shutting down StateSet FastAPI app") await async_client.close() if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) ``` ```python theme={null} # settings.py import os from dotenv import load_dotenv load_dotenv() # StateSet Configuration STATESET_API_KEY = os.getenv('STATESET_API_KEY') STATESET_ENVIRONMENT = os.getenv('STATESET_ENVIRONMENT', 'sandbox') STATESET_WEBHOOK_SECRET = os.getenv('STATESET_WEBHOOK_SECRET') # StateSet_client.py from django.conf import settings from StateSet import StateSetClient import logging logger = logging.getLogger(__name__) class StateSetService: """Singleton StateSet service for Django""" _instance = None _client = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance @property def client(self): if self._client is None: self._client = StateSetClient( api_key=settings.STATESET_API_KEY, environment=settings.STATESET_ENVIRONMENT ) return self._client # views.py from django.http import JsonResponse from django.views import View from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from .StateSet_client import StateSetService import json StateSet_service = StateSetService() @method_decorator(csrf_exempt, name='dispatch') class OrdersView(View): def get(self, request): try: page = int(request.GET.get('page', 1)) limit = int(request.GET.get('limit', 20)) status = request.GET.get('status') response = StateSet_service.client.orders.list( page=page, limit=limit, status=status ) return JsonResponse({ 'success': True, 'data': response.data, 'pagination': { 'page': response.page, 'limit': response.limit, 'total': response.total } }) except Exception as e: return JsonResponse({ 'success': False, 'error': str(e) }, status=500) def post(self, request): try: data = json.loads(request.body) order = StateSet_service.client.orders.create(**data) return JsonResponse({ 'success': True, 'data': order }, status=201) except Exception as e: return JsonResponse({ 'success': False, 'error': str(e) }, status=400) class OrderDetailView(View): def get(self, request, order_id): try: order = StateSet_service.client.orders.retrieve(order_id) return JsonResponse({ 'success': True, 'data': order }) except Exception as e: status_code = 404 if 'not found' in str(e).lower() else 500 return JsonResponse({ 'success': False, 'error': str(e) }, status=status_code) # urls.py from django.urls import path from .views import OrdersView, OrderDetailView urlpatterns = [ path('api/orders/', OrdersView.as_view(), name='orders'), path('api/orders//', OrderDetailView.as_view(), name='order-detail'), ] ``` *** ## Ruby SDK ### Prerequisites ```bash theme={null} ruby --version # Should output ruby 2.7.0 or higher # Check gem version gem --version # Should be version 3.0.0 or higher # Check bundler bundle --version # Should be version 2.0.0 or higher ``` Ruby 2.7+ is required. For older versions, use `StateSet-ruby` v1.x ```bash theme={null} # Install bundler if not present gem install bundler # Optional: Install development tools gem install pry rubocop rspec ``` ### Installation ```ruby theme={null} # Gemfile source 'https://rubygems.org' # StateSet SDK gem 'StateSet-ruby', '~> 2.0' # Environment management gem 'dotenv-rails', groups: [:development, :test] # For Rails # OR gem 'dotenv', groups: [:development, :test] # For non-Rails # Optional dependencies gem 'faraday-retry' # Advanced retry logic gem 'concurrent-ruby' # For async operations ``` ```bash theme={null} bundle install ``` ```bash theme={null} # Install directly via gem gem install StateSet-ruby # Install with specific version gem install StateSet-ruby -v '2.0.0' # Install development version gem install StateSet-ruby --pre ``` ```bash theme={null} # Clone and build from source git clone https://github.com/StateSet/StateSet-ruby.git cd StateSet-ruby bundle install rake build gem install pkg/StateSet-ruby-*.gem ``` ### Quick Setup ```bash theme={null} # Create new Ruby project mkdir my-StateSet-app && cd my-StateSet-app # Initialize bundler bundle init # Create project structure mkdir -p lib/StateSet config spec touch .env .env.example .gitignore README.md touch config/StateSet.rb lib/StateSet_service.rb ``` ```bash theme={null} # .env STATESET_API_KEY=sk_live_your_actual_key_here STATESET_ENVIRONMENT=production STATESET_WEBHOOK_SECRET=whsec_3rK9pL7nQ2xS5mT8... STATESET_LOG_LEVEL=info STATESET_TIMEOUT=30 STATESET_MAX_RETRIES=3 ``` ```bash theme={null} # .gitignore *.gem *.rbc /.config /coverage/ /spec/reports/ /tmp/ .env .env.local *.log .DS_Store ``` ```ruby theme={null} # config/StateSet.rb require 'StateSet' require 'dotenv/load' require 'logger' # Configure logger StateSet.logger = Logger.new(STDOUT) StateSet.logger.level = ENV.fetch('STATESET_LOG_LEVEL', 'INFO') # Validate required environment variables required_vars = ['STATESET_API_KEY'] missing_vars = required_vars.select { |var| ENV[var].nil? || ENV[var].empty? } unless missing_vars.empty? raise "Missing required environment variables: #{missing_vars.join(', ')}" end # Configure StateSet client StateSet.configure do |config| config.api_key = ENV['STATESET_API_KEY'] config.environment = ENV.fetch('STATESET_ENVIRONMENT', 'sandbox') config.timeout = ENV.fetch('STATESET_TIMEOUT', '30').to_i config.max_retries = ENV.fetch('STATESET_MAX_RETRIES', '3').to_i config.webhook_secret = ENV['STATESET_WEBHOOK_SECRET'] # Optional: Configure custom Faraday middleware config.configure_faraday do |faraday| faraday.request :retry, max: 3 faraday.use :instrumentation, name: 'StateSet.request' end end # Test connection helper module StateSetHelper def self.test_connection begin health = StateSet::Health.check StateSet.logger.info "✅ Connected to StateSet: #{health['status']}" # Test API access orders = StateSet::Order.list(limit: 1) StateSet.logger.info "✅ API Access verified: #{orders.data.length} orders found" true rescue => e StateSet.logger.error "❌ Connection failed: #{e.message}" false end end end ``` ### Basic Configuration ```ruby theme={null} # app.rb require_relative 'config/StateSet' # Test the connection if StateSetHelper.test_connection puts "StateSet is properly configured!" else exit 1 end $client = getStateSetClient() begin # Create a customer customer = StateSet::Customer.create( email: 'test@example.com', name: 'Test Customer', metadata: { source: 'ruby_sdk' } ) puts "Created customer: #{customer.id}" # Create an order order = StateSet::Order.create( customer_id: customer.id, items: [ { product_id: 'prod_123', quantity: 2, price: 1999 } ], shipping_address: { line1: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' } ) puts "Created order: #{order.id}" # List recent orders orders = StateSet::Order.list(limit: 10, status: 'pending') orders.data.each do |order| puts "Order #{order.id}: #{order.status} - $#{order.total / 100.0}" end rescue StateSet::Error => e puts "StateSet Error: #{e.message}" puts "Error Code: #{e.code}" if e.code puts "Request ID: #{e.request_id}" if e.request_id end ``` ```ruby theme={null} # lib/StateSet_service.rb require_relative '../config/StateSet' class StateSetService class << self def create_order(customer_id:, items:, shipping_address:, metadata: {}) StateSet::Order.create( customer_id: customer_id, items: items, shipping_address: shipping_address, metadata: metadata ) rescue StateSet::Error => e handle_error(e) end def get_order(order_id) StateSet::Order.retrieve(order_id) rescue StateSet::NotFoundError => e nil rescue StateSet::Error => e handle_error(e) end def list_orders(filters = {}) defaults = { limit: 20, page: 1 } StateSet::Order.list(defaults.merge(filters)) rescue StateSet::Error => e handle_error(e) end def update_order_status(order_id, status) StateSet::Order.update(order_id, status: status) rescue StateSet::Error => e handle_error(e) end private def handle_error(error) StateSet.logger.error "StateSet API Error: #{error.message}" StateSet.logger.error "Error Type: #{error.class}" StateSet.logger.error "Request ID: #{error.request_id}" if error.request_id # Re-raise or return error response based on your needs raise error end end end ``` ```ruby theme={null} # lib/async_StateSet.rb require 'concurrent' require_relative '../config/StateSet' class AsyncStateSet def self.batch_create_orders(orders_data) promises = orders_data.map do |order_data| Concurrent::Promise.execute do StateSet::Order.create(order_data) end end # Wait for all promises to complete results = promises.map(&:value!) # Handle results successful = results.select { |r| !r.is_a?(Exception) } failed = results.select { |r| r.is_a?(Exception) } { successful: successful, failed: failed, total: orders_data.length } end def self.parallel_fetch(resource_ids) promises = resource_ids.map do |id| Concurrent::Promise.execute do { id: id, order: StateSet::Order.retrieve(id), customer: StateSet::Customer.retrieve( StateSet::Order.retrieve(id).customer_id ) } end end promises.map(&:value!) end end # Usage example if __FILE__ == $0 # Create multiple orders in parallel orders_data = 5.times.map do |i| { customer_id: 'cus_123', items: [{ product_id: "prod_#{i}", quantity: 1, price: 1000 }], shipping_address: { line1: "#{i} Main St", city: 'SF', state: 'CA' } } end results = AsyncStateSet.batch_create_orders(orders_data) puts "Created #{results[:successful].length} orders successfully" puts "Failed: #{results[:failed].length}" end ``` ### Framework Integration ```ruby theme={null} # config/initializers/StateSet.rb require 'StateSet' Rails.application.config.before_initialize do StateSet.configure do |config| config.api_key = Rails.application.credentials.StateSet[:api_key] config.environment = Rails.env.production? ? 'production' : 'sandbox' config.logger = Rails.logger config.timeout = 30 # Add Rails-specific middleware config.configure_faraday do |faraday| faraday.request :retry, max: 3 faraday.use :instrumentation, name: 'StateSet.request' end end end # app/services/StateSet_service.rb class StateSetService include ActiveSupport::Rescuable rescue_from StateSet::Error, with: :handle_StateSet_error def create_order(user, items, shipping_address) order = StateSet::Order.create( customer_id: user.StateSet_customer_id, items: items.map(&:to_StateSet_item), shipping_address: shipping_address.to_StateSet_format, metadata: { user_id: user.id, created_via: 'rails_app' } ) # Store order reference user.orders.create!( StateSet_order_id: order.id, total: order.total, status: order.status ) order end def sync_order_status(local_order) StateSet_order = StateSet::Order.retrieve(local_order.StateSet_order_id) if local_order.status != StateSet_order.status local_order.update!( status: StateSet_order.status, updated_at: Time.at(StateSet_order.updated) ) end StateSet_order end private def handle_StateSet_error(error) Rails.logger.error "StateSet Error: #{error.message}" Bugsnag.notify(error) if defined?(Bugsnag) case error when StateSet::RateLimitError raise CustomErrors::RateLimitExceeded when StateSet::AuthenticationError raise CustomErrors::ServiceUnavailable else raise error end end end # app/controllers/api/orders_controller.rb class Api::OrdersController < ApplicationController before_action :authenticate_user! def index orders = current_user.orders.includes(:items) # Optionally sync with StateSet if params[:sync] == 'true' service = StateSetService.new orders.each { |order| service.sync_order_status(order) } end render json: orders end def create service = StateSetService.new order = service.create_order( current_user, order_params[:items], order_params[:shipping_address] ) render json: order, status: :created rescue StateSet::Error => e render json: { error: e.message }, status: :unprocessable_entity end private def order_params params.require(:order).permit( items: [:product_id, :quantity, :price], shipping_address: [:line1, :line2, :city, :state, :postal_code, :country] ) end end # app/jobs/StateSet_webhook_job.rb class StateSetWebhookJob < ApplicationJob def perform(event) case event['type'] when 'order.updated' handle_order_update(event['data']) when 'order.completed' handle_order_completion(event['data']) end end private def handle_order_update(order_data) order = Order.find_by(StateSet_order_id: order_data['id']) order&.update!(status: order_data['status']) end def handle_order_completion(order_data) order = Order.find_by(StateSet_order_id: order_data['id']) OrderMailer.completion_notification(order).deliver_later if order end end ``` ```ruby theme={null} # app.rb require 'sinatra' require 'sinatra/json' require_relative 'config/StateSet' class StateSetApp < Sinatra::Base configure do set :show_exceptions, false set :raise_errors, false end # Error handling error StateSet::Error do |e| status e.http_status || 400 json error: { message: e.message, type: e.class.name } end error do |e| status 500 json error: { message: 'Internal server error' } end # Middleware for common headers before do content_type :json headers['Access-Control-Allow-Origin'] = '*' end # Routes get '/api/orders' do page = params[:page]&.to_i || 1 limit = params[:limit]&.to_i || 20 status = params[:status] orders = StateSet::Order.list( page: page, limit: limit, status: status ) json( data: orders.data, pagination: { page: orders.page, limit: orders.limit, total: orders.total } ) end post '/api/orders' do data = JSON.parse(request.body.read) order = StateSet::Order.create( customer_id: data['customer_id'], items: data['items'], shipping_address: data['shipping_address'] ) status 201 json data: order end get '/api/orders/:id' do |id| order = StateSet::Order.retrieve(id) json data: order end patch '/api/orders/:id' do |id| data = JSON.parse(request.body.read) order = StateSet::Order.update(id, data) json data: order end get '/api/health' do health = StateSet::Health.check json( status: 'healthy', StateSet: health, environment: ENV['STATESET_ENVIRONMENT'] ) rescue => e status 503 json( status: 'unhealthy', error: e.message ) end # Webhook endpoint post '/webhooks/StateSet' do payload = request.body.read sig_header = request.env['HTTP_STATESET_SIGNATURE'] begin event = StateSet::Webhook.construct_event( payload, sig_header, ENV['STATESET_WEBHOOK_SECRET'] ) # Process webhook event asynchronously # WebhookProcessor.perform_async(event) status 200 json received: true rescue StateSet::SignatureVerificationError => e status 400 json error: 'Invalid signature' end end run! if app_file == $0 end ``` *** ## PHP SDK ### Prerequisites ```bash theme={null} php --version # Should output PHP 8.0.0 or higher # Check Composer version composer --version # Should be version 2.0.0 or higher # Check required extensions php -m | grep -E "(curl|json|mbstring)" # Should show curl, json, and mbstring ``` PHP 8.0+ is required. For older versions, use `StateSet-php` v1.x ```bash theme={null} # Ubuntu/Debian sudo apt-get install php8.1-curl php8.1-json php8.1-mbstring # macOS with Homebrew brew install php@8.1 # Windows with XAMPP/WAMP # Extensions are usually pre-installed ``` ### Installation ```bash theme={null} # Install via Composer composer require StateSet/StateSet-php # Install with specific version composer require StateSet/StateSet-php:^2.0 # Install development dependencies composer require --dev phpunit/phpunit phpstan/phpstan ``` ```bash theme={null} # Download the latest release wget https://github.com/StateSet/StateSet-php/archive/v2.0.0.zip unzip v2.0.0.zip # Include in your project require_once 'path/to/StateSet-php/init.php'; ``` ```bash theme={null} # Install via Composer composer require StateSet/StateSet-php # Publish configuration php artisan vendor:publish --provider="StateSet\Laravel\StateSetServiceProvider" # Add to .env STATESET_API_KEY=your_api_key_here STATESET_ENVIRONMENT=sandbox ``` ### Quick Setup ```bash theme={null} # Create new PHP project mkdir my-StateSet-app && cd my-StateSet-app composer init # Create project structure mkdir -p src/{Services,Controllers,Models} config tests touch .env .env.example .gitignore README.md touch config/StateSet.php src/Services/StateSetService.php ``` ```bash theme={null} # .env STATESET_API_KEY=sk_live_your_actual_key_here STATESET_ENVIRONMENT=production STATESET_WEBHOOK_SECRET=whsec_3rK9pL7nQ2xS5mT8... STATESET_LOG_LEVEL=info STATESET_TIMEOUT=30 STATESET_MAX_RETRIES=3 ``` ```bash theme={null} # .gitignore /vendor/ /.env /.env.local /composer.lock /.phpunit.result.cache /logs/ *.log .DS_Store ``` ```php theme={null} load(); // Validate required environment variables $dotenv->required(['STATESET_API_KEY'])->notEmpty(); // Configure logger $logger = new Logger('StateSet'); $logger->pushHandler(new StreamHandler( __DIR__ . '/../logs/StateSet.log', $_ENV['STATESET_LOG_LEVEL'] ?? Logger::INFO )); // Configure StateSet client function getStateSetClient(): StateSetClient { global $logger; return new StateSetClient([ 'api_key' => $_ENV['STATESET_API_KEY'], 'environment' => $_ENV['STATESET_ENVIRONMENT'] ?? 'sandbox', 'timeout' => (int)($_ENV['STATESET_TIMEOUT'] ?? 30), 'max_retries' => (int)($_ENV['STATESET_MAX_RETRIES'] ?? 3), 'logger' => $logger, 'webhook_secret' => $_ENV['STATESET_WEBHOOK_SECRET'] ?? null ]); } // Test connection helper function testStateSetConnection(): bool { global $logger; try { $client = getStateSetClient(); $health = $client->health->check(); $logger->info("✅ Connected to StateSet: " . json_encode($health)); // Test API access $orders = $client->orders->list(['limit' => 1]); $logger->info("✅ API Access verified: " . count($orders->data) . " orders found"); return true; } catch (StateSetException $e) { $logger->error("❌ Connection failed: " . $e->getMessage()); return false; } } ``` ### Basic Configuration ```php theme={null} customers->create([ 'email' => 'test@example.com', 'name' => 'Test Customer', 'metadata' => ['source' => 'php_sdk'] ]); echo "Created customer: {$customer->id}\n"; // Create an order $order = $client->orders->create([ 'customer_id' => $customer->id, 'items' => [ [ 'product_id' => 'prod_123', 'quantity' => 2, 'price' => 1999 ] ], 'shipping_address' => [ 'line1' => '123 Main St', 'city' => 'San Francisco', 'state' => 'CA', 'postal_code' => '94105', 'country' => 'US' ] ]); echo "Created order: {$order->id}\n"; // List recent orders $orders = $client->orders->list([ 'limit' => 10, 'status' => 'pending' ]); foreach ($orders->data as $order) { $total = number_format($order->total / 100, 2); echo "Order {$order->id}: {$order->status} - \${$total}\n"; } } catch (StateSetException $e) { echo "StateSet Error: {$e->getMessage()}\n"; if ($e->getCode()) { echo "Error Code: {$e->getCode()}\n"; } if ($e->getRequestId()) { echo "Request ID: {$e->getRequestId()}\n"; } } ``` ```php theme={null} client = $client; $this->logger = $logger; } public function createOrder(array $data): ?object { try { $order = $this->client->orders->create($data); $this->logger->info("Order created", ['order_id' => $order->id]); return $order; } catch (StateSetException $e) { $this->handleError($e); return null; } } public function getOrder(string $orderId): ?object { try { return $this->client->orders->retrieve($orderId); } catch (StateSetException $e) { if ($e->getHttpStatus() === 404) { return null; } $this->handleError($e); throw $e; } } public function listOrders(array $filters = []): array { $defaults = ['limit' => 20, 'page' => 1]; $params = array_merge($defaults, $filters); try { $response = $this->client->orders->list($params); return [ 'data' => $response->data, 'pagination' => [ 'page' => $response->page, 'limit' => $response->limit, 'total' => $response->total ] ]; } catch (StateSetException $e) { $this->handleError($e); throw $e; } } public function updateOrderStatus(string $orderId, string $status): ?object { try { return $this->client->orders->update($orderId, ['status' => $status]); } catch (StateSetException $e) { $this->handleError($e); throw $e; } } private function handleError(StateSetException $e): void { $this->logger->error("StateSet API Error", [ 'message' => $e->getMessage(), 'code' => $e->getCode(), 'request_id' => $e->getRequestId(), 'http_status' => $e->getHttpStatus() ]); } } ``` ```php theme={null} client = $client; } public function batchCreateOrders(array $ordersData) { $promises = []; $results = ['successful' => [], 'failed' => []]; foreach ($ordersData as $index => $orderData) { $promises[$index] = new Promise(function ($resolve, $reject) use ($orderData) { try { $order = $this->client->orders->create($orderData); $resolve($order); } catch (\Exception $e) { $reject($e); } }); } // Wait for all promises foreach ($promises as $index => $promise) { $promise->then( function ($order) use (&$results) { $results['successful'][] = $order; }, function ($error) use (&$results) { $results['failed'][] = $error; } ); } // Run event loop Loop::run(); return $results; } public function parallelFetch(array $orderIds) { $results = []; $promises = array_map(function ($orderId) { return new Promise(function ($resolve) use ($orderId) { try { $order = $this->client->orders->retrieve($orderId); $customer = $this->client->customers->retrieve($order->customer_id); $resolve([ 'order' => $order, 'customer' => $customer ]); } catch (\Exception $e) { $resolve(['error' => $e->getMessage()]); } }); }, $orderIds); foreach ($promises as $index => $promise) { $promise->then(function ($result) use (&$results, $orderIds, $index) { $results[$orderIds[$index]] = $result; }); } Loop::run(); return $results; } } ``` ### Framework Integration ```php theme={null} env('STATESET_API_KEY'), 'environment' => env('STATESET_ENVIRONMENT', 'sandbox'), 'webhook_secret' => env('STATESET_WEBHOOK_SECRET'), 'timeout' => env('STATESET_TIMEOUT', 30), 'max_retries' => env('STATESET_MAX_RETRIES', 3), ]; ``` ```php theme={null} app->singleton(StateSetClient::class, function ($app) { return new StateSetClient([ 'api_key' => config('StateSet.api_key'), 'environment' => config('StateSet.environment'), 'timeout' => config('StateSet.timeout'), 'max_retries' => config('StateSet.max_retries'), ]); }); } public function boot() { $this->publishes([ __DIR__.'/../../config/StateSet.php' => config_path('StateSet.php'), ], 'config'); } } ``` ```php theme={null} client = $client; } public function createOrder(array $data) { try { $order = $this->client->orders->create($data); // Cache the order Cache::put("order_{$order->id}", $order, now()->addMinutes(5)); // Dispatch event event(new \App\Events\OrderCreated($order)); return $order; } catch (StateSetException $e) { Log::error('StateSet order creation failed', [ 'error' => $e->getMessage(), 'data' => $data ]); throw $e; } } public function getOrder(string $orderId) { // Check cache first return Cache::remember("order_{$orderId}", 300, function () use ($orderId) { return $this->client->orders->retrieve($orderId); }); } } ``` ```php theme={null} StateSetService = $StateSetService; } public function index(Request $request): JsonResponse { $validated = $request->validate([ 'page' => 'integer|min:1', 'limit' => 'integer|min:1|max:100', 'status' => 'string|in:pending,processing,completed,cancelled' ]); try { $orders = $this->StateSetService->listOrders($validated); return response()->json($orders); } catch (\Exception $e) { return response()->json([ 'error' => $e->getMessage() ], 500); } } public function store(Request $request): JsonResponse { $validated = $request->validate([ 'customer_id' => 'required|string', 'items' => 'required|array', 'items.*.product_id' => 'required|string', 'items.*.quantity' => 'required|integer|min:1', 'shipping_address' => 'required|array' ]); try { $order = $this->StateSetService->createOrder($validated); return response()->json($order, 201); } catch (\Exception $e) { return response()->json([ 'error' => $e->getMessage() ], 422); } } public function show(string $id): JsonResponse { try { $order = $this->StateSetService->getOrder($id); return response()->json($order); } catch (\Exception $e) { return response()->json([ 'error' => 'Order not found' ], 404); } } } ``` ```php theme={null} getContent(); $sigHeader = $request->header('StateSet-Signature'); $secret = config('StateSet.webhook_secret'); try { $event = Webhook::constructEvent($payload, $sigHeader, $secret); // Process webhook event switch ($event->type) { case 'order.updated': $this->handleOrderUpdate($event->data); break; case 'order.completed': $this->handleOrderCompleted($event->data); break; default: Log::info('Unhandled webhook event type: ' . $event->type); } return response()->json(['received' => true]); } catch (\Exception $e) { Log::error('Webhook error: ' . $e->getMessage()); return response()->json(['error' => 'Invalid signature'], 400); } } private function handleOrderUpdate($orderData) { // Update local database \App\Models\Order::where('StateSet_id', $orderData->id) ->update(['status' => $orderData->status]); } private function handleOrderCompleted($orderData) { // Send notification email \App\Jobs\SendOrderCompletionEmail::dispatch($orderData->id); } } ``` ```php theme={null} initClient(); $this->setupHooks(); } private function initClient() { $this->client = new \StateSet\StateSetClient([ 'api_key' => get_option('StateSet_api_key'), 'environment' => get_option('StateSet_environment', 'sandbox'), 'timeout' => 30 ]); } private function setupHooks() { // Admin menu add_action('admin_menu', [$this, 'addAdminMenu']); // REST API endpoints add_action('rest_api_init', [$this, 'registerRestRoutes']); // WooCommerce integration if (class_exists('WooCommerce')) { add_action('woocommerce_order_status_changed', [$this, 'syncOrderStatus'], 10, 3); add_action('woocommerce_new_order', [$this, 'createStateSetOrder']); } } public function addAdminMenu() { add_menu_page( 'StateSet Settings', 'StateSet', 'manage_options', 'StateSet-settings', [$this, 'settingsPage'], 'dashicons-cloud', 30 ); } public function settingsPage() { ?>

StateSet Settings

API key
Environment
'GET', 'callback' => [$this, 'getOrders'], 'permission_callback' => function() { return current_user_can('manage_options'); } ]); register_rest_route('StateSet/v1', '/orders/(?P[a-zA-Z0-9_-]+)', [ 'methods' => 'GET', 'callback' => [$this, 'getOrder'], 'permission_callback' => function() { return current_user_can('manage_options'); } ]); } public function getOrders($request) { try { $params = [ 'limit' => $request->get_param('limit') ?: 20, 'page' => $request->get_param('page') ?: 1 ]; $orders = $this->client->orders->list($params); return new WP_REST_Response([ 'success' => true, 'data' => $orders->data, 'pagination' => [ 'total' => $orders->total, 'page' => $orders->page, 'limit' => $orders->limit ] ], 200); } catch (\Exception $e) { return new WP_Error('StateSet_error', $e->getMessage(), ['status' => 500]); } } public function createStateSetOrder($orderId) { $order = wc_get_order($orderId); if (!$order) { return; } try { $StateSetOrder = $this->client->orders->create([ 'customer_id' => $this->getOrCreateCustomer($order), 'items' => $this->formatOrderItems($order), 'shipping_address' => $this->formatAddress($order->get_address('shipping')), 'metadata' => [ 'woocommerce_order_id' => $orderId, 'source' => 'wordpress_plugin' ] ]); // Save StateSet order ID update_post_meta($orderId, '_StateSet_order_id', $StateSetOrder->id); } catch (\Exception $e) { error_log('StateSet order creation failed: ' . $e->getMessage()); } } private function getOrCreateCustomer($order) { $email = $order->get_billing_email(); try { // Try to find existing customer $customers = $this->client->customers->list(['email' => $email]); if (!empty($customers->data)) { return $customers->data[0]->id; } // Create new customer $customer = $this->client->customers->create([ 'email' => $email, 'name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(), 'phone' => $order->get_billing_phone() ]); return $customer->id; } catch (\Exception $e) { throw $e; } } private function formatOrderItems($order) { $items = []; foreach ($order->get_items() as $item) { $product = $item->get_product(); $items[] = [ 'product_id' => 'prod_' . $product->get_id(), 'name' => $product->get_name(), 'quantity' => $item->get_quantity(), 'price' => (int)($product->get_price() * 100) // Convert to cents ]; } return $items; } private function formatAddress($address) { return [ 'line1' => $address['address_1'], 'line2' => $address['address_2'], 'city' => $address['city'], 'state' => $address['state'], 'postal_code' => $address['postcode'], 'country' => $address['country'] ]; } } // Initialize plugin add_action('plugins_loaded', function() { StateSetPlugin::getInstance(); }); // Register settings add_action('admin_init', function() { register_setting('StateSet_settings', 'StateSet_api_key'); register_setting('StateSet_settings', 'StateSet_environment'); register_setting('StateSet_settings', 'StateSet_webhook_secret'); }); ```
*** ## Environment Configuration ### Development Environment ```bash theme={null} # .env.development STATESET_API_KEY=sk_test_your_actual_key_here STATESET_ENVIRONMENT=sandbox STATESET_WEBHOOK_SECRET=whsec_test_3rK9pL7nQ2xS5mT8... LOG_LEVEL=debug ``` ### Production Environment ```bash theme={null} # .env.production STATESET_API_KEY=sk_live_your_actual_key_here STATESET_ENVIRONMENT=production STATESET_WEBHOOK_SECRET=whsec_prod_3rK9pL7nQ2xS5mT8... LOG_LEVEL=info ``` ### Docker Configuration ```dockerfile theme={null} # Dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 CMD ["npm", "start"] ``` ```yaml theme={null} # docker-compose.yml version: '3.8' services: app: build: . ports: - "3000:3000" environment: - STATESET_API_KEY=${STATESET_API_KEY} - STATESET_ENVIRONMENT=production volumes: - .:/app - /app/node_modules ``` *** ## Troubleshooting ### Common Issues **Problem**: `401 Unauthorized` errors **Solutions**: ```bash theme={null} # 1. Verify API key format echo $STATESET_API_KEY # Should start with sk_test_ or sk_live_ # 2. Check environment variables are loaded node -e "logger.info(process.env.STATESET_API_KEY);" # 3. Verify API key permissions in dashboard # https://app.StateSet.com/settings/api-keys # 4. Ensure correct environment # sandbox keys: sk_test_* # production keys: sk_live_* ``` **Code fix**: ```javascript theme={null} // Ensure environment variables are loaded import dotenv from 'dotenv'; dotenv.config({ path: '.env.local' }); // Try different path // Debug API key logger.info('API key exists:', !!process.env.STATESET_API_KEY); logger.info('API key prefix:', process.env.STATESET_API_KEY?.substring(0, 7);); ``` **Problem**: Requests timing out or `ETIMEDOUT` errors **Solutions**: ```javascript theme={null} // 1. Increase timeout const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, timeout: 60000, // 60 seconds maxRetries: 5 }); // 2. Check network connectivity // Run: curl https://api.StateSet.com/v1/health // 3. Configure proxy if behind firewall import { HttpsProxyAgent } from 'https-proxy-agent'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, httpAgent: new HttpsProxyAgent(process.env.HTTP_PROXY) }); // 4. Implement custom retry logic async function retryableRequest(fn, retries = 3) { for (let i = 0; i < retries; i++) { try { return await fn(); } catch (error) { if (i === retries - 1) throw error; await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i))); } } } ``` **Problem**: Cannot import StateSet modules or TypeScript errors **Solutions**: ```bash theme={null} # 1. Clear cache and reinstall rm -rf node_modules package-lock.json npm cache clean --force npm install # 2. Check Node.js version node --version # Must be 16.0.0+ # 3. Verify installation npm list StateSet-node # 4. Fix TypeScript paths # tsconfig.json { "compilerOptions": { "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true } } # 5. For ESM issues, add to package.json: { "type": "module" } ``` **Problem**: `429 Too Many Requests` errors **Solutions**: ```javascript theme={null} // 1. Implement exponential backoff import pRetry from 'p-retry'; const createOrderWithRetry = async (data) => { return pRetry( () => client.orders.create(data), { retries: 5, onFailedAttempt: error => { if (error.statusCode === 429) { logger.info(`Rate limited, retrying in ${error.retriesLeft * 1000}ms`); } } } ); }; // 2. Implement request queuing import PQueue from 'p-queue'; const queue = new PQueue({ concurrency: 2, // Max 2 concurrent requests interval: 1000, // Per second intervalCap: 10 // Max 10 requests per second }); // 3. Cache frequently accessed data const cache = new Map(); async function getCachedOrder(id) { if (cache.has(id)) { return cache.get(id); } const order = await client.orders.retrieve(id); cache.set(id, order); return order; } ``` **Problem**: Webhook signature verification failing **Solutions**: ```javascript theme={null} // 1. Ensure raw body is used app.use('/webhooks/StateSet', express.raw({ type: 'application/json' })); // 2. Correct signature verification app.post('/webhooks/StateSet', (req, res) => { const sig = req.headers['StateSet-signature']; const body = req.body; // Must be raw Buffer try { const event = StateSet.webhooks.constructEvent( body, sig, process.env.STATESET_WEBHOOK_SECRET ); // Process event res.json({ received: true }); } catch (err) { logger.error('Webhook Error:', err.message); res.status(400).send(`Webhook Error: ${err.message}`); } }); // 3. Debug webhook secret logger.info('Webhook secret exists:', !!process.env.STATESET_WEBHOOK_SECRET); logger.info('Secret prefix:', process.env.STATESET_WEBHOOK_SECRET?.substring(0, 7);); ``` ### Platform-Specific Issues ```javascript theme={null} // vercel.json { "functions": { "api/webhooks/StateSet.js": { "maxDuration": 30 } }, "headers": [ { "source": "/api/(.*)", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "*" } ] } ] } // api/webhooks/StateSet.js export const config = { api: { bodyParser: false, // Important for raw body }, }; ``` ```javascript theme={null} // serverless.yml functions: webhook: handler: handler.webhook events: - http: path: webhooks/StateSet method: post cors: true environment: STATESET_API_KEY: ${env:STATESET_API_KEY} STATESET_WEBHOOK_SECRET: ${env:STATESET_WEBHOOK_SECRET} // handler.js const getRawBody = require('raw-body'); exports.webhook = async (event) => { const body = Buffer.from(event.body, 'base64'); const sig = event.headers['StateSet-signature']; try { const webhookEvent = StateSet.webhooks.constructEvent( body, sig, process.env.STATESET_WEBHOOK_SECRET ); return { statusCode: 200, body: JSON.stringify({ received: true }) }; } catch (err) { return { statusCode: 400, body: JSON.stringify({ error: err.message }) }; } }; ``` ```dockerfile theme={null} # Dockerfile debugging FROM node:18-alpine # Install debugging tools RUN apk add --no-cache curl openssl WORKDIR /app # Copy and install dependencies COPY package*.json ./ RUN npm ci --only=production # Copy application COPY . . # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('./health-check.js')" || exit 1 EXPOSE 3000 CMD ["node", "index.js"] ``` ```yaml theme={null} # docker-compose.yml with debugging version: '3.8' services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production - STATESET_API_KEY=${STATESET_API_KEY} - DEBUG=StateSet:* volumes: - ./logs:/app/logs command: > sh -c " echo 'Testing StateSet connection...' && node test-connection.js && node index.js " ``` ## Testing Your Integration ### Unit Testing ```javascript theme={null} // __tests__/StateSet.test.js import { StateSetClient } from 'StateSet-node'; import nock from 'nock'; describe('StateSet Integration', () => { let client; beforeEach(() => { client = new StateSetClient({ apiKey: 'sk_test_123', environment: 'sandbox' }); }); afterEach(() => { nock.cleanAll(); }); test('should create an order', async () => { const orderData = { customer_id: 'cus_123', items: [{ product_id: 'prod_123', quantity: 1 }] }; nock('https://api.StateSet.com') .post('/v1/orders', orderData) .reply(201, { id: 'ord_123', ...orderData, status: 'pending' }); const order = await client.orders.create(orderData); expect(order.id).toBe('ord_123'); expect(order.status).toBe('pending'); }); test('should handle errors gracefully', async () => { nock('https://api.StateSet.com') .post('/v1/orders') .reply(400, { error: { message: 'Invalid customer_id', code: 'invalid_request' } }); await expect(client.orders.create({})) .rejects .toThrow('Invalid customer_id'); }); }); ``` ```python theme={null} # test_StateSet.py import pytest from unittest.mock import Mock, patch from StateSet import StateSetClient from StateSet.exceptions import StateSetError @pytest.fixture def client(): return StateSetClient(api_key='sk_test_123') @pytest.fixture def mock_response(): mock = Mock() mock.json.return_value = { 'id': 'ord_123', 'status': 'pending' } mock.status_code = 201 return mock def test_create_order(client, mock_response): with patch('requests.post', return_value=mock_response): order = client.orders.create( customer_id='cus_123', items=[{'product_id': 'prod_123', 'quantity': 1}] ) assert order.id == 'ord_123' assert order.status == 'pending' def test_handle_error(client): mock_response = Mock() mock_response.status_code = 400 mock_response.json.return_value = { 'error': { 'message': 'Invalid request', 'code': 'invalid_request' } } with patch('requests.post', return_value=mock_response): with pytest.raises(StateSetError) as exc_info: client.orders.create() assert 'Invalid request' in str(exc_info.value) @pytest.mark.asyncio async def test_async_client(): from StateSet import AsyncStateSetClient async_client = AsyncStateSetClient(api_key='sk_test_123') with patch('httpx.AsyncClient.post') as mock_post: mock_post.return_value.json.return_value = {'id': 'ord_123'} mock_post.return_value.status_code = 201 order = await async_client.orders.create( customer_id='cus_123' ) assert order.id == 'ord_123' ``` ```php theme={null} client = new StateSetClient([ 'api_key' => 'sk_test_123', 'environment' => 'sandbox' ]); } public function testCreateOrder() { // Create mock handler $mock = new MockHandler([ new Response(201, [], json_encode([ 'id' => 'ord_123', 'status' => 'pending', 'customer_id' => 'cus_123' ])) ]); $handlerStack = HandlerStack::create($mock); $mockClient = new Client(['handler' => $handlerStack]); // Inject mock client $this->client->setHttpClient($mockClient); $order = $this->client->orders->create([ 'customer_id' => 'cus_123', 'items' => [ ['product_id' => 'prod_123', 'quantity' => 1] ] ]); $this->assertEquals('ord_123', $order->id); $this->assertEquals('pending', $order->status); } public function testHandleError() { $mock = new MockHandler([ new Response(400, [], json_encode([ 'error' => [ 'message' => 'Invalid customer_id', 'code' => 'invalid_request' ] ])) ]); $handlerStack = HandlerStack::create($mock); $mockClient = new Client(['handler' => $handlerStack]); $this->client->setHttpClient($mockClient); $this->expectException(StateSetException::class); $this->expectExceptionMessage('Invalid customer_id'); $this->client->orders->create([]); } } ``` ### Integration Testing ```javascript theme={null} // integration-test.js import { StateSetClient } from 'StateSet-node'; import assert from 'assert'; const runIntegrationTests = async () => { logger.info('🧪 Running StateSet Integration Tests...\n'); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: 'sandbox' }); const tests = [ { name: 'Health Check', fn: async () => { const health = await client.health.check(); assert(health.status === 'healthy', 'API should be healthy'); } }, { name: 'Create Customer', fn: async () => { const customer = await client.customers.create({ email: `test-${Date.now()}@example.com`, name: 'Test Customer' }); assert(customer.id, 'Customer should have an ID'); return customer; } }, { name: 'Create Order', fn: async (customer) => { const order = await client.orders.create({ customer_id: customer.id, items: [ { product_id: 'prod_test', quantity: 1, price: 1000 } ] }); assert(order.id, 'Order should have an ID'); assert(order.status === 'pending', 'Order should be pending'); return order; } }, { name: 'Retrieve Order', fn: async (order) => { const retrieved = await client.orders.retrieve(order.id); assert(retrieved.id === order.id, 'Should retrieve the same order'); } }, { name: 'List Orders', fn: async () => { const orders = await client.orders.list({ limit: 5 }); assert(Array.isArray(orders.data), 'Should return an array of orders'); assert(orders.data.length <= 5, 'Should respect limit parameter'); } } ]; let context = {}; for (const test of tests) { try { const result = await test.fn(context); if (result) context = result; logger.info(`✅ ${test.name}`); } catch (error) { logger.error(`❌ ${test.name}: ${error.message}`); process.exit(1); } } logger.info('\n✨ All integration tests passed!'); }; runIntegrationTests().catch(console.error); ``` ### Load Testing ```javascript theme={null} // load-test.js import { StateSetClient } from 'StateSet-node'; import pLimit from 'p-limit'; const runLoadTest = async () => { const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: 'sandbox' }); const limit = pLimit(10); // Max 10 concurrent requests const totalRequests = 100; const startTime = Date.now(); logger.info(`🚀 Starting load test with ${totalRequests} requests...\n`); const requests = Array.from({ length: totalRequests }, (_, i) => limit(async () => { const start = Date.now(); try { await client.orders.list({ limit: 1 }); return { success: true, duration: Date.now() - start }; } catch (error) { return { success: false, error: error.message, duration: Date.now() - start }; } }) ); const results = await Promise.all(requests); const endTime = Date.now(); // Calculate statistics const successful = results.filter(r => r.success).length; const failed = results.filter(r => !r.success).length; const avgDuration = results.reduce((sum, r) => sum + r.duration, 0) / results.length; const totalDuration = endTime - startTime; const requestsPerSecond = (totalRequests / totalDuration) * 1000; logger.info('📊 Load Test Results:'); logger.info(`Total Requests: ${totalRequests}`); logger.info(`Successful: ${successful} (${(successful/totalRequests*100);.toFixed(1)}%)`); logger.info(`Failed: ${failed}`); logger.info(`Average Response Time: ${avgDuration.toFixed(0);}ms`); logger.info(`Total Duration: ${totalDuration}ms`); logger.info(`Requests/Second: ${requestsPerSecond.toFixed(1);}`); if (failed > 0) { logger.info('\n❌ Failed requests:'); results.filter(r => !r.success).forEach((r, i) => { logger.info(` ${i + 1}. ${r.error}`); }); } }; runLoadTest().catch(console.error); ``` *** ## Best Practices ### Security Never commit API keys or secrets to version control. Always use environment variables. ```javascript theme={null} // config/StateSet.js import { StateSetClient } from 'StateSet-node'; // Validate environment const validateEnvironment = () => { const required = ['STATESET_API_KEY']; const missing = required.filter(key => !process.env[key]); if (missing.length > 0) { throw new Error(`Missing environment variables: ${missing.join(', ')}`); } // Validate API key format const apiKey = process.env.STATESET_API_KEY; if (!apiKey.startsWith('sk_test_') && !apiKey.startsWith('sk_live_')) { throw new Error('Invalid API key format'); } // Ensure test keys aren't used in production if (process.env.NODE_ENV === 'production' && apiKey.startsWith('sk_test_')) { throw new Error('Test API keys cannot be used in production'); } }; validateEnvironment(); export const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox' }); ``` ```javascript theme={null} // Implement key rotation without downtime class StateSetClientManager { constructor() { this.clients = new Map(); this.primaryKey = process.env.STATESET_API_KEY_PRIMARY; this.secondaryKey = process.env.STATESET_API_KEY_SECONDARY; } getClient(useSecondary = false) { const key = useSecondary ? this.secondaryKey : this.primaryKey; if (!this.clients.has(key)) { this.clients.set(key, new StateSetClient({ apiKey: key })); } return this.clients.get(key); } async rotateKeys() { // Test secondary key try { const secondaryClient = this.getClient(true); await secondaryClient.health.check(); // Swap keys this.primaryKey = this.secondaryKey; this.secondaryKey = process.env.STATESET_API_KEY_NEW; // Clear old client this.clients.clear(); logger.info('Key rotation completed successfully'); } catch (error) { logger.error('Key rotation failed:', error); throw error; } } } ``` ### Error Handling ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; import retry from 'async-retry'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, maxRetries: 0 // Disable built-in retry }); // Custom retry with exponential backoff async function resilientRequest(operation) { return retry( async (bail) => { try { return await operation(); } catch (error) { // Don't retry client errors if (error.statusCode >= 400 && error.statusCode < 500) { bail(error); } throw error; } }, { retries: 5, factor: 2, minTimeout: 1000, maxTimeout: 30000, onRetry: (error, attempt) => { logger.info(`Attempt ${attempt} failed:`, error.message); } } ); } // Usage const order = await resilientRequest(() => client.orders.create(orderData) ); ``` ```javascript theme={null} import CircuitBreaker from 'opossum'; const options = { timeout: 3000, errorThresholdPercentage: 50, resetTimeout: 30000 }; const breaker = new CircuitBreaker( async (data) => client.orders.create(data), options ); breaker.on('open', () => logger.info('Circuit breaker opened'); ); breaker.on('halfOpen', () => logger.info('Circuit breaker half-open'); ); // Usage with fallback try { const order = await breaker.fire(orderData); } catch (error) { if (breaker.opened) { // Use fallback behavior logger.info('Service unavailable, using cache'); return getCachedOrder(orderId); } throw error; } ``` ### Performance Optimization ```javascript theme={null} // Reuse HTTP connections import https from 'https'; const agent = new https.Agent({ keepAlive: true, keepAliveMsecs: 1000, maxSockets: 50, maxFreeSockets: 10, timeout: 60000 }); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, httpsAgent: agent }); ``` ```javascript theme={null} class BatchProcessor { constructor(client, options = {}) { this.client = client; this.batchSize = options.batchSize || 100; this.flushInterval = options.flushInterval || 1000; this.queue = []; this.timer = null; } add(operation) { this.queue.push(operation); if (this.queue.length >= this.batchSize) { this.flush(); } else if (!this.timer) { this.timer = setTimeout(() => this.flush(), this.flushInterval); } } async flush() { if (this.timer) { clearTimeout(this.timer); this.timer = null; } if (this.queue.length === 0) return; const batch = this.queue.splice(0, this.batchSize); try { const results = await Promise.all( batch.map(op => op.execute()) ); batch.forEach((op, i) => { op.resolve(results[i]); }); } catch (error) { batch.forEach(op => op.reject(error)); } } } ``` ```javascript theme={null} import { LRUCache } from 'lru-cache'; const cache = new LRUCache({ max: 500, ttl: 1000 * 60 * 5, // 5 minutes updateAgeOnGet: true }); class CachedStateSetClient { constructor(client) { this.client = client; } async getOrder(orderId, skipCache = false) { const cacheKey = `order:${orderId}`; if (!skipCache && cache.has(cacheKey)) { return cache.get(cacheKey); } const order = await this.client.orders.retrieve(orderId); cache.set(cacheKey, order); return order; } async createOrder(data) { const order = await this.client.orders.create(data); // Cache the created order cache.set(`order:${order.id}`, order); // Invalidate list cache cache.delete('orders:list'); return order; } async listOrders(params = {}) { const cacheKey = `orders:list:${JSON.stringify(params)}`; if (cache.has(cacheKey)) { return cache.get(cacheKey); } const orders = await this.client.orders.list(params); cache.set(cacheKey, orders); return orders; } } ``` ### Monitoring & Logging ```javascript theme={null} // monitoring.js import { StateSetClient } from 'StateSet-node'; import winston from 'winston'; import { StatsD } from 'node-statsd'; // Configure logger const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), transports: [ new winston.transports.File({ filename: 'StateSet-error.log', level: 'error' }), new winston.transports.File({ filename: 'StateSet-combined.log' }) ] }); // Configure metrics const metrics = new StatsD({ host: 'localhost', port: 8125, prefix: 'StateSet.' }); // Wrap client with monitoring class MonitoredStateSetClient extends StateSetClient { async request(method, path, data) { const startTime = Date.now(); const metricName = `api.${method.toLowerCase()}.${path.replace(/\//g, '.')}`; try { const result = await super.request(method, path, data); // Log success const duration = Date.now() - startTime; metrics.timing(metricName, duration); metrics.increment(`${metricName}.success`); logger.info('API Request Success', { method, path, duration, status: result.status }); return result; } catch (error) { // Log error const duration = Date.now() - startTime; metrics.timing(metricName, duration); metrics.increment(`${metricName}.error`); logger.error('API Request Failed', { method, path, duration, error: { message: error.message, code: error.code, statusCode: error.statusCode, requestId: error.requestId } }); throw error; } } } ``` *** ## Next Steps Now that you have StateSet SDK installed and configured: Detailed documentation for all endpoints Interactive API testing environment Connect your online store Configure real-time events Build resilient applications Understand API limits Check out our example applications: * [Node.js E-commerce App](https://github.com/StateSet/example-node-ecommerce) * [Python Order Management](https://github.com/StateSet/example-python-orders) * [Ruby on Rails Integration](https://github.com/StateSet/example-rails) * [PHP WordPress Plugin](https://github.com/StateSet/wordpress-plugin) ## Support & Resources * [API Reference](/api-reference) * [Guides & Tutorials](/guides) * [Code Examples](https://github.com/StateSet/examples) * [Changelog](/changelog) * [Discord Community](https://discord.gg/VfcaqgZywq) * [GitHub Discussions](https://github.com/StateSet/StateSet-node/discussions) * [Stack Overflow](https://stackoverflow.com/questions/tagged/StateSet) * [Twitter Updates](https://twitter.com/StateSet) * Email: [support@StateSet.com](mailto:support@StateSet.com) * Enterprise: [enterprise@StateSet.com](mailto:enterprise@StateSet.com) * Security: [security@StateSet.com](mailto:security@StateSet.com) * [System Status](https://status.StateSet.com) * [API Changelog](/changelog) * [Blog](https://StateSet.com/blog) * [Newsletter](https://StateSet.com/newsletter) **Need help?** Our support team is available Monday-Friday, 9 AM - 5 PM PST. Enterprise customers have 24/7 support. # Shopify Product Quickstart Source: https://docs.stateset.com/guides/shopify-quickstart Getting started with the Shopify Embeddings ### Quickstart Guide This is a quickstart guide to get you up and running with the Shopify Embeddings. This guide will walk you through the steps to get your Shopify product data into Pinecone and create embeddings for each product. ### Authentication StateSet ResponseCX Shopify App ### Shopify Product Embeddings Once you have installed the app we can create embeddings and store your Shopify product data in Pinecone, you can create embeddings for each product. Embeddings are vector representations of your product data. You can use these embeddings to find similar products, recommend products, and more. Loop Through Shopify Product Data Create embeddings for each product returns and store in Pinecone Store the vector representation of the product data in Pinecone and associated metadata with the product data ```javascript theme={null} let page = 1; // Get Shopify Products async function getShopifyProducts(nextPageToken, shop, limit, maxPage, shopify_access_token, pinecone_index, pinecone_api_key, pinecone_namespace) { if (nextPageToken && page <= maxPage) { const axiosConfig = { headers: { 'Content-Type': 'application/json', 'X-Shopify-Access-Token': shopify_access_token }, }; const response = await axios.get(`https://${shop}/admin/api/2021-10/products.json?limit=${limit}&page_info=${nextPageToken}; rel="next"`, axiosConfig); nextPageToken = response.headers.link?.split(",")?.find((link) => link.includes(`rel="next"`))?.match(/<(.+)>/)?.[1]; const products = response.data.products; const documents = []; for (const item of products) { try { const id = item.id || null; const title = item.title || null; const handle = item.handle || null; const image = item.image.src || null; const images_src = item.image.src || null; const vendor = item.vendor || null; const product_type = item.product_type || null; for (const variant of item.variants) { const sku = variant.sku || null; const variants_sku = variant.sku || null; const variants_price = variant.price || null; const variants_compare_at_price = variant.compare_at_price || null; const variants_inventory_quantity = variant.inventory_quantity || null; const option_1 = variant.option1 || null; const option_2 = variant.option2 || null; const option_3 = variant.option3 || null; const shipping_weight = variant.weight || null; const variant_id = variant.id || null; let metadata = { id, title, handle, image, sku, variants_sku, images_src, variants_price, variants_compare_at_price, variants_inventory_quantity, vendor, option_1, option_2, option_3, shipping_weight, product_type, variant_id }; const document = { id: uuid(), title, metadata, }; documents.push(document); } } catch (error) { logger.info(`Error processing item: ${JSON.stringify(item);}`); logger.info(error); } for (let i = 0; i < documents.length; i += DOCUMENT_UPSERT_BATCH_SIZE) { // Split documents into batches var batchDocuments = documents.slice(i, i + DOCUMENT_UPSERT_BATCH_SIZE); logger.info(batchDocuments); // Convert batchDocuments to string var batchDocumentString = JSON.stringify(batchDocuments) // Remove commas from string logger.info(batchDocumentString); // Create Embeddings logger.info('Looping through documents...'); const user_id = "domsteil"; // OpenAI Request Body var raw = JSON.stringify({ "input": batchDocumentString, "model": "text-embedding-ada-002", "user": user_id }); // OpenAI Request Options var requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': process.env.OPEN_AI }, body: raw, redirect: 'follow' }; // Make Callout to OpenAI to get Embeddings logger.info('Creating Embedding...'); // Make Callout to OpenAI let embeddings_response = await fetch("https://api.openai.com/v1/embeddings", requestOptions) // Create Pinecone Request Body const vectors_embeddings = await embeddings_response.json(); logger.info(vectors_embeddings); // Create Pinecone Request Body var vectors_object = { id: uuid(), values: vectors_embeddings.data[0].embedding, metadata: { "text": batchDocumentString, "user": user_id } }; logger.info(vectors_object); var raw = JSON.stringify({ "vectors": vectors_object, "namespace": "shopify_product_data" }); var pineconeRequestOptions = { method: "POST", headers: { "Content-Type": "application/json", "Host": pinecone_index, "Content-Length": 60, "Api-Key": pinecone_api_key, }, body: raw, redirect: "follow", }; // Make Callout to Pinecone // Pinecone Upsert logger.info('Upserting Pinecone...'); let pinecone_query_response = await fetch(`https://${pinecone_index}/vectors/upsert`, pineconeRequestOptions) .then(response => response.text()) .then(json => { logger.info(json); }) .catch(error => { logger.error(error); }); } } page += 1; logger.info(`On page ${page}, processing next page...`); return getShopifyProducts(nextPageToken, shop, limit, maxPage, shopify_access_token, pinecone_index, pinecone_api_key, pinecone_namespace); ``` # Smart Agents Transacting with USDC Source: https://docs.stateset.com/guides/smart-agents-usdc-guide Enable AI agents to autonomously execute commerce transactions using native USDC on StateSet # Smart Agents: Autonomous Commerce with USDC ## Overview StateSet Commerce Network enables AI agents to transact autonomously using native USDC, creating a new paradigm for automated commerce. This guide covers how to build, deploy, and manage smart agents that can execute transactions, manage inventory, optimize pricing, and handle complex commercial workflows - all without human intervention. ## Why Smart Agents on StateSet? ### The Perfect Environment for Agent Commerce * **Native USDC**: Agents transact in stable digital dollars * **No Gas Complexity**: Fees paid directly in USDC * **Instant Settlement**: Sub-second transaction finality * **Rich APIs**: Comprehensive commerce modules * **Built-in Compliance**: KYC/AML checks automated * **Programmable Logic**: Smart contracts enforce boundaries ## Quick Start: Your First Trading Agent ```typescript theme={null} import { StateSetAgent, AgentWallet } from '@StateSet/agent-sdk'; // Initialize an agent with spending limits const agent = new StateSetAgent({ name: 'TradingBot-001', wallet: new AgentWallet({ seed: process.env.AGENT_SEED, spendingLimit: '10000.00', // Daily USDC limit approvedContracts: ['StateSet1abc...'] // Whitelisted contracts }), capabilities: ['trade', 'analyze', 'report'] }); // Agent autonomously executes trades await agent.execute({ task: 'optimize_inventory', parameters: { targetMargin: 0.15, maxOrderSize: '1000.00', reorderPoint: 100 } }); ``` ## Architecture: How Agent Commerce Works ```mermaid theme={null} graph TD A[AI Agent] -->|Analyzes| B[Market Data] A -->|Decides| C[Action Required] C -->|Generates| D[Transaction] D -->|Signs with| E[Agent Wallet] E -->|Broadcasts to| F[StateSet Network] F -->|Validates| G[Smart Contract] G -->|Executes| H[USDC Transfer] H -->|Updates| I[State] I -->|Notifies| A ``` ## Core Concepts ### 1. Agent Wallets Agent wallets are specialized accounts with built-in safety features: ```typescript theme={null} const agentWallet = new AgentWallet({ // Hierarchical deterministic wallet for the agent seed: generateSecureSeed(), // Safety parameters limits: { perTransaction: '1000.00', daily: '10000.00', monthly: '100000.00' }, // Allowed operations permissions: { allowedMethods: ['transfer', 'swap', 'stake'], blockedAddresses: ['suspicious1...'], requiresApproval: ['amount > 5000'] } }); ``` ### 2. Agent Permissions Fine-grained control over agent capabilities: ```typescript theme={null} // Define agent boundaries const permissions = { // Financial limits spending: { max_per_tx: '5000.00', max_daily: '25000.00', require_2fa_above: '10000.00' }, // Operational constraints operations: { can_create_orders: true, can_modify_prices: true, max_price_change: 0.10, // 10% blackout_hours: [0, 6] // No trades 12am-6am }, // Smart contract interactions contracts: { whitelist: ['dex_contract', 'lending_protocol'], max_gas_per_tx: '1.00' // USDC } }; ``` ### 3. Agent State Management Agents maintain state across transactions: ```typescript theme={null} interface AgentState { wallet: { address: string; balance: string; // USDC balance nonce: number; }; metrics: { total_transactions: number; total_volume: string; success_rate: number; profit_loss: string; }; inventory: { products: Product[]; total_value: string; turnover_rate: number; }; learning: { model_version: string; last_training: Date; performance_score: number; }; } ``` ## Use Cases ### 1. 🛒 E-Commerce Price Optimization ```typescript theme={null} const pricingAgent = new StateSetAgent({ name: 'DynamicPricer', type: 'pricing_optimizer' }); // Agent monitors competitors and adjusts prices pricingAgent.addStrategy({ name: 'competitive_pricing', async execute(context) { // Get competitor prices const competitors = await context.fetchCompetitorPrices(); // Calculate optimal price const optimalPrice = context.ml.calculatePrice({ competitors, inventory: context.inventory, demand: context.demandForecast, targetMargin: 0.20 }); // Update price on StateSet if (Math.abs(optimalPrice - context.currentPrice) > 0.50) { await context.StateSet.products.updatePrice({ sku: context.product.sku, price: optimalPrice.toFixed(2), reason: 'Competitive adjustment' }); } }, frequency: 'every 15 minutes', limits: { maxPriceChange: 0.15, // 15% max change minMargin: 0.10 // 10% minimum margin } }); ``` ### 2. 💱 Arbitrage Trading ```typescript theme={null} const arbitrageBot = new StateSetAgent({ name: 'ArbitrageHunter', type: 'trading' }); // Multi-DEX arbitrage scanner arbitrageBot.addStrategy({ name: 'dex_arbitrage', async execute(context) { // Monitor price differences across DEXs const opportunities = await context.scanArbitrage({ pairs: ['USDC/STATE', 'ATOM/USDC'], minProfit: '10.00', // Minimum $10 profit maxSlippage: 0.005 // 0.5% slippage tolerance }); for (const opp of opportunities) { // Calculate profit after fees const netProfit = opp.profit - (opp.fees * 2); if (netProfit > 10) { // Execute arbitrage atomically await context.executeArbitrage({ buyOn: opp.cheaperDex, sellOn: opp.expensiveDex, amount: opp.optimalAmount, deadline: Date.now() + 30000 // 30 second deadline }); } } }, frequency: 'continuous', riskLimits: { maxPositionSize: '5000.00', maxOpenPositions: 3, stopLoss: '100.00' } }); ``` ### 3. 📦 Supply Chain Automation ```typescript theme={null} const supplyChainAgent = new StateSetAgent({ name: 'SupplyManager', type: 'operations' }); // Automated reordering system supplyChainAgent.addStrategy({ name: 'auto_reorder', async execute(context) { const inventory = await context.StateSet.inventory.list(); for (const item of inventory) { // Check if reorder needed if (item.quantity <= item.reorderPoint) { // Calculate optimal order quantity const orderQty = context.calculateEOQ({ demand: item.avgDailyDemand * 30, orderCost: '50.00', holdingCost: item.value * 0.20 / 365 }); // Find best supplier const suppliers = await context.findSuppliers(item.sku); const bestSupplier = context.selectSupplier(suppliers, { criteria: ['price', 'delivery_time', 'reliability'], weights: [0.4, 0.3, 0.3] }); // Create purchase order const po = await context.StateSet.purchaseOrders.create({ supplier: bestSupplier.did, items: [{ sku: item.sku, quantity: orderQty, price: bestSupplier.price }], terms: 'Net 30', delivery: bestSupplier.estimatedDelivery }); // Pay with USDC if early payment discount available if (bestSupplier.earlyPayDiscount > 0.02) { await context.StateSet.orders.pay({ order_id: po.id, amount: po.total * (1 - bestSupplier.earlyPayDiscount) }); } } } }, frequency: 'daily at 6am UTC' }); ``` ### 4. 🤖 Customer Service Agent ```typescript theme={null} const customerAgent = new StateSetAgent({ name: 'CustomerSupport', type: 'service' }); // Automated refund processing customerAgent.addCapability({ name: 'process_refunds', async execute(context, request) { // Validate refund request const order = await context.StateSet.orders.get(request.orderId); const validation = await context.validateRefund(order, request); if (validation.approved) { // Process instant USDC refund const refund = await context.StateSet.orders.refund({ order_id: order.id, amount: validation.refundAmount, reason: validation.reason, items: validation.items }); // Update customer record await context.updateCustomerRecord({ customerId: order.customerId, event: 'refund_processed', amount: refund.amount, satisfaction: request.satisfaction }); return { success: true, refundId: refund.id, message: `Refund of ${refund.amount} USDC processed successfully` }; } return { success: false, reason: validation.rejectionReason, alternativeOptions: validation.alternatives }; }, limits: { maxRefundAmount: '500.00', requiresHumanApproval: ['amount > 500', 'frequency > 3'] } }); ``` ### 5. 💰 Yield Optimization ```typescript theme={null} const yieldAgent = new StateSetAgent({ name: 'YieldOptimizer', type: 'defi' }); // Optimize idle USDC balances yieldAgent.addStrategy({ name: 'optimize_treasury', async execute(context) { // Get current balance const balance = await context.getUSDCBalance(); const reserves = balance * 0.20; // Keep 20% liquid const deployable = balance - reserves; if (deployable > 1000) { // Analyze yield opportunities const opportunities = await context.analyzeYield({ chains: ['StateSet', 'osmosis', 'neutron'], protocols: ['lending', 'liquidity', 'staking'], minAPR: 0.05, maxRisk: 'medium' }); // Diversify across strategies const allocation = context.optimizeAllocation({ amount: deployable, opportunities, constraints: { maxPerProtocol: 0.40, minLiquidity: 'daily', targetAPR: 0.08 } }); // Deploy capital for (const alloc of allocation) { await context.deployCapital({ protocol: alloc.protocol, amount: alloc.amount, duration: alloc.lockPeriod, autoCompound: true }); } } }, frequency: 'daily', monitoring: { checkHealth: 'hourly', rebalanceThreshold: 0.05, emergencyWithdraw: ['protocol_risk > high', 'apr_drop > 50%'] } }); ``` ## Advanced Features ### Multi-Agent Systems Deploy fleets of specialized agents working together: ```typescript theme={null} const agentOrchestrator = new AgentOrchestrator({ agents: [ { id: 'sourcing-01', type: 'procurement', budget: '50000.00' }, { id: 'pricing-01', type: 'revenue', budget: '10000.00' }, { id: 'logistics-01', type: 'fulfillment', budget: '20000.00' }, { id: 'finance-01', type: 'treasury', budget: '100000.00' } ], coordination: { communicationProtocol: 'mesh', // Agents communicate directly consensusRequired: ['budget > 10000', 'risk > medium'], disputeResolution: 'voting' } }); // Agents collaborate on complex tasks await agentOrchestrator.executeWorkflow({ name: 'new_product_launch', steps: [ { agent: 'sourcing-01', task: 'find_suppliers' }, { agent: 'finance-01', task: 'analyze_unit_economics' }, { agent: 'pricing-01', task: 'set_launch_price' }, { agent: 'logistics-01', task: 'setup_fulfillment' } ] }); ``` ### Machine Learning Integration Agents that learn and improve over time: ```typescript theme={null} const mlAgent = new StateSetAgent({ name: 'SmartTrader', ml: { model: 'reinforcement_learning', features: ['price', 'volume', 'sentiment', 'on_chain_metrics'], training: 'continuous', framework: 'tensorflow.js' } }); // Agent learns from outcomes mlAgent.addLearningLoop({ async onTransactionComplete(tx, outcome) { // Record outcome for training await this.recordOutcome({ action: tx.action, context: tx.context, result: outcome, reward: outcome.profit - outcome.costs }); // Retrain if performance drops if (this.performance.last100Trades < 0.6) { await this.retrain({ epochs: 100, batchSize: 32, learningRate: 0.001 }); } } }); ``` ### Risk Management Framework Built-in risk controls for agent operations: ```typescript theme={null} const riskFramework = { // Position limits positions: { maxConcentration: 0.20, // Max 20% in one asset maxLeverage: 1.0, // No leverage allowed maxDrawdown: 0.10 // Stop at 10% loss }, // Operational limits operations: { maxTransactionsPerHour: 100, maxValuePerHour: '50000.00', requiredConfirmations: 1 }, // Circuit breakers circuitBreakers: [ { condition: 'loss > 1000 USDC in 1 hour', action: 'pause_all_trading' }, { condition: 'error_rate > 0.10', action: 'alert_human_operator' }, { condition: 'unusual_activity_detected', action: 'require_2fa' } ] }; ``` ## Security Best Practices ### 1. Secure Key Management ```typescript theme={null} // Use hardware security modules for production const secureWallet = new AgentWallet({ keyStorage: 'hsm', provider: 'aws-cloudhsm', backupStrategy: 'shamir-secret-sharing', threshold: 3, shares: 5 }); // Rotate keys periodically const keyRotation = { frequency: 'monthly', strategy: 'gradual', // Overlap old and new keys notifyWebhook: 'https://api.company.com/key-rotation' }; ``` ### 2. Transaction Verification ```typescript theme={null} // Multi-signature requirements for large transactions const multiSigPolicy = { thresholds: [ { amount: '1000.00', signatures: 1 }, { amount: '10000.00', signatures: 2 }, { amount: '100000.00', signatures: 3 } ], signers: [ { role: 'agent', weight: 1 }, { role: 'risk_system', weight: 1 }, { role: 'human_operator', weight: 2 } ] }; ``` ### 3. Audit Logging ```typescript theme={null} // Comprehensive audit trail const auditLogger = new AuditLogger({ storage: 'immutable', encryption: 'aes-256-gcm', logEvents: [ 'transaction_initiated', 'transaction_signed', 'transaction_broadcast', 'transaction_confirmed', 'balance_changed', 'permission_changed', 'error_occurred' ], retention: '7 years', export: { format: 'json', schedule: 'daily', destination: 's3://audit-logs/' } }); ``` ## Monitoring and Analytics ### Real-Time Dashboards ```typescript theme={null} // Monitor agent performance const monitoring = new AgentMonitor({ metrics: [ 'transaction_volume', 'success_rate', 'avg_response_time', 'profit_loss', 'gas_consumed' ], alerts: [ { metric: 'error_rate', threshold: 0.05, action: 'email' }, { metric: 'daily_loss', threshold: '1000.00', action: 'pause_agent' } ], dashboard: 'https://monitoring.company.com/agents' }); ``` ### Performance Analytics ```typescript theme={null} // Track agent effectiveness const analytics = await agent.getAnalytics({ period: 'last_30_days', metrics: [ 'total_transactions', 'volume_traded', 'fees_paid', 'net_profit', 'success_rate', 'avg_execution_time' ] }); logger.info(` Agent Performance Report: - ROI: ${analytics.roi}% - Win Rate: ${analytics.winRate}% - Sharpe Ratio: ${analytics.sharpeRatio} - Total Profit: ${analytics.totalProfit} USDC `); ``` ## Deployment Guide ### 1. Development Environment ```bash theme={null} # Clone the agent template git clone https://github.com/StateSet/agent-template cd agent-template # Install dependencies npm install # Configure environment cp .env.example .env # Edit .env with your settings # Run tests npm test # Start local agent npm run dev ``` ### 2. Production Deployment ```yaml theme={null} # kubernetes/agent-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: trading-agent spec: replicas: 3 template: spec: containers: - name: agent image: StateSet/agent:latest env: - name: AGENT_WALLET valueFrom: secretKeyRef: name: agent-secrets key: wallet-seed - name: SPENDING_LIMIT value: "10000.00" - name: STATESET_ENDPOINT value: "https://api.StateSet.network" resources: limits: memory: "1Gi" cpu: "500m" ``` ### 3. Monitoring Setup ```typescript theme={null} // Initialize monitoring const monitor = new StateSetMonitor({ agentId: 'trading-bot-001', webhooks: { alerts: 'https://api.company.com/alerts', reports: 'https://api.company.com/reports' }, customMetrics: [ { name: 'arbitrage_opportunities', query: 'count(trades.type = "arbitrage")' }, { name: 'avg_profit_per_trade', query: 'avg(trades.profit)' } ] }); ``` ## Cost Optimization ### Fee Management ```typescript theme={null} // Optimize transaction costs const feeOptimizer = { // Batch transactions when possible batching: { enabled: true, maxBatchSize: 100, maxWaitTime: '5 minutes' }, // Use efficient routes routing: { preferDirectTransfers: true, maxHops: 2, avoidHighFeeContracts: true }, // Time transactions optimally timing: { avoidPeakHours: true, preferredHours: [2, 3, 4, 5], // UTC urgentThreshold: '1000.00' // Skip optimization for urgent } }; ``` ## Compliance and Regulations ### Built-in Compliance ```typescript theme={null} const complianceFramework = { // KYC/AML for agent operations kyc: { requiredFor: ['withdrawal > 10000', 'new_counterparty'], provider: 'chainalysis', refreshFrequency: 'annual' }, // Transaction monitoring aml: { screenCounterparties: true, flagSuspiciousPatterns: true, reportingThreshold: '10000.00', sarsFilingWebhook: 'https://compliance.company.com/sars' }, // Regulatory reporting reporting: { taxReporting: { form: '1099-K', frequency: 'annual', includeFees: true }, regulatoryReporting: { jurisdictions: ['US', 'EU'], realTime: true } } }; ``` ## Future Roadmap ### Coming Soon 1. **Natural Language Control**: Tell agents what to do in plain English 2. **Cross-Chain Agents**: Operate seamlessly across multiple blockchains 3. **Agent Marketplace**: Buy, sell, and license proven agent strategies 4. **Collaborative Agents**: Agents that work together on complex tasks 5. **Quantum-Resistant Security**: Future-proof cryptography ## Conclusion Smart agents on StateSet Commerce Network represent the future of autonomous commerce. With native USDC, instant settlements, and comprehensive APIs, developers can build agents that: * Execute complex trading strategies * Optimize business operations * Provide 24/7 customer service * Manage treasury and yield * Scale without human intervention The combination of AI and blockchain creates unprecedented opportunities for automation, efficiency, and innovation in commerce. ## Resources * [Agent SDK Documentation](https://docs.StateSet.network/agent-sdk) * [Example Agents](https://github.com/StateSet/agent-examples) * [Video Tutorials](https://youtube.com/StateSet-agents) * [Discord Community](https://discord.gg/VfcaqgZywq-agents) Start building your autonomous commerce agent today and join the revolution in how business gets done. # Sources Quickstart Source: https://docs.stateset.com/guides/sources-quickstart This guide explains how to create and manage information Sources for your ResponseCX Agents. ## What are Sources? In ResponseCX, a Source is a location where your Agents can retrieve information to answer user questions. A source can be a website, a document, or a knowledge base. By providing sources, you can equip your agents with the specific knowledge they need to be effective. ## Creating a Source You can create a source through the Response\_CX dashboard or using the SDK. ### Using the Dashboard 1. Navigate to the **Sources** section of the ResponseCX dashboard. 2. Click the **Add New Source** button. 3. Fill in the source's details. For example: * **Name:** A descriptive name for your source (e.g., "Public Website"). * **Description:** A brief summary of what the source contains. * **Type:** The type of source, such as `Website`, `Document`, or `Knowledge Base`. * **URI:** The location of the source, like a URL for a website or a path to a document. 4. Click **Add Source** to create the source. ### Using the SDK Here's how to create a source using the Node.js SDK. ```javascript theme={null} // The 'StateSet' object should be initialized with your API key. // Please refer to the official StateSet SDK documentation for initialization details. // For example: // const StateSet = new StateSet({ apiKey: process.env.STATESET_API_KEY }); const source = await StateSet.sources.create({ name: "My API-created Source", description: "Documentation website.", type: "Website", uri: "https://docs.example.com", }); logger.info("Source created:", source); ``` ## Managing Sources You can list, update, and delete your sources. ### Listing Sources Retrieve a list of all your sources via the SDK. ```javascript theme={null} const sources = await StateSet.sources.list(); logger.info(sources); ``` ## Updating a Source You can update a source's properties from the dashboard or through the SDK. ### Using the Dashboard 1. In the **Sources** list, click the **Update** button for the source you want to modify. 2. Change the desired fields. 3. Click **Save**. ### Using the SDK ```javascript theme={null} const updatedSource = await StateSet.sources.update({ id: source.id, name: "Updated Source Name", }); logger.info("Source updated:", updatedSource); ``` ## Deleting a Source You can delete a source from the dashboard or via the SDK. ```javascript theme={null} await StateSet.sources.delete({ id: source.id }); logger.info("Source deleted."); ``` ## Next Steps After creating a source, you can associate it with an Agent to give that agent access to the information within the source. * **Connect to an Agent:** Learn how to link this source to one of your agents. * **Explore different source types:** Investigate how to use other source types, like documents or knowledge bases. # StateSet Cloud Quickstart Source: https://docs.stateset.com/guides/stateset-cloud-quickstart Getting started with the StateSet Cloud ## Introduction StateSet Cloud is our fully managed platform that provides scalable infrastructure, secure APIs, and comprehensive tools for building and deploying autonomous business operations. This guide will walk you through the initial setup and configuration of your StateSet Cloud environment. ## Prerequisites Before you begin, ensure you have: * A StateSet account (sign up at [StateSet.com/sign-up](https://StateSet.com/sign-up)) * Access to your email for verification * Basic understanding of REST APIs and authentication ## Getting Started Navigate to the [StateSet Cloud Dashboard](https://cloud.StateSet.com) and click the **"New Project"** button in the top right corner. Configure your project with: * **Project Name**: A unique identifier for your project * **Environment**: Choose between Development, Staging, or Production * **Region**: Select your preferred data center location for optimal performance Set up your organization to manage team members and billing: 1. Click **"New Organization"** in the dashboard 2. Enter your organization details: * Organization name * Industry type * Company size 3. Configure team settings and invite team members Create API keys to authenticate your applications: 1. Navigate to **Settings > API keys** 2. Click **"New API key"** 3. Configure key permissions: * Read/Write access levels * Scope restrictions (if needed) * Expiration settings 4. Securely store your API key - it won't be shown again ## Core Features ### Infrastructure Management StateSet Cloud provides: * **Auto-scaling**: Automatically adjusts resources based on demand * **Global CDN**: Ensures fast response times worldwide * **Database Management**: Fully managed PostgreSQL with automatic backups * **Event Streaming**: Real-time event processing with Kafka ### Security & Compliance * **SOC 2 Type II Certified**: Enterprise-grade security standards * **Data Encryption**: AES-256 encryption at rest and in transit * **RBAC**: Role-based access control for team management * **Audit Logs**: Complete activity tracking for compliance ### Monitoring & Analytics * **Real-time Dashboards**: Monitor API usage, performance metrics, and costs * **Custom Alerts**: Set up notifications for important events * **Log Management**: Centralized logging with search and filtering ## Environment Configuration ### Development Environment ```javascript theme={null} // .env.development STATESET_API_KEY=your_development_api_key STATESET_API_URL=https://api.StateSet.com/v1 STATESET_ENVIRONMENT=development ``` ### Production Environment ```javascript theme={null} // .env.production STATESET_API_KEY=your_production_api_key STATESET_API_URL=https://api.StateSet.com/v1 STATESET_ENVIRONMENT=production STATESET_LOG_LEVEL=error ``` ## Quick Integration Example Here's a simple example to verify your StateSet Cloud setup: ```javascript theme={null} const { StateSetClient } = require('StateSet-node'); // Initialize the client const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.STATESET_ENVIRONMENT }); // Test the connection async function testConnection() { try { const health = await client.health.check(); logger.info('Connection successful:', health); // Create a test order const order = await client.orders.create({ customer_email: 'test@example.com', items: [{ sku: 'TEST-001', quantity: 1, price: 99.99 }] }); logger.info('Test order created:', order.id); } catch (error) { logger.error('Connection failed:', error); } } testConnection(); ``` ## Best Practices ### API key Management * Never commit API keys to version control * Use environment variables for key storage * Rotate keys regularly * Use separate keys for different environments ### Rate Limiting * Default rate limit: 1000 requests per minute * Implement exponential backoff for retries * Use webhook endpoints for async operations ### Error Handling ```javascript theme={null} try { const response = await client.orders.list(); // Process response } catch (error) { if (error.status === 429) { // Handle rate limiting await sleep(error.retryAfter * 1000); } else if (error.status >= 500) { // Handle server errors logger.error('Server error:', error.message); } } ``` ## Support Resources * **Documentation**: [docs.StateSet.com](https://docs.StateSet.com) * **API Reference**: [api.StateSet.com/reference](https://api.StateSet.com/reference) * **Community Forum**: [community.StateSet.com](https://community.StateSet.com) * **Support Email**: [support@StateSet.com](mailto:support@StateSet.com) ## Advanced Configuration ### Rate Limiting and Retry Strategies Implement robust retry logic to handle API rate limits and transient failures: ```javascript theme={null} class StateSetApiClient { constructor(apiKey, options = {}) { this.apiKey = apiKey; this.maxRetries = options.maxRetries || 3; this.retryDelay = options.retryDelay || 1000; this.rateLimiter = new RateLimiter({ tokensPerInterval: 100, interval: 'minute' }); } async makeRequest(endpoint, options = {}) { let lastError; for (let attempt = 0; attempt <= this.maxRetries; attempt++) { try { // Check rate limit await this.rateLimiter.removeTokens(1); const response = await fetch(`${STATESET_API_URL}${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', ...options.headers } }); // Handle rate limit response if (response.status === 429) { const retryAfter = response.headers.get('Retry-After'); const delay = retryAfter ? parseInt(retryAfter) * 1000 : this.calculateBackoff(attempt); console.warn(`Rate limited. Retrying after ${delay}ms...`); await this.sleep(delay); continue; } // Handle other errors if (!response.ok) { const error = await response.json(); throw new StateSetApiError(error.message, response.status, error.code); } return await response.json(); } catch (error) { lastError = error; // Don't retry on client errors (4xx) if (error.status >= 400 && error.status < 500 && error.status !== 429) { throw error; } // Calculate exponential backoff if (attempt < this.maxRetries) { const delay = this.calculateBackoff(attempt); console.warn(`Request failed, retrying in ${delay}ms...`, error.message); await this.sleep(delay); } } } throw lastError || new Error('Max retries exceeded'); } calculateBackoff(attempt) { // Exponential backoff with jitter const baseDelay = this.retryDelay * Math.pow(2, attempt); const jitter = Math.random() * 1000; return Math.min(baseDelay + jitter, 30000); // Max 30 seconds } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Custom error class for better error handling class StateSetApiError extends Error { constructor(message, status, code) { super(message); this.name = 'StateSetApiError'; this.status = status; this.code = code; } } ``` ### Connection Pooling and Performance Optimize API performance with connection pooling and request batching: ```javascript theme={null} class StateSetBatchClient extends StateSetApiClient { constructor(apiKey, options = {}) { super(apiKey, options); this.batchQueue = []; this.batchSize = options.batchSize || 50; this.batchInterval = options.batchInterval || 100; this.startBatchProcessor(); } // Queue requests for batch processing async batchRequest(operation, data) { return new Promise((resolve, reject) => { this.batchQueue.push({ operation, data, resolve, reject, timestamp: Date.now() }); }); } startBatchProcessor() { setInterval(async () => { if (this.batchQueue.length === 0) return; // Process up to batchSize items const batch = this.batchQueue.splice(0, this.batchSize); try { const response = await this.makeRequest('/batch', { method: 'POST', body: JSON.stringify({ operations: batch.map(item => ({ operation: item.operation, data: item.data })) }) }); // Resolve individual promises batch.forEach((item, index) => { if (response.results[index].error) { item.reject(new Error(response.results[index].error)); } else { item.resolve(response.results[index].data); } }); } catch (error) { // Reject all promises in the batch batch.forEach(item => item.reject(error)); } }, this.batchInterval); } } ``` ## Troubleshooting ### Common Issues and Solutions **Problem**: Getting 401 Unauthorized errors **Solutions**: * Verify your API key is correct and hasn't expired * Check that you're using the correct environment (dev/staging/prod) * Ensure the Authorization header format is correct: `Bearer YOUR_API_KEY` ```javascript theme={null} // Validate API key format if (!apiKey || !apiKey.startsWith('sk_')) { throw new Error('Invalid API key format. Keys should start with sk_'); } ``` **Problem**: Receiving 429 Too Many Requests errors **Solutions**: * Implement exponential backoff (see retry strategy above) * Use batch endpoints when processing multiple items * Cache frequently accessed data * Monitor your usage in the dashboard ```javascript theme={null} // Track API usage const usage = await client.usage.get({ startDate: '2024-01-01', endDate: '2024-01-31' }); logger.info(`API calls this month: ${usage.totalCalls}`); ``` **Problem**: Requests timing out or taking too long **Solutions**: * Implement request timeouts * Use regional endpoints for better latency * Enable HTTP keep-alive for connection reuse ```javascript theme={null} // Configure timeout const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 30000); try { const response = await fetch(url, { signal: controller.signal, // Enable keep-alive keepalive: true }); } finally { clearTimeout(timeout); } ``` **Problem**: Getting 400 Bad Request errors **Solutions**: * Validate data before sending * Check required fields and data types * Use TypeScript for compile-time validation ```typescript theme={null} interface OrderData { customer_email: string; items: Array<{ sku: string; quantity: number; price: number; }>; } function validateOrderData(data: any): data is OrderData { return ( typeof data.customer_email === 'string' && Array.isArray(data.items) && data.items.every(item => typeof item.sku === 'string' && typeof item.quantity === 'number' && typeof item.price === 'number' ) ); } ``` ### Debug Mode Enable debug mode to troubleshoot issues: ```javascript theme={null} const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, debug: true, // Enables detailed logging logger: { info: (msg, data) => logger.info('[INFO]', msg, data);, warn: (msg, data) => console.warn('[WARN]', msg, data), error: (msg, data) => logger.error('[ERROR]', msg, data); } }); // Log all requests and responses client.on('request', (req) => { logger.info('Request:', { method: req.method, url: req.url, headers: req.headers }); }); client.on('response', (res) => { logger.info('Response:', { status: res.status, headers: res.headers, data: res.data }); }); ``` ## Monitoring and Alerts ### Set Up Health Checks Monitor your StateSet Cloud integration health: ```javascript theme={null} class StateSetHealthMonitor { constructor(client, options = {}) { this.client = client; this.checkInterval = options.checkInterval || 60000; // 1 minute this.alertThreshold = options.alertThreshold || 3; this.failureCount = 0; } start() { setInterval(async () => { try { const health = await this.checkHealth(); if (!health.healthy) { this.failureCount++; if (this.failureCount >= this.alertThreshold) { await this.sendAlert({ type: 'service_unhealthy', message: `StateSet API unhealthy for ${this.failureCount} consecutive checks`, details: health }); } } else { this.failureCount = 0; } // Log metrics await this.logMetrics({ timestamp: new Date(), healthy: health.healthy, latency: health.latency, services: health.services }); } catch (error) { logger.error('Health check failed:', error); this.failureCount++; } }, this.checkInterval); } async checkHealth() { const start = Date.now(); try { const response = await this.client.health.check(); const latency = Date.now() - start; return { healthy: response.status === 'healthy', latency, services: response.services, timestamp: new Date() }; } catch (error) { return { healthy: false, error: error.message, timestamp: new Date() }; } } async sendAlert(alert) { // Integrate with your alerting system // Example: PagerDuty, Slack, email, etc. logger.error('ALERT:', alert); } async logMetrics(metrics) { // Send to your metrics system // Example: Datadog, CloudWatch, Prometheus logger.info('Metrics:', metrics); } } // Start monitoring const monitor = new StateSetHealthMonitor(client); monitor.start(); ``` ## Next Steps Now that you have your StateSet Cloud environment set up with robust error handling and monitoring: Learn how to implement autonomous order management Create intelligent AI agents for customer interactions Deep dive into API patterns and optimization Ensure your integration is production-ready # StateSet Computer Use Agents - Quick Start Guide Source: https://docs.stateset.com/guides/stateset-computer-use-agents Quick start guide for using StateSet Computer Use Agents # StateSet Computer Use Agents - Quick Start Guide ## 🚀 Quick Setup ### 1. Install and Activate ```bash theme={null} git clone https://gitlab.com/StateSet/StateSet-computer-use-agent.git cd StateSet-computer-use-agent python -m venv venv source venv/bin/activate pip install -r requirements.txt ``` ### 2. Run Your First Agent ```bash theme={null} # Auto-close tickets ./start-autoclose-agent.sh # Or with custom instruction python main.py "auto-close all pending tickets" ``` ## 📋 Common Commands ### Agent-Specific Commands #### Auto-Close Agent ```bash theme={null} # Using script ./start-autoclose-agent.sh # Direct command python main.py "auto-close tickets" ``` #### Social Media Agent ```bash theme={null} # Using script ./start-socialmedia-agent.sh # Direct command python main.py "social media content moderation" ``` #### LinkedIn Agent ```bash theme={null} # Using script ./start-linkedin-agent.sh # Direct command python main.py "linkedin send connection requests" ``` #### Slack Support Agent ```bash theme={null} # Using script ./start-slack-agent.sh # Direct command python main.py "slack respond to customer inquiries" ``` #### Shopify Agent ```bash theme={null} # Using script ./start-shopify-agent.sh # Direct command python main.py "shopify update product inventory" ``` ### General Purpose Commands ```bash theme={null} # Custom task with general agent ./start-general-agent.sh "your task description here" # Multiple agents simultaneously python main.py "auto-close tickets and social media monitoring" ``` ## 🔧 Configuration Examples ### Setting Display Resolution Edit `main.py`: ```python theme={null} WIDTH = 1920 # Full HD width HEIGHT = 1080 # Full HD height ``` ### API key Configuration Replace in `main.py`: ```python theme={null} api_key = 'sk-ant-api03-YOUR-KEY-HERE' ``` ### Custom Agent Selection Logic Add to `get_active_agents()` function: ```python theme={null} if "custom_keyword" in instruction: active_agents.append(AGENT_CONFIGS["YOUR_AGENT"]) ``` ## 📊 Monitoring Commands ### View Logs in Real-Time ```bash theme={null} # Follow logs as they're generated python main.py "your task" 2>&1 | tee agent.log # Filter logs by agent type python main.py "your task" | grep "\[AUTO_CLOSE\]" ``` ### Check Screenshots ```bash theme={null} # List all screenshots ls -la screenshots/*/ # View latest screenshot eog screenshots/AUTO_CLOSE/screenshot_*.png ``` ## 🛠️ Troubleshooting Commands ### Check Dependencies ```bash theme={null} pip list | grep -E "anthropic|httpx|streamlit" ``` ### Test Display ```bash theme={null} echo $DISPLAY xdpyinfo ``` ### Verify API Connectivity ```bash theme={null} curl -X POST https://response.cx/api/agents/get-agent \ -H "Content-Type: application/json" \ -d '{"agent_id": "your-agent-id"}' ``` ## 💡 Usage Examples ### Example 1: Close Support Tickets ```bash theme={null} python main.py "auto-close all tickets marked as resolved in the last 24 hours" ``` ### Example 2: Social Media Monitoring ```bash theme={null} python main.py "social media hide inappropriate comments on our Facebook page" ``` ### Example 3: LinkedIn Outreach ```bash theme={null} python main.py "linkedin send connection requests to software engineers in San Francisco" ``` ### Example 4: Slack Customer Support ```bash theme={null} python main.py "slack respond to questions in #customer-support channel" ``` ### Example 5: Shopify Management ```bash theme={null} python main.py "shopify update inventory levels for out-of-stock products" ``` ## 🔑 Key Environment Variables ```bash theme={null} # Set display for GUI applications export DISPLAY=:1 # Optional: Set Anthropic API key export ANTHROPIC_API_KEY="your-key-here" # Optional: Set workspace path export WORKSPACE_PATH="/home/user/StateSet-computer-use-agent" ``` ## 📈 Performance Tips 1. **Run Multiple Agents**: Use "&" to run agents in background ```bash theme={null} python main.py "auto-close tickets" & python main.py "social media monitoring" & ``` 2. **Limit Token Usage**: Modify in code ```python theme={null} max_tokens=2048 # Instead of 4096 ``` 3. **Reduce Screenshot Frequency**: Modify in code ```python theme={null} only_n_most_recent_images=3 # Instead of 5 ``` ## 🛡️ Security Quick Checks ```bash theme={null} # Check API key isn't in git git grep "sk-ant-api" # Verify permissions ls -la ~/.ssh/ chmod 600 ~/.ssh/id_rsa # Check running processes ps aux | grep python ``` ## 📝 Notes * Always use `Ctrl+C` for graceful shutdown * Screenshots are saved in `screenshots/{AGENT_TYPE}/` * Logs show `[AGENT_TYPE]` prefix for easy filtering * Billing only occurs for completed tasks * Virtual display must be running (DISPLAY=:1) *** For detailed documentation, see [USERGUIDE.md](USERGUIDE.md) # StateSet Computer Use Agents - Architecture Overview Source: https://docs.stateset.com/guides/stateset-computer-use-agents-architecture Architecture overview for using StateSet Computer Use Agents # StateSet Computer Use Agents - Architecture Overview ## Overview AI-powered automation platform that leverages Claude Opus 4 to perform various tasks through computer interaction. The system uses multiple specialized agents that can control desktop environments, interact with web applications, and automate complex workflows. ## 🛠️ Key Features * **Multi-Agent Architecture** - Specialized agents for different tasks * **Computer Vision & Control** - Agents can see and interact with desktop environments * **API Integration** - Seamless integration with StateSet APIs * **Metered Billing** - Usage-based billing through Stripe * **Parallel Processing** - Multiple agents can run concurrently * **Graceful Shutdown** - Safe termination with Ctrl+C ## 📋 Requirements * Ubuntu Linux (kernel 5.15.0+) * Python 3.8+ * Virtual display (DISPLAY=:1) * Anthropic API key ## System Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ User Interface │ │ (Command Line / Shell Scripts) │ └─────────────────────┬───────────────────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────────────────┐ │ main.py │ │ ┌─────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │ │ Agent │ │ Agent │ │ Global State │ │ │ │ Selector │ │ Runner │ │ Management │ │ │ └─────────────┘ └──────────────┘ └────────────────────┘ │ └─────────────────────┬───────────────────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────────────────┐ │ agent/loop.py │ │ ┌─────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │ │ Sampling │ │ API │ │ System Prompt │ │ │ │ Loop │ │ Providers │ │ Initialization │ │ │ └─────────────┘ └──────────────┘ └────────────────────┘ │ └─────────────────────┬───────────────────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────────────────┐ │ Tool Collection │ │ ┌────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │ │ Computer │ │ Bash │ │ Edit │ │ │ │ Tool │ │ Tool │ │ Tool │ │ │ └────────────┘ └──────────────┘ └────────────────────┘ │ └─────────────────────┬───────────────────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────────────────┐ │ External Services │ │ ┌────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │ │ Anthropic │ │ StateSet │ │ Stripe │ │ │ │ API │ │ APIs │ │ Billing │ │ │ └────────────┘ └──────────────┘ └────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Core Components ### 1. Main Entry Point (`main.py`) The main module orchestrates the entire system: #### Key Functions: * **`main()`**: Entry point that initializes and runs agents * **`get_active_agents()`**: Determines which agents to activate based on instruction keywords * **`run_agent()`**: Executes a single agent with error handling and billing * **`continuous_loop()`**: Manages multiple agents running in parallel * **`analyze_task_completion()`**: Determines if a task was completed successfully #### Global State Management: ```python theme={null} class GlobalState: - running: bool # System-wide running flag - tasks: Set[asyncio.Task] # Active agent tasks - shutdown_event: Event # Coordination for graceful shutdown - _lock: threading.Lock # Thread-safe state management ``` ### 2. Agent Loop (`agent/loop.py`) The core agent execution engine: #### Key Components: * **`sampling_loop()`**: Main conversation loop with the AI model * **`initialize_system_prompt()`**: Fetches agent configuration from APIs * **API Provider Support**: Anthropic, Bedrock, Vertex * **Message Management**: Handles context window and prompt caching #### Message Flow: 1. Initialize system prompt with agent rules and attributes 2. Send messages to AI model 3. Process AI response and tool calls 4. Execute tools and collect results 5. Continue conversation until task completion ### 3. Tool System #### Tool Collection Architecture: ```python theme={null} ToolCollection ├── ComputerTool # GUI interaction │ ├── screenshot() │ ├── click() │ ├── type_text() │ └── scroll() ├── BashTool # System commands │ ├── run() │ └── execute_command() └── EditTool # File manipulation ├── create() └── modify() ``` #### Tool Versions: * **computer\_use\_20241022**: Legacy version * **computer\_use\_20250124**: Current version with enhanced capabilities ### 4. Agent Types Each agent is configured with: ```python theme={null} @dataclass class AgentConfig: org_id: str # Organization identifier agent_id: str # Unique agent identifier description: str # Agent purpose capabilities: List[str] # What the agent can do stripe_customer_id: str # Billing identifier ``` ### 5. Communication Flow #### 1. Instruction Processing: ``` User Input → Keyword Analysis → Agent Selection → Task Distribution ``` #### 2. Agent Execution: ``` Agent → API Configuration → System Prompt → AI Model → Tool Execution → Result ``` #### 3. Tool Execution: ``` AI Request → Tool Selection → Tool Execution → Result Collection → Response ``` ## Data Flow ### 1. Configuration Loading ``` StateSet APIs ├── /api/rules/get-agent-rules ├── /api/attributes/get-agent-attributes └── /api/agents/get-agent ↓ System Prompt Generation ↓ Agent Initialization ``` ### 2. Message Processing ``` User Message ↓ Messages Array (with history) ↓ Anthropic API (with tools) ↓ Response with Tool Calls ↓ Tool Execution ↓ Tool Results ↓ Continue or Complete ``` ### 3. Billing Flow ``` Task Completion Detection ↓ Token Usage Calculation ↓ Stripe Meter Event ↓ Usage Logged ``` ## Concurrency Model ### Asyncio-based Architecture: * **Main Event Loop**: Coordinates all async operations * **Agent Tasks**: Each agent runs as an independent asyncio task * **Parallel Execution**: Multiple agents can run simultaneously * **Graceful Shutdown**: Cancellation propagates to all tasks ### Task Management: ```python theme={null} # Parallel agent execution tasks = [] for agent in active_agents: task = asyncio.create_task(run_agent(...)) tasks.append(task) # Wait for all agents results = await asyncio.gather(*tasks, return_exceptions=True) ``` ## Error Handling Strategy ### 1. Retry Mechanism: * API calls: 3 retries with exponential backoff * Network failures: Automatic retry with delay * Tool failures: Error reported back to AI for recovery ### 2. Error Propagation: ``` Tool Error → ToolResult(error=...) → AI Model → Alternative Approach ``` ### 3. Graceful Degradation: * Missing API data: Use default system prompt * Tool failure: AI suggests alternative approach * API quota: Graceful shutdown with state preservation ## Security Architecture ### 1. API key Management: * Keys stored in code (should use environment variables) * Separate keys for different services * No key transmission to external services ### 2. Sandbox Execution: * Tools run in controlled environment * File system access limited by permissions * Network access controlled by system ### 3. Data Privacy: * Screenshots stored locally * No automatic data transmission * User data stays within system boundaries ## Performance Optimizations ### 1. Prompt Caching: * 3 most recent conversation turns cached * Reduces token usage for repeated contexts * Ephemeral cache for session optimization ### 2. Image Management: * Configurable image retention (default: 5 most recent) * Automatic cleanup of older images * Base64 encoding for efficient transmission ### 3. Parallel Processing: * Multiple agents run concurrently * Independent task execution * Shared resource optimization ## Extension Points ### 1. Adding New Agents: 1. Define AgentConfig in AGENT\_CONFIGS 2. Add keyword detection in get\_active\_agents() 3. Create specialized completion detection logic ### 2. Adding New Tools: 1. Implement tool class inheriting from base 2. Add to tool version groups 3. Update tool collection initialization ### 3. Custom API Providers: 1. Add to APIProvider enum 2. Implement client initialization 3. Update provider-specific logic ## Monitoring and Observability ### Logging Architecture: ``` Logger Configuration ├── Agent-specific logging with [AGENT_TYPE] prefix ├── Timestamp and log level ├── Structured error reporting └── API response logging ``` ### Metrics Collection: * Token usage per agent * Task completion rates * Error frequency and types * API response times ## Best Practices for Development 1. **Agent Development**: * Keep agents focused on specific domains * Implement clear completion detection * Handle errors gracefully 2. **Tool Development**: * Return structured ToolResult objects * Include helpful error messages * Support both success and failure paths 3. **System Integration**: * Use async/await consistently * Implement proper cleanup * Test shutdown scenarios 4. **Performance**: * Minimize API calls * Cache reusable data * Optimize image handling This architecture provides a scalable, maintainable foundation for computer use automation with AI agents. # StateSet Contracts Source: https://docs.stateset.com/guides/stateset-contracts Build and deploy smart contracts for autonomous commerce operations on the StateSet Network ## Introduction StateSet Contracts enable autonomous, self-executing business agreements on the StateSet Commerce Network. Built on CosmWasm, these smart contracts power everything from automated order fulfillment to complex multi-party trade finance arrangements. This guide covers contract development, deployment, and integration. ## What are StateSet Contracts? StateSet Contracts are WebAssembly-based smart contracts that: * **Execute Autonomously**: Run without manual intervention when conditions are met * **Ensure Trust**: Immutable and transparent execution on blockchain * **Enable Composability**: Contracts can interact with each other * **Support Complex Logic**: Handle multi-party agreements and conditional flows ## Prerequisites Before developing StateSet Contracts: * Rust programming knowledge (basic to intermediate) * Familiarity with smart contract concepts * StateSet CLI installed (`curl -L https://StateSet.network/install | sh`) * A StateSet Network account with testnet tokens ## Getting Started ```bash theme={null} # Install Rust curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Install cargo-generate for templates cargo install cargo-generate # Install StateSet CLI curl -L https://StateSet.network/install | sh # Verify installation StateSet version ``` ```bash theme={null} # Generate from template cargo generate --git https://github.com/StateSet/contract-template cd my-first-contract # Build the contract cargo wasm # Run tests cargo test ``` ```bash theme={null} # Store the contract code StateSet tx wasm store target/wasm32-unknown-unknown/release/my_contract.wasm \ --from wallet \ --chain-id StateSet-testnet \ --gas auto \ --gas-adjustment 1.3 # Instantiate the contract StateSet tx wasm instantiate CODE_ID '{"admin":"StateSet1..."}' \ --from wallet \ --label "my-contract" \ --chain-id StateSet-testnet ``` ## Core Contract Types ### 1. Order Management Contract Automate order lifecycle from placement to fulfillment: ```rust theme={null} use cosmwasm_std::{ entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, }; use cw2::set_contract_version; const CONTRACT_NAME: &str = "StateSet:order-manager"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Order { pub id: String, pub buyer: Addr, pub seller: Addr, pub items: Vec, pub total: Uint128, pub status: OrderStatus, pub payment_status: PaymentStatus, pub created_at: Timestamp, pub fulfilled_at: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub enum OrderStatus { Pending, Confirmed, Processing, Shipped, Delivered, Cancelled, Refunded, } #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { match msg { ExecuteMsg::CreateOrder { items, shipping } => { create_order(deps, env, info, items, shipping) } ExecuteMsg::ConfirmPayment { order_id } => { confirm_payment(deps, env, info, order_id) } ExecuteMsg::ShipOrder { order_id, tracking } => { ship_order(deps, env, info, order_id, tracking) } ExecuteMsg::ConfirmDelivery { order_id } => { confirm_delivery(deps, env, info, order_id) } ExecuteMsg::InitiateRefund { order_id, reason } => { initiate_refund(deps, env, info, order_id, reason) } } } fn create_order( deps: DepsMut, env: Env, info: MessageInfo, items: Vec, shipping: ShippingInfo, ) -> Result { // Validate items and calculate total let total = calculate_order_total(&items)?; // Generate unique order ID let order_id = generate_order_id(&env, &info.sender)?; // Create order object let order = Order { id: order_id.clone(), buyer: info.sender.clone(), seller: SELLER.load(deps.storage)?, items, total, status: OrderStatus::Pending, payment_status: PaymentStatus::Pending, created_at: env.block.time, fulfilled_at: None, }; // Store order ORDERS.save(deps.storage, &order_id, &order)?; // Emit event Ok(Response::new() .add_attribute("action", "create_order") .add_attribute("order_id", order_id) .add_attribute("buyer", info.sender) .add_attribute("total", total)) } ``` ### 2. Supply Chain Contract Track products through the supply chain with full transparency: ```rust theme={null} #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct SupplyChainEvent { pub product_id: String, pub event_type: EventType, pub location: String, pub handler: Addr, pub timestamp: Timestamp, pub temperature: Option, pub humidity: Option, pub notes: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub enum EventType { Manufactured, QualityChecked, Packaged, ShippedFromFactory, ArrivedAtWarehouse, ShippedToRetailer, ReceivedByRetailer, SoldToCustomer, } pub fn track_product( deps: DepsMut, env: Env, info: MessageInfo, product_id: String, event_type: EventType, location: String, metadata: Option, ) -> Result { // Verify handler authorization verify_handler_authorization(&deps, &info.sender, &event_type)?; // Create supply chain event let event = SupplyChainEvent { product_id: product_id.clone(), event_type: event_type.clone(), location, handler: info.sender.clone(), timestamp: env.block.time, temperature: metadata.as_ref().and_then(|m| m.temperature), humidity: metadata.as_ref().and_then(|m| m.humidity), notes: metadata.and_then(|m| m.notes), }; // Store event in chain let mut product_history = PRODUCT_HISTORY .load(deps.storage, &product_id) .unwrap_or_default(); product_history.push(event.clone()); PRODUCT_HISTORY.save(deps.storage, &product_id, &product_history)?; // Update product status update_product_status(deps.storage, &product_id, &event_type)?; Ok(Response::new() .add_attribute("action", "track_product") .add_attribute("product_id", product_id) .add_attribute("event_type", format!("{:?}", event_type)) .add_attribute("handler", info.sender)) } ``` ### 3. Trade Finance Contract Automate letters of credit and trade finance operations: ```rust theme={null} #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct LetterOfCredit { pub id: String, pub importer: Addr, pub exporter: Addr, pub issuing_bank: Addr, pub advising_bank: Addr, pub amount: Coin, pub documents_required: Vec, pub expiry_date: Timestamp, pub status: LCStatus, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub enum LCStatus { Issued, Confirmed, DocumentsSubmitted, DocumentsApproved, PaymentReleased, Completed, Expired, } pub fn submit_documents( deps: DepsMut, env: Env, info: MessageInfo, lc_id: String, documents: Vec, ) -> Result { let mut lc = LETTERS_OF_CREDIT.load(deps.storage, &lc_id)?; // Verify submitter is the exporter if info.sender != lc.exporter { return Err(ContractError::Unauthorized {}); } // Verify LC is in correct status if lc.status != LCStatus::Confirmed { return Err(ContractError::InvalidStatus {}); } // Validate all required documents are submitted validate_documents(&lc.documents_required, &documents)?; // Store documents SUBMITTED_DOCUMENTS.save(deps.storage, &lc_id, &documents)?; // Update LC status lc.status = LCStatus::DocumentsSubmitted; LETTERS_OF_CREDIT.save(deps.storage, &lc_id, &lc)?; Ok(Response::new() .add_attribute("action", "submit_documents") .add_attribute("lc_id", lc_id) .add_attribute("exporter", info.sender)) } ``` ### 4. Inventory Management Contract Real-time inventory tracking and automated reordering: ```rust theme={null} #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct InventoryItem { pub sku: String, pub name: String, pub quantity: u64, pub reserved: u64, pub reorder_point: u64, pub reorder_quantity: u64, pub supplier: Addr, pub last_restocked: Timestamp, } pub fn update_inventory( deps: DepsMut, env: Env, info: MessageInfo, updates: Vec, ) -> Result { let mut messages = vec![]; let mut attributes = vec![("action", "update_inventory")]; for update in updates { let mut item = INVENTORY.load(deps.storage, &update.sku)?; match update.operation { Operation::Add => { item.quantity = item.quantity.saturating_add(update.quantity); item.last_restocked = env.block.time; } Operation::Remove => { if item.quantity < update.quantity { return Err(ContractError::InsufficientInventory { sku: update.sku, available: item.quantity, requested: update.quantity, }); } item.quantity = item.quantity.saturating_sub(update.quantity); } Operation::Reserve => { let available = item.quantity.saturating_sub(item.reserved); if available < update.quantity { return Err(ContractError::InsufficientInventory { sku: update.sku, available, requested: update.quantity, }); } item.reserved = item.reserved.saturating_add(update.quantity); } } // Check if reorder needed if item.quantity <= item.reorder_point && item.quantity > 0 { let reorder_msg = create_reorder_message( &item.supplier, &update.sku, item.reorder_quantity, )?; messages.push(reorder_msg); attributes.push(("reorder_triggered", &update.sku)); } INVENTORY.save(deps.storage, &update.sku, &item)?; } Ok(Response::new() .add_messages(messages) .add_attributes(attributes)) } ``` ## Advanced Features ### Cross-Contract Communication Enable contracts to interact with each other: ```rust theme={null} // Call another contract pub fn execute_cross_contract_order( deps: DepsMut, env: Env, info: MessageInfo, order_details: OrderDetails, ) -> Result { // Prepare order for order management contract let order_msg = WasmMsg::Execute { contract_addr: ORDER_CONTRACT.load(deps.storage)?.to_string(), msg: to_binary(&OrderExecuteMsg::CreateOrder { items: order_details.items, shipping: order_details.shipping, })?, funds: info.funds, }; // Update inventory contract let inventory_msg = WasmMsg::Execute { contract_addr: INVENTORY_CONTRACT.load(deps.storage)?.to_string(), msg: to_binary(&InventoryExecuteMsg::ReserveItems { items: order_details.items.clone(), })?, funds: vec![], }; Ok(Response::new() .add_message(order_msg) .add_message(inventory_msg) .add_attribute("action", "cross_contract_order")) } ``` ### Event-Driven Architecture Use events to trigger automated workflows: ```rust theme={null} // Emit custom events pub fn emit_order_event( order_id: String, event_type: OrderEventType, ) -> Event { Event::new("order_event") .add_attribute("order_id", order_id) .add_attribute("event_type", format!("{:?}", event_type)) .add_attribute("timestamp", Timestamp::now().to_string()) } // Subscribe to events in another contract pub fn handle_order_event( deps: DepsMut, env: Env, event: OrderEvent, ) -> Result { match event.event_type { OrderEventType::PaymentConfirmed => { // Trigger fulfillment workflow start_fulfillment_process(deps, env, event.order_id)? } OrderEventType::Shipped => { // Update tracking system update_tracking_info(deps, env, event.order_id, event.tracking_info)? } OrderEventType::Delivered => { // Release payment to seller release_payment(deps, env, event.order_id)? } } Ok(Response::new()) } ``` ### Upgradeable Contracts Implement upgrade patterns for contract evolution: ```rust theme={null} // Migration entry point #[cfg_attr(not(feature = "library"), entry_point)] pub fn migrate( deps: DepsMut, _env: Env, msg: MigrateMsg, ) -> Result { let ver = cw2::get_contract_version(deps.storage)?; // Ensure we are migrating from an allowed version if ver.contract != CONTRACT_NAME { return Err(ContractError::CannotMigrate { previous_contract: ver.contract, }); } if ver.version > CONTRACT_VERSION { return Err(ContractError::CannotMigrateVersion { previous_version: ver.version, new_version: CONTRACT_VERSION.to_string(), }); } // Perform migration logic match msg { MigrateMsg::UpdateConfig { new_config } => { CONFIG.save(deps.storage, &new_config)?; } MigrateMsg::AddFeature { feature } => { enable_new_feature(deps.storage, feature)?; } } // Update contract version set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; Ok(Response::new() .add_attribute("action", "migrate") .add_attribute("version", CONTRACT_VERSION)) } ``` ## Testing Strategies ### Unit Testing ```rust theme={null} #[cfg(test)] mod tests { use super::*; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::{coins, from_binary}; #[test] fn test_create_order() { let mut deps = mock_dependencies(); let env = mock_env(); let info = mock_info("buyer", &coins(1000, "ustate")); // Initialize contract let msg = InstantiateMsg { admin: None }; let _res = instantiate(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); // Create order let create_msg = ExecuteMsg::CreateOrder { items: vec![ OrderItem { sku: "PROD-001".to_string(), quantity: 2, price: Uint128::new(100), } ], shipping: ShippingInfo { address: "123 Main St".to_string(), method: ShippingMethod::Standard, }, }; let res = execute(deps.as_mut(), env, info, create_msg).unwrap(); // Verify response assert_eq!(res.attributes.len(), 4); assert_eq!(res.attributes[0].key, "action"); assert_eq!(res.attributes[0].value, "create_order"); } } ``` ### Integration Testing ```rust theme={null} use StateSet_integration_tests::{Contract, ContractWrapper}; #[test] fn test_order_fulfillment_flow() { let mut app = mock_app(); // Deploy contracts let order_contract = deploy_order_contract(&mut app); let inventory_contract = deploy_inventory_contract(&mut app); let payment_contract = deploy_payment_contract(&mut app); // Test complete order flow let order_id = create_test_order(&mut app, &order_contract); confirm_payment(&mut app, &payment_contract, &order_id); verify_inventory_reserved(&mut app, &inventory_contract, &order_id); ship_order(&mut app, &order_contract, &order_id); confirm_delivery(&mut app, &order_contract, &order_id); verify_payment_released(&mut app, &payment_contract, &order_id); } ``` ## Deployment & Management ### Mainnet Deployment Checklist 1. **Security Audit**: Complete third-party audit 2. **Gas Optimization**: Profile and optimize gas usage 3. **Error Handling**: Comprehensive error messages 4. **Admin Controls**: Implement proper access control 5. **Upgrade Path**: Plan for future updates ### Monitoring & Analytics ```bash theme={null} # Query contract state StateSet query wasm contract-state smart CONTRACT_ADDR \ '{"get_order":{"order_id":"ORD-12345"}}' \ --chain-id StateSet-mainnet # Monitor contract events StateSet query txs --events 'wasm.contract_address=CONTRACT_ADDR' \ --chain-id StateSet-mainnet # Check contract metrics StateSet query wasm contract-state smart CONTRACT_ADDR \ '{"get_metrics":{}}' \ --chain-id StateSet-mainnet ``` ## Best Practices ### 1. Security First * Always validate inputs * Use proper access controls * Implement rate limiting * Handle all edge cases ### 2. Gas Efficiency * Minimize storage operations * Batch operations when possible * Use efficient data structures * Profile gas usage ### 3. Maintainability * Write comprehensive tests * Document all functions * Use clear naming conventions * Implement upgrade patterns ## Next Steps Explore ready-to-use contract templates Access tools, faucets, and documentation # StateSet Network Quickstart Source: https://docs.stateset.com/guides/stateset-network Getting started with the StateSet Network ### Prerequisites First we need to install Git, Node.js, Go and Rust: #### Install Git ```jsx bash theme={null} sudo apt-get update sudo apt-get install git ``` #### Install Node.js with NVM ```jsx bash theme={null} curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash ``` Currently, StateSet Network uses Go 1.19 to compile the code. Install GO Install Go 1.19 Verify the installation by typing go version in your terminal. ```bash jsx theme={null} go version go version go1.18.1 darwin/amd64 ``` ## Setup 1. Stop your node 2. Reset `StateSetd unsafe-reset-all` 3. Remove genesis `rm .StateSet/config/genesis.json` 4. Remove gentxs `rm -r .StateSet/config/gentx/` 5. Follow generate gentx as normal below **Genesis File** [Genesis File](/StateSet-1/genesis.json): ```bash theme={null} curl -s https://raw.githubusercontent.com/StateSet/networks/main/StateSet-1/genesis.json > ~/.StateSet/config/genesis.json ``` **StateSetd version** ```bash theme={null} $ StateSetd version latest-8e35a4d3 ``` ## Setup **Prerequisites:** Make sure to have [Golang >=1.19](https://golang.org/). #### Build from source You need to ensure your gopath configuration is correct. If the following **'make'** step does not work then you might have to add these lines to your .profile or .zshrc in the users home folder: ```bash theme={null} nano ~/.profile ``` ```bash theme={null} export GOROOT=/usr/local/go export GOPATH=$HOME/go export GO111MODULE=on export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin ``` Source update .profile ```bash theme={null} source .profile ``` ```bash theme={null} git clone https://github.com/StateSet/StateSet cd StateSet make build && make install ``` This will build and install `StateSetd` binary into `$GOBIN`. Note: When building from source, it is important to have your `$GOPATH` set correctly. When in doubt, the following should do: ```bash theme={null} mkdir ~/go export GOPATH=~/go ``` ### Minimum hardware requirements * 8-16GB RAM * 100GB of disk space * 2 cores ## Setup validator node Below are the instructions to generate & submit your genesis transaction ### Generate genesis transaction (gentx) 1. Initialize the StateSet directories and create the local genesis file with the correct chain-id: ```bash theme={null} StateSetd init --chain-id=StateSet-1 ``` 2. Create a local key pair: ```bash theme={null} StateSetd keys add ``` 3. Add your account to your local genesis file with a given amount and the key you just created. ```bash theme={null} StateSetd add-genesis-account $(StateSetd keys show -a) 10000000000ustate ``` 4. Create the gentx, use only `9000000000ustate`: ```bash theme={null} StateSetd gentx 9000000000ustate --chain-id=StateSet-1-testnet ``` If all goes well, you will see a message similar to the following: ```bash theme={null} Genesis transaction written to "/home/user/.StateSet/config/gentx/gentx-******.json" ``` ### Submit genesis transaction * Fork [the networks repo](https://github.com/StateSet/networks) into your Github account * Clone your repo using ```bash theme={null} git clone https://github.com//networks ``` * Copy the generated gentx json file to `/networks/StateSet-1/gentx/` ```bash theme={null} > cd testnets > cp ~/.StateSet/config/gentx/gentx*.json ./StateSet-1/gentx/ ``` * Commit and push to your repo * Create a PR onto [https://github.com/StateSet/networks](https://github.com/StateSet/networks) * Only PRs from individuals / groups with a history successfully running nodes will be accepted. This is to ensure the network successfully starts on time. # StateSet Orders Quickstart Source: https://docs.stateset.com/guides/stateset-network-orders Getting started with Orders on the StateSet Commerce Network ## Overview StateSet Commerce Network provides a Cosmos SDK based blockchain network for managing orders and payments for the StateSet Commerce platform. This guide will walk you through the steps to get started with creating Orders on the StateSet Commerce Network. ### The Order Module StateSet Commerce Network provides an API for creating Orders. The API is available at [https://api.StateSet.network](https://api.StateSet.network) An order is a customer’s completed request to purchase one or more products from a seller. An order is created when a customer completes the checkout process. The Order is braodcasted to the StateSet Commerce Network and the Order Module maintains the state of the Order. The States of an Order are: * `UNFULFILLED` * `FULFILLED` * `CANCELLED` To learn more about Modules, check out [this introduction](https://docs.cosmos.network/v0.46/building-modules/intro.html). ### Order Messages The `x/order` module implements an order state machine using the following messages: * MsgCreateOrder * MsgFulfillOrder * MsgCancelOrder ```Go theme={null} // Msg defines the order Msg service. service Msg { // MsgCreateOrder defines a method for creating an order rpc Create(MsgCreateOrder) returns (MsgCreateResponse); // MsgFulfillOrder defines a method for fulfilling an order rpc Fulfill(MsgFulfillOrder) returns (MsgFulfillResponse); // MsgCancelOrder defines a method for cancelling an order rpc Cancel(MsgCancelOrder) returns (MsgCancelResponse); } ``` Use these messages to make state changes on the network #### Create an Order Client ```javascript theme={null} import { Type, Field } from "protobufjs"; const MsgCreateOrder = new Type("MsgCreateOrder") .add(new Field("creator", 1, "string")) .add(new Field("seller", 2, "string")) .add(new Field("amount", 3, "string")) .add(new Field("fee", 4, "string")) .add(new Field("order_number", 5, "string")) .add(new Field("name", 6, "string")) .add(new Field("state", 7, "string")); const handleSubmitOrder = async () => { setStatus(prevStatus => ({ ...prevStatus, submitting: true })) const myRegistry = new Registry(defaultStargateTypes); myRegistry.register("/StateSet.core.order.MsgCreateOrder", MsgCreateOrder); const wallet = await DirectSecp256k1HdWallet.fromMnemonic( inputs.mnemonic, { prefix: "StateSet" }, ); const firstAccount = await wallet.getAccounts(); var creator_address; if (firstAccount) { creator_address = firstAccount[0].address; } const rpcEndpoint = "https://rpc.StateSet.zone"; const client = await SigningStateSetClient.connectWithSigner(rpcEndpoint, wallet, { registry: myRegistry, gasPrice: "0.00025state" }); if (client) { var _uuid = uuid(); // collateral const collateral = { amount: [ { denom: "ustate", amount: inputs.collateral, }, ], }; const message = { typeUrl: "/StateSet.core.order.MsgCreateOrder", value: { buyer: creator_address, seller: inputs.seller, amount: inputs.amount, fee: inputs.fee, order_number: _uuid, name: inputs.name, state: "UNFULFILLED" }, }; // Fee const fee = { amount: [ { denom: "state", amount: "0", }, ], gas: "10000", }; const result = await client.signAndBroadcast(creator_address, [message], "auto", 'creating an order from the StateSet zone'); if (result) { setStatus(prevStatus => ({ ...prevStatus, submitted: true, })) setOrderID(_uuid); } } } ``` #### Query an Order Create a new page called `index.js` in the `pages/order/[id]` directory. ```javascript theme={null} const Order = () => { const router = useRouter(); const id = router.query; var id_ = id.id; const [orders, setOrders] = useState([]); useEffect(() => { async function getOrders() { const res = await fetch(`https://rest-api.StateSet.zone/StateSet/core/order/order/${id_}`, { method: 'GET' }); const order_data = await res.json(); setOrdets(order_data.Order); }; getOrders(); }, []); return (); } export default Order ``` #### Fulfill an Order ```javascript theme={null} import { Type, Field } from "protobufjs"; const MsgFulfillOrder = new Type("MsgFulfillOrder") .add(new Field("creator", 1, "string")) .add(new Field("state", 2, "string")); const handleFulfillOrder = async () => { setStatus(prevStatus => ({ ...prevStatus, submitting: true })) const myRegistry = new Registry(defaultStargateTypes); myRegistry.register("/StateSet.core.order.MsgFulfillOrder", MsgFulfillOrder); const wallet = await DirectSecp256k1HdWallet.fromMnemonic( inputs.mnemonic, { prefix: "StateSet" }, ); const firstAccount = await wallet.getAccounts(); var creator_address; if (firstAccount) { creator_address = firstAccount[0].address; } const rpcEndpoint = "https://rpc.StateSet.zone"; const client = await SigningStateSetClient.connectWithSigner(rpcEndpoint, wallet, { registry: myRegistry, gasPrice: "0.00025state" }); if (client) { // collateral const collateral = { amount: [ { denom: "ustate", amount: inputs.collateral, }, ], }; const message = { typeUrl: "/StateSet.core.order.MsgFulfillOrder", value: { creator: creator_address, state: "FULFILLED" }, } } } ``` ### Submitting an Order using the CLI ```bash theme={null} StateSetd tx order create-order \ --from \ --seller \ --amount \ --fee \ --order-number \ --name \ --state \ --chain-id StateSet-1 \ --node tcp://rpc.StateSet.zone:26657 \ --gas-prices 0.00025state \ --gas auto \ --broadcast-mode block \ --yes ``` ### Querying an Order using the CLI ```bash theme={null} StateSetd query order order \ --chain-id StateSet-1 \ --node tcp://rpc.StateSet.zone:26657 ``` ### Fulfilling an Order using the CLI ```bash theme={null} StateSetd tx order fulfill-order \ --from \ --state \ --chain-id StateSet-1 \ --node tcp://rpc.StateSet.zone:26657 \ --gas-prices 0.00025state \ --gas auto \ --broadcast-mode block \ --yes ``` ## Additional Information (Coming Soon) * [StateSet Commerce Network](https://StateSet.network) * [StateSet Commerce API](https://api.StateSet.network) * [StateSet Zone](https://app.StateSet.zone) # StateSet Sandbox Source: https://docs.stateset.com/guides/stateset-sandbox Self-hosted Kubernetes sandbox for running AI agents with full code execution in isolated containers StateSet Sandbox is a Kubernetes-based sandbox infrastructure for running code execution workloads inside isolated pods. It exposes REST and WebSocket APIs for creating sandboxes, streaming command output, and reading or writing files inside each sandbox workspace. ## Key capabilities * Isolated execution per sandbox pod with resource limits * REST and WebSocket APIs for command execution and streaming output * File read and write APIs for workspace workflows * Prebuilt runtime with Node.js, Python, Go, Rust, and common CLI tooling * Automatic cleanup with per-sandbox timeouts * Optional warm pool support for faster startup ## Architecture overview ```mermaid theme={null} graph LR Client[Your app or agent runner] -->|HTTP or WebSocket| Controller[Sandbox controller] Controller -->|Kubernetes API| Pod[Sandbox pod] Pod --> Workspace[/workspace/] ``` ## Hosted API quickstart 1. Register and receive an API key. 2. Create a sandbox with a timeout. 3. Execute commands inside the sandbox. ```bash theme={null} curl -X POST https://api.sandbox.StateSet.app/api/v1/register \ -H "Content-Type: application/json" \ -d '{"first_name":"Ada","last_name":"Lovelace","organization_name":"Example Co","email":"ada@example.com"}' ``` ```bash theme={null} curl -X POST https://api.sandbox.StateSet.app/api/v1/sandbox/create \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"timeout_seconds": 300}' ``` ```bash theme={null} curl -X POST https://api.sandbox.StateSet.app/api/v1/sandbox/SANDBOX_ID/execute \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command":"python3 -c \"print(Hello World!)\""}' ``` ## TypeScript SDK example ```ts theme={null} import { StateSetSandbox } from "@StateSet/sandbox-sdk"; const sandbox = new StateSetSandbox({ baseUrl: "https://api.sandbox.StateSet.app", authToken: "sk-sandbox-your-api-key", timeout: 120000, }); const instance = await sandbox.create({ cpus: "2", memory: "2Gi", timeout_seconds: 300, }); await sandbox.writeFile( instance.sandbox_id, "/workspace/hello.js", 'logger.info("Hello from sandbox!");' ); const result = await sandbox.execute(instance.sandbox_id, { command: "node /workspace/hello.js", }); logger.info(result.stdout); await sandbox.stop(instance.sandbox_id); ``` ## Self-hosted deployment At a high level, deployment includes: 1. Build and push the sandbox and controller images. 2. Apply the Kubernetes manifests in `k8s/`. 3. Configure secrets for JWT signing and provider keys. 4. Deploy the controller and verify pod creation. ```bash theme={null} kubectl apply -f k8s/namespace.yaml kubectl apply -f k8s/rbac.yaml kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/deployment.yaml ``` ## API summary | Method | Path | Description | | ------ | ------------------------------------ | -------------------------- | | POST | `/api/v1/sandbox/create` | Create a new sandbox | | GET | `/api/v1/sandbox/:id` | Get sandbox details | | GET | `/api/v1/sandbox/:id/status` | Get sandbox status | | GET | `/api/v1/sandboxes` | List sandboxes | | POST | `/api/v1/sandbox/:id/files` | Write files to a sandbox | | GET | `/api/v1/sandbox/:id/files?path=...` | Read a file from a sandbox | | POST | `/api/v1/sandbox/:id/execute` | Execute a command | | POST | `/api/v1/sandbox/:id/stop` | Stop and delete a sandbox | | DELETE | `/api/v1/sandbox/:id` | Delete a sandbox | ## Configuration highlights | Variable | Default | Description | | ----------------------- | --------- | -------------------------------- | | `SANDBOX_IMAGE` | - | Base image for sandbox pods | | `DEFAULT_CPUS` | `2` | Default CPU limit | | `DEFAULT_MEMORY` | `2Gi` | Default memory limit | | `DEFAULT_TIMEOUT` | `600` | Default timeout in seconds | | `MAX_SANDBOXES_PER_ORG` | `5` | Max concurrent sandboxes per org | | `SANDBOX_EXEC_BACKEND` | `kubectl` | Command exec backend | | `WARM_POOL_ENABLED` | `false` | Enable warm pool pods | ## Security and isolation * Sandboxes run as non-root with dropped Linux capabilities. * Seccomp profiles and resource limits are enforced at the pod level. * Network policies restrict egress to HTTPS and DNS. # Supplier Quickstart Source: https://docs.stateset.com/guides/supplier-quickstart Learn how to manage suppliers and purchase orders with the StateSet API # Introduction The StateSet API provides a comprehensive suite of tools to manage your supplier relationships, including creating and updating suppliers, tracking performance metrics, managing purchase orders (POs), and handling advanced shipment notices (ASNs). This quickstart guide will walk you through key operations to integrate supplier management into your application. ## Prerequisites Before you begin, make sure you have: 1. A StateSet account with API access 2. Your API key (found in your dashboard) 3. Node.js 18+ installed (for SDK usage) ## Installation Install the StateSet Node SDK: ```bash npm theme={null} npm install StateSet-node ``` ```bash yarn theme={null} yarn add StateSet-node ``` ```bash pnpm theme={null} pnpm add StateSet-node ``` ## Configuration Set up your environment variables: ```bash theme={null} # .env file STATESET_API_KEY=your_api_key_here NODE_ENV=production ``` Initialize the StateSet client with proper error handling: ```javascript theme={null} import { StateSetClient } from 'StateSet-node'; class SupplierService { constructor() { this.client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox', timeout: 30000, retries: 3 }); this.logger = this.setupLogger(); } setupLogger() { // Use your preferred logging service return { info: (message, data) => { if (process.env.NODE_ENV !== 'production') { console.info(`[INFO] ${message}`, data); } // Send to logging service }, error: (message, error) => { logger.error(`[ERROR] ${message}`, error); // Send to error tracking service }, debug: (message, data) => { if (process.env.NODE_ENV === 'development') { console.debug(`[DEBUG] ${message}`, data); } } }; } async checkConnection() { try { const health = await this.client.health.check(); this.logger.info('StateSet API connection established', { status: health.status }); return health; } catch (error) { this.logger.error('Failed to connect to StateSet API', error); throw new Error('Unable to establish API connection'); } } } const supplierService = new SupplierService(); ``` ## Supplier Management ### Creating a Supplier ```javascript theme={null} async function createSupplier(supplierData) { try { const supplier = await supplierService.client.suppliers.create({ name: supplierData.name, contact_email: supplierData.contact_email, contact_phone: supplierData.contact_phone, address: supplierData.address, payment_terms: supplierData.payment_terms || 'NET30', lead_time_days: supplierData.lead_time_days || 7, minimum_order_value: supplierData.minimum_order_value || 0, preferred: supplierData.preferred || false, active: true, metadata: { category: supplierData.category, rating: supplierData.rating } }); supplierService.logger.info('Supplier created', { supplierId: supplier.id, name: supplier.name }); return { success: true, supplier }; } catch (error) { supplierService.logger.error('Failed to create supplier', error); throw error; } } // Example usage const newSupplier = await createSupplier({ name: 'Acme Manufacturing Co.', contact_email: 'orders@acmemfg.com', contact_phone: '+1-555-0123', address: { street: '123 Industrial Way', city: 'Detroit', state: 'MI', postal_code: '48201', country: 'US' }, payment_terms: 'NET30', lead_time_days: 14, minimum_order_value: 500, category: 'electronics', rating: 4.5 }); ``` ### Updating Supplier Performance Metrics ```javascript theme={null} async function updateSupplierMetrics(supplierId, metrics) { try { const updated = await supplierService.client.suppliers.update(supplierId, { performance_metrics: { on_time_delivery_rate: metrics.on_time_delivery_rate, quality_rating: metrics.quality_rating, response_time_hours: metrics.response_time_hours, defect_rate: metrics.defect_rate, last_evaluated: new Date().toISOString() } }); supplierService.logger.info('Supplier metrics updated', { supplierId, metrics: updated.performance_metrics }); return updated; } catch (error) { supplierService.logger.error('Failed to update supplier metrics', error); throw error; } } ``` ### Finding Alternative Suppliers ```javascript theme={null} async function findAlternativeSuppliers(criteria) { try { const alternatives = await supplierService.client.suppliers.list({ filter: { active: true, 'metadata.category': criteria.category, 'performance_metrics.quality_rating': { $gte: criteria.min_quality_rating || 3.5 }, 'performance_metrics.on_time_delivery_rate': { $gte: criteria.min_delivery_rate || 0.85 } }, sort: '-performance_metrics.quality_rating', limit: criteria.limit || 5 }); supplierService.logger.info('Alternative suppliers found', { partNumber: criteria.part_number, count: alternatives.data.length }); // Calculate scores for each supplier const scoredSuppliers = alternatives.data.map(supplier => ({ ...supplier, score: calculateSupplierScore(supplier, criteria) })); return scoredSuppliers.sort((a, b) => b.score - a.score); } catch (error) { supplierService.logger.error('Failed to find alternative suppliers', error); throw error; } } function calculateSupplierScore(supplier, criteria) { const weights = { quality: 0.3, delivery: 0.3, price: 0.2, leadTime: 0.2 }; const scores = { quality: (supplier.performance_metrics?.quality_rating || 0) / 5, delivery: supplier.performance_metrics?.on_time_delivery_rate || 0, price: 1 - (supplier.metadata?.price_index || 1), // Lower price = higher score leadTime: Math.max(0, 1 - (supplier.lead_time_days / 30)) }; return Object.keys(weights).reduce((total, key) => total + (weights[key] * scores[key]), 0 ); } ``` ## Purchase Order Management ### Creating a Purchase Order ```javascript theme={null} async function createPurchaseOrder(poData) { try { // Validate supplier exists and is active const supplier = await supplierService.client.suppliers.get(poData.supplier_id); if (!supplier.active) { throw new Error('Cannot create PO for inactive supplier'); } // Calculate totals const subtotal = poData.line_items.reduce((sum, item) => sum + (item.quantity * item.unit_price), 0 ); const tax = subtotal * (poData.tax_rate || 0); const total = subtotal + tax + (poData.shipping_cost || 0); const purchaseOrder = await supplierService.client.purchaseOrders.create({ supplier_id: poData.supplier_id, po_number: generatePONumber(), order_date: new Date().toISOString(), expected_delivery_date: calculateExpectedDelivery(supplier.lead_time_days), line_items: poData.line_items.map(item => ({ ...item, subtotal: item.quantity * item.unit_price })), subtotal, tax, shipping_cost: poData.shipping_cost || 0, total, status: 'pending', payment_terms: supplier.payment_terms, shipping_address: poData.shipping_address, notes: poData.notes }); supplierService.logger.info('Purchase order created', { poId: purchaseOrder.id, poNumber: purchaseOrder.po_number, supplierId: purchaseOrder.supplier_id, total: purchaseOrder.total }); // Send notification to supplier await notifySupplier(purchaseOrder); return purchaseOrder; } catch (error) { supplierService.logger.error('Failed to create purchase order', error); throw error; } } function generatePONumber() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substr(2, 5); return `PO-${timestamp}-${random}`.toUpperCase(); } function calculateExpectedDelivery(leadTimeDays) { const date = new Date(); date.setDate(date.getDate() + leadTimeDays); return date.toISOString(); } ``` ### Tracking Purchase Order Status ```javascript theme={null} async function getPurchaseOrderStatus(poId) { try { const po = await supplierService.client.purchaseOrders.get(poId); const statusInfo = { current_status: po.status, status_history: po.status_history || [], expected_delivery: po.expected_delivery_date, days_until_delivery: calculateDaysUntilDelivery(po.expected_delivery_date), is_overdue: isOrderOverdue(po), completion_percentage: calculateCompletionPercentage(po) }; supplierService.logger.info('Purchase order status retrieved', { poId, status: statusInfo.current_status }); return statusInfo; } catch (error) { supplierService.logger.error('Failed to get purchase order status', error); throw error; } } function calculateDaysUntilDelivery(expectedDate) { const now = new Date(); const delivery = new Date(expectedDate); const diffTime = delivery - now; return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } function isOrderOverdue(po) { return po.status !== 'delivered' && new Date(po.expected_delivery_date) < new Date(); } function calculateCompletionPercentage(po) { const statusProgress = { 'pending': 0, 'confirmed': 20, 'in_production': 40, 'shipped': 80, 'delivered': 100 }; return statusProgress[po.status] || 0; } ``` ## Advanced Shipment Notice (ASN) Management ### Creating an ASN ```javascript theme={null} async function createASN(asnData) { try { // Validate PO exists and is in correct status const po = await supplierService.client.purchaseOrders.get(asnData.po_id); if (!['confirmed', 'in_production'].includes(po.status)) { throw new Error(`Cannot create ASN for PO in ${po.status} status`); } const asn = await supplierService.client.asns.create({ po_id: asnData.po_id, po_number: po.po_number, supplier_id: po.supplier_id, asn_number: generateASNNumber(), ship_date: asnData.ship_date || new Date().toISOString(), expected_arrival_date: asnData.expected_arrival_date, carrier: asnData.carrier, tracking_number: asnData.tracking_number, line_items: asnData.line_items.map(item => ({ po_line_item_id: item.po_line_item_id, part_number: item.part_number, description: item.description, quantity_shipped: item.quantity_shipped, unit_of_measure: item.unit_of_measure })), packing_list_number: asnData.packing_list_number, total_weight: asnData.total_weight, total_packages: asnData.total_packages, status: 'in_transit', notes: asnData.notes }); // Update PO status await supplierService.client.purchaseOrders.update(po.id, { status: 'shipped', tracking_info: { carrier: asn.carrier, tracking_number: asn.tracking_number, ship_date: asn.ship_date } }); supplierService.logger.info('ASN created', { asnId: asn.id, asnNumber: asn.asn_number, poNumber: asn.po_number, trackingNumber: asn.tracking_number }); return asn; } catch (error) { supplierService.logger.error('Failed to create ASN', error); throw error; } } function generateASNNumber() { const date = new Date(); const dateStr = date.toISOString().split('T')[0].replace(/-/g, ''); const random = Math.random().toString(36).substr(2, 4); return `ASN-${dateStr}-${random}`.toUpperCase(); } ``` ### Receiving and Reconciling ASN ```javascript theme={null} async function receiveASN(asnId, receivingData) { try { const asn = await supplierService.client.asns.get(asnId); // Record receiving details const receiving = await supplierService.client.asns.update(asnId, { status: 'received', received_date: new Date().toISOString(), received_by: receivingData.received_by, receiving_notes: receivingData.notes, line_items: asn.line_items.map(item => { const receivedItem = receivingData.items.find( r => r.po_line_item_id === item.po_line_item_id ); return { ...item, quantity_received: receivedItem?.quantity_received || 0, condition: receivedItem?.condition || 'good', discrepancy_notes: receivedItem?.discrepancy_notes }; }) }); // Reconcile with PO const reconciliationResult = await reconcileASNWithPO(asn.id, asn.po_id); supplierService.logger.info('ASN received and reconciled', { asnId, poId: asn.po_id, hasDiscrepancies: reconciliationResult.has_discrepancies }); return { asn: receiving, reconciliation: reconciliationResult }; } catch (error) { supplierService.logger.error('Failed to receive ASN', error); throw error; } } async function reconcileASNWithPO(asnId, poId) { try { const [asn, po] = await Promise.all([ supplierService.client.asns.get(asnId), supplierService.client.purchaseOrders.get(poId) ]); const discrepancies = []; // Check each line item asn.line_items.forEach(asnItem => { const poItem = po.line_items.find( p => p.id === asnItem.po_line_item_id ); if (!poItem) { discrepancies.push({ type: 'item_not_in_po', part_number: asnItem.part_number, message: 'Item in ASN not found in PO' }); return; } const quantityDiff = asnItem.quantity_received - poItem.quantity; if (quantityDiff !== 0) { discrepancies.push({ type: 'quantity_mismatch', part_number: asnItem.part_number, po_quantity: poItem.quantity, received_quantity: asnItem.quantity_received, difference: quantityDiff }); } if (asnItem.condition !== 'good') { discrepancies.push({ type: 'condition_issue', part_number: asnItem.part_number, condition: asnItem.condition, notes: asnItem.discrepancy_notes }); } }); const result = { asn_id: asnId, po_id: poId, has_discrepancies: discrepancies.length > 0, discrepancies, reconciled_at: new Date().toISOString() }; // Update PO status based on reconciliation const newStatus = discrepancies.length > 0 ? 'received_with_issues' : 'received'; await supplierService.client.purchaseOrders.update(poId, { status: newStatus, reconciliation_result: result }); return result; } catch (error) { supplierService.logger.error('Failed to reconcile ASN with PO', error); throw error; } } ``` ## Analytics and Reporting ### Safety Stock Status ```javascript theme={null} async function getSafetyStockStatus() { try { const inventory = await supplierService.client.inventory.list({ filter: { quantity: { $lte: 'reorder_point' } }, include: ['supplier'] }); const criticalItems = inventory.data.map(item => ({ part_number: item.part_number, description: item.description, current_quantity: item.quantity, reorder_point: item.reorder_point, safety_stock: item.safety_stock, days_of_supply: calculateDaysOfSupply(item), supplier: item.supplier, urgency: calculateUrgency(item) })); supplierService.logger.info('Safety stock status retrieved', { criticalItemsCount: criticalItems.length }); return criticalItems.sort((a, b) => b.urgency - a.urgency); } catch (error) { supplierService.logger.error('Failed to get safety stock status', error); throw error; } } function calculateDaysOfSupply(item) { if (!item.average_daily_usage || item.average_daily_usage === 0) return Infinity; return Math.floor(item.quantity / item.average_daily_usage); } function calculateUrgency(item) { const stockPercentage = item.quantity / item.reorder_point; const daysOfSupply = calculateDaysOfSupply(item); if (stockPercentage <= 0.25 || daysOfSupply <= 3) return 5; // Critical if (stockPercentage <= 0.5 || daysOfSupply <= 7) return 4; // High if (stockPercentage <= 0.75 || daysOfSupply <= 14) return 3; // Medium if (stockPercentage <= 1 || daysOfSupply <= 21) return 2; // Low return 1; // Normal } ``` ### Supply Chain KPIs ```javascript theme={null} async function getSupplyChainKPIs(params = {}) { try { const timeframe = params.timeframe || '30d'; const startDate = calculateStartDate(timeframe); const [suppliers, purchaseOrders, asns] = await Promise.all([ supplierService.client.suppliers.list({ filter: { active: true } }), supplierService.client.purchaseOrders.list({ filter: { created_at: { $gte: startDate } } }), supplierService.client.asns.list({ filter: { created_at: { $gte: startDate } } }) ]); const kpis = { timeframe, supplier_performance: calculateSupplierPerformanceKPIs(suppliers.data), order_metrics: calculateOrderMetrics(purchaseOrders.data), delivery_metrics: calculateDeliveryMetrics(asns.data), cost_metrics: calculateCostMetrics(purchaseOrders.data), generated_at: new Date().toISOString() }; supplierService.logger.info('Supply chain KPIs calculated', { timeframe, supplierCount: suppliers.data.length }); return kpis; } catch (error) { supplierService.logger.error('Failed to calculate supply chain KPIs', error); throw error; } } function calculateSupplierPerformanceKPIs(suppliers) { const activeSuppliers = suppliers.filter(s => s.active); const avgMetrics = activeSuppliers.reduce((acc, supplier) => { const metrics = supplier.performance_metrics || {}; return { quality_rating: acc.quality_rating + (metrics.quality_rating || 0), on_time_delivery: acc.on_time_delivery + (metrics.on_time_delivery_rate || 0), defect_rate: acc.defect_rate + (metrics.defect_rate || 0) }; }, { quality_rating: 0, on_time_delivery: 0, defect_rate: 0 }); const count = activeSuppliers.length || 1; return { average_quality_rating: (avgMetrics.quality_rating / count).toFixed(2), average_on_time_delivery: (avgMetrics.on_time_delivery / count * 100).toFixed(1) + '%', average_defect_rate: (avgMetrics.defect_rate / count * 100).toFixed(2) + '%', total_active_suppliers: activeSuppliers.length }; } ``` ## Error Handling and Monitoring Implement comprehensive error handling and monitoring: ```javascript theme={null} class SupplierAPIError extends Error { constructor(message, code, details) { super(message); this.name = 'SupplierAPIError'; this.code = code; this.details = details; this.timestamp = new Date().toISOString(); } } async function withErrorHandling(operation, context) { const startTime = Date.now(); try { const result = await operation(); // Track successful operations supplierService.logger.info('Operation completed', { context, duration: Date.now() - startTime }); return result; } catch (error) { // Categorize and handle different error types if (error.response?.status === 429) { throw new SupplierAPIError( 'Rate limit exceeded', 'RATE_LIMIT', { retryAfter: error.response.headers['retry-after'] } ); } if (error.response?.status === 404) { throw new SupplierAPIError( 'Resource not found', 'NOT_FOUND', { resource: context } ); } // Log and re-throw supplierService.logger.error('Operation failed', { context, error: error.message, duration: Date.now() - startTime }); throw error; } } // Usage example const supplier = await withErrorHandling( () => createSupplier(supplierData), 'create_supplier' ); ``` ## Best Practices 1. **Always use environment variables** for sensitive configuration 2. **Implement proper logging** instead of console.log statements 3. **Handle errors gracefully** with meaningful error messages 4. **Use transactions** for operations that modify multiple resources 5. **Implement retry logic** for transient failures 6. **Monitor API usage** to stay within rate limits 7. **Cache frequently accessed data** to improve performance 8. **Validate data** before sending to the API 9. **Use webhook events** for real-time updates instead of polling 10. **Document your integration** for future maintenance ## Next Steps Now that you understand the basics of supplier management with StateSet: 1. **Explore advanced features** like automated reordering and demand forecasting 2. **Set up webhooks** to receive real-time updates on PO and ASN status changes 3. **Integrate with your ERP** for seamless data synchronization 4. **Build custom dashboards** using the analytics data 5. **Implement approval workflows** for purchase orders For more information, check out: * [API Reference Documentation](/api-reference) * [Webhook Events Guide](/guides/webhooks) * [Best Practices Guide](/guides/best-practices) If you need help, contact [support@StateSet.com](mailto:support@StateSet.com) or join our [Discord community](https://discord.gg/VfcaqgZywq). ``` ``` # Synthetic Data Studio Source: https://docs.stateset.com/guides/synthetic-data Generate high-quality synthetic data for training, testing, and improving your StateSet agents ## Introduction StateSet Synthetic Data Studio is a powerful platform for generating realistic, diverse synthetic data at scale. Whether you're training AI agents, testing systems, or building demos, our synthetic data engine creates production-quality data that maintains statistical properties while ensuring privacy compliance. ## Why Synthetic Data? Generate data without exposing real customer information Create millions of records on-demand for any use case Test edge cases and scenarios rare in production data ## Getting Started ### Prerequisites 1. StateSet account with Synthetic Data Studio access 2. API key from your dashboard 3. Node.js 18+, Python 3.8+, or any HTTP client ### Base Configuration ```bash Environment theme={null} # Development export SYNTHETIC_DATA_API="https://yourapp.com:8000" # Production export SYNTHETIC_DATA_API="https://studio.StateSet.app" export STATESET_API_KEY="your_api_key_here" ``` ```javascript JavaScript theme={null} const baseURL = process.env.SYNTHETIC_DATA_API || 'https://yourapp.com:8000'; const apiKey = process.env.STATESET_API_KEY || ''; const SyntheticDataClient = { baseURL, headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, async post(endpoint, data) { const response = await fetch(`${this.baseURL}${endpoint}`, { method: 'POST', headers: this.headers, body: JSON.stringify(data) }); return response.json(); } }; ``` ```python Python theme={null} import os import requests class SyntheticDataClient: def __init__(self): self.base_url = os.getenv('SYNTHETIC_DATA_API', 'https://yourapp.com:8000') self.headers = { 'Authorization': f"Bearer {os.getenv('STATESET_API_KEY')}" } ``` ## Core Features ### 1. E-commerce Customer Generation Generate realistic customer profiles with comprehensive demographic, behavioral, and predictive data. #### Quick Start ```javascript JavaScript theme={null} // Generate 1000 diverse customer profiles const generateCustomers = async () => { const formData = new FormData(); formData.append('project_id', 'my-ecommerce-project'); formData.append('num_customers', '1000'); formData.append('output_format', 'json'); const response = await fetch(`${SyntheticDataClient.baseURL}/synthdata/generate-ecommerce-customers`, { method: 'POST', headers: { 'Authorization': SyntheticDataClient.headers.Authorization }, body: formData }); const job = await response.json(); logger.info(`Job started: ${job.job_id}`); // Monitor progress via WebSocket const wsURL = SyntheticDataClient.baseURL.replace(/^http/, 'ws').replace(/^https/, 'wss'); const ws = new WebSocket(`${wsURL}/ws/jobs/${job.job_id}`); ws.onmessage = (event) => { const data = JSON.parse(event.data); logger.info(`Progress: ${data.progress}% - ${data.message}`); }; return job; }; ``` ```python Python theme={null} import aiohttp import asyncio import websockets import json async def generate_customers(): url = f"{SyntheticDataClient.base_url}/synthdata/generate-ecommerce-customers" form_data = aiohttp.FormData() form_data.add_field('project_id', 'my-ecommerce-project') form_data.add_field('num_customers', '1000') form_data.add_field('output_format', 'json') async with aiohttp.ClientSession() as session: async with session.post(url, headers=SyntheticDataClient.headers, data=form_data) as response: job = await response.json() print(f"Job started: {job['job_id']}") # Monitor progress via WebSocket ws_url = SyntheticDataClient.base_url.replace('http', 'ws').replace('https', 'wss') + f"/ws/jobs/{job['job_id']}" async with websockets.connect(ws_url) as ws: async for message in ws: data = json.loads(message) print(f"Progress: {data['progress']}% - {data['message']}") return job # Run the async function asyncio.run(generate_customers()) ``` #### Customer Profile Schema Each generated customer includes: ```typescript theme={null} { customer_id: string, personal_info: { first_name: string, last_name: string, gender: "male" | "female" | "other", date_of_birth: string, username: string, avatar_url: string } } ``` ```typescript theme={null} { demographics: { customer_segment: "budget_conscious" | "value_seeker" | "premium_buyer" | "luxury_enthusiast", income_range: { min: number, max: number }, occupation: string, education_level: string, interests: string[], household_size: number } } ``` ```typescript theme={null} { behavioral_data: { preferred_device: string, avg_session_duration: number, preferred_shopping_time: string, marketing_opt_in: { email: boolean, sms: boolean, push_notifications: boolean } } } ``` ```typescript theme={null} { predictive_scores: { lifetime_value_prediction: number, churn_probability: number, next_purchase_probability: number, fraud_risk_score: number, recommendation_responsiveness: number } } ``` #### Advanced Customer Generation ```javascript JavaScript theme={null} // Generate segment-specific customers with custom parameters async function generateSegmentedCustomers() { const segments = [ { segment: 'premium_buyer', count: 200, config: { min_income: 100000, min_order_value: 150, interests: ['luxury', 'fashion', 'technology'] } }, { segment: 'value_seeker', count: 500, config: { price_sensitivity: 'high', promotion_responsiveness: 0.9 } } ]; const jobs = []; for (const segment of segments) { const formData = new FormData(); formData.append('project_id', 'segmented-customers'); formData.append('num_customers', segment.count.toString()); formData.append('segment_filter', segment.segment); formData.append('custom_config', JSON.stringify(segment.config)); const response = await fetch(`${SyntheticDataClient.baseURL}/synthdata/generate-ecommerce-customers`, { method: 'POST', headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}` }, body: formData }); jobs.push(await response.json()); } return jobs; } ``` ```python Python theme={null} import aiohttp import asyncio import json async def generate_segmented_customers(): segments = [ { 'segment': 'premium_buyer', 'count': 200, 'config': { 'min_income': 100000, 'min_order_value': 150, 'interests': ['luxury', 'fashion', 'technology'] } }, { 'segment': 'value_seeker', 'count': 500, 'config': { 'price_sensitivity': 'high', 'promotion_responsiveness': 0.9 } } ] jobs = [] async with aiohttp.ClientSession() as session: for segment in segments: url = f"{SyntheticDataClient.base_url}/synthdata/generate-ecommerce-customers" form_data = aiohttp.FormData() form_data.add_field('project_id', 'segmented-customers') form_data.add_field('num_customers', str(segment['count'])) form_data.add_field('segment_filter', segment['segment']) form_data.add_field('custom_config', json.dumps(segment['config'])) async with session.post(url, headers=SyntheticDataClient.headers, data=form_data) as response: job = await response.json() jobs.append(job) return jobs # Run the async function asyncio.run(generate_segmented_customers()) ``` ### 2. QA Pair Generation Create high-quality question-answer pairs from documents for training conversational AI. #### Generate QA Pairs ```javascript theme={null} async function generateQAPairs(documentPath, options = {}) { const formData = new FormData(); formData.append('project_id', 'qa-generation'); formData.append('input_file', documentPath); formData.append('qa_type', options.qaType || 'qa'); // qa, cot, summary, extraction formData.append('num_pairs', options.numPairs || '100'); formData.append('verbose', options.verbose || 'false'); const response = await fetch(`${SyntheticDataClient.baseURL}/synthdata/create-qa`, { method: 'POST', headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}` }, body: formData }); return response.json(); } // Generate different types of QA pairs const qaTypes = { standard: await generateQAPairs('/docs/product-manual.pdf', { qaType: 'qa', numPairs: 200 }), chainOfThought: await generateQAPairs('/docs/technical-guide.pdf', { qaType: 'cot', numPairs: 100 }), summaries: await generateQAPairs('/docs/company-reports.pdf', { qaType: 'summary', numPairs: 50 }), extraction: await generateQAPairs('/docs/contracts.pdf', { qaType: 'extraction', numPairs: 150 }) }; ``` #### Curate QA Pairs Apply quality scoring and filtering to ensure high-quality training data: ```javascript theme={null} async function curateQAPairs(inputFile, qualityThreshold = 8.0) { const formData = new FormData(); formData.append('project_id', 'qa-curation'); formData.append('input_file', inputFile); formData.append('threshold', qualityThreshold.toString()); formData.append('batch_size', '100'); const response = await fetch(`${SyntheticDataClient.baseURL}/synthdata/curate-qa`, { method: 'POST', headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}` }, body: formData }); const job = await response.json(); // Wait for curation to complete const result = await waitForJob(job.id); logger.info(`Curated ${result.kept_pairs} high-quality pairs`); logger.info(`Filtered out ${result.removed_pairs} low-quality pairs`); return result; } ``` ### 3. Fine-Tuning Data Preparation Prepare and format data for fine-tuning language models: ```javascript theme={null} class FineTuningDataPipeline { constructor(apiClient) { this.client = apiClient; } async prepareTrainingData(rawData, config) { // Step 1: Generate synthetic examples if needed if (config.augmentWithSynthetic) { const synthetic = await this.generateSyntheticExamples( rawData, config.syntheticRatio ); rawData = [...rawData, ...synthetic]; } // Step 2: Format for fine-tuning const formatted = this.formatForFineTuning(rawData, config.model); // Step 3: Split into train/validation const { train, validation } = this.splitData(formatted, config.validationSplit); // Step 4: Upload files const trainFile = await this.uploadTrainingFile(train); const validationFile = await this.uploadTrainingFile(validation); // Step 5: Create fine-tuning job const job = await this.createFineTuningJob({ training_file: trainFile.id, validation_file: validationFile.id, model: config.model, hyperparameters: config.hyperparameters }); return job; } formatForFineTuning(data, model) { return data.map(item => { if (model.includes('gpt')) { return { messages: [ { role: 'system', content: item.system || 'You are a helpful assistant.' }, { role: 'user', content: item.prompt }, { role: 'assistant', content: item.completion } ] }; } // Add other model formats as needed return item; }); } async uploadTrainingFile(data) { const jsonl = data.map(item => JSON.stringify(item)).join('\n'); const blob = new Blob([jsonl], { type: 'application/jsonl' }); const formData = new FormData(); formData.append('file', blob, 'training_data.jsonl'); const response = await fetch(`${SyntheticDataClient.baseURL}/api/finetuning/upload-training-file`, { method: 'POST', headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}` }, body: formData }); return response.json(); } } ``` ## Advanced Use Cases ### 1. Multi-Modal Data Generation Generate coordinated datasets across multiple data types: ```javascript theme={null} class MultiModalDataGenerator { async generateEcommerceDataset(config) { const dataset = { customers: [], products: [], orders: [], reviews: [], support_tickets: [] }; // Step 1: Generate customers const customerJob = await this.generateCustomers(config.numCustomers); dataset.customers = await this.waitForJobCompletion(customerJob); // Step 2: Generate products based on customer interests const productJob = await this.generateProducts({ count: config.numProducts, categories: this.extractCategories(dataset.customers) }); dataset.products = await this.waitForJobCompletion(productJob); // Step 3: Generate realistic order history const orderJob = await this.generateOrders({ customers: dataset.customers, products: dataset.products, timeRange: config.orderTimeRange }); dataset.orders = await this.waitForJobCompletion(orderJob); // Step 4: Generate reviews based on orders const reviewJob = await this.generateReviews({ orders: dataset.orders, sentiment_distribution: config.reviewSentiment }); dataset.reviews = await this.waitForJobCompletion(reviewJob); // Step 5: Generate support tickets based on orders and reviews const ticketJob = await this.generateSupportTickets({ orders: dataset.orders, reviews: dataset.reviews.filter(r => r.rating < 3), issue_probability: config.supportTicketRate }); dataset.support_tickets = await this.waitForJobCompletion(ticketJob); return dataset; } } ``` ### 2. Time-Series Data Generation Create realistic time-series data for analytics and forecasting: ```javascript theme={null} async function generateTimeSeriesData(config) { const generator = new TimeSeriesGenerator({ startDate: '2023-01-01', endDate: '2024-12-31', frequency: 'daily', metrics: [ { name: 'daily_revenue', baseValue: 10000, trend: 0.002, // 0.2% daily growth seasonality: { weekly: { sunday: 0.7, saturday: 1.3 }, monthly: { december: 1.8, january: 0.6 } }, noise: 0.1 }, { name: 'customer_count', baseValue: 1000, trend: 0.001, correlation: { daily_revenue: 0.8 } } ] }); const data = await generator.generate(); // Add realistic anomalies const anomalies = [ { date: '2023-11-24', metric: 'daily_revenue', multiplier: 3.5 }, // Black Friday { date: '2023-12-26', metric: 'daily_revenue', multiplier: 2.0 }, // Boxing Day ]; return generator.injectAnomalies(data, anomalies); } ``` ### 3. Scenario Testing Data Generate specific scenarios for testing edge cases: ```javascript theme={null} class ScenarioDataGenerator { async generateTestScenarios() { const scenarios = { highValueCustomerChurn: await this.generateScenario({ customerProfile: { lifetime_value: { min: 10000 }, loyalty_points: { min: 5000 }, order_count: { min: 50 } }, behavior: { recent_activity: 'declining', support_tickets: 'increasing', satisfaction_trend: 'negative' }, count: 100 }), fraudulentPatterns: await this.generateScenario({ customerProfile: { account_age_days: { max: 7 }, shipping_addresses: { min: 3 }, payment_methods: { min: 4 } }, orderPatterns: { high_value_items: true, rush_shipping: true, different_billing_shipping: true }, count: 50 }), seasonalSurge: await this.generateScenario({ timeframe: 'holiday_season', traffic_multiplier: 5, conversion_rate: 0.08, average_order_value: 1.5, support_ticket_rate: 2.0, count: 10000 }) }; return scenarios; } } ``` ## Monitoring & Analytics ### Real-Time Progress Monitoring ```javascript theme={null} class SyntheticDataMonitor { constructor(jobId) { this.jobId = jobId; this.metrics = { recordsGenerated: 0, qualityScore: 0, estimatedTimeRemaining: 0 }; } async monitor() { // WebSocket connection for real-time updates const ws = new WebSocket(`ws://localhost:8000/ws/jobs/${this.jobId}`); ws.onmessage = (event) => { const update = JSON.parse(event.data); switch (update.type) { case 'progress': this.updateProgress(update); break; case 'quality_check': this.updateQuality(update); break; case 'completed': this.handleCompletion(update); break; case 'error': this.handleError(update); break; } }; // Periodic status checks via REST API this.statusInterval = setInterval(async () => { const status = await this.checkJobStatus(); this.updateMetrics(status); }, 5000); } async checkJobStatus() { const response = await fetch(`${SyntheticDataClient.baseURL}/jobs/${this.jobId}`, { headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}` } }); return response.json(); } } ``` ### Quality Metrics Dashboard ```javascript theme={null} async function getDataQualityMetrics(projectId) { const response = await fetch(`${SyntheticDataClient.baseURL}/projects/${projectId}/quality-metrics`, { headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}` } }); const metrics = await response.json(); return { overall_quality_score: metrics.overall_score, data_distribution: { statistical_validity: metrics.distribution.ks_test_score, diversity_index: metrics.distribution.diversity, balance_score: metrics.distribution.balance }, field_quality: metrics.fields.map(field => ({ name: field.name, completeness: field.completeness, uniqueness: field.uniqueness, validity: field.validity, consistency: field.consistency })), recommendations: metrics.recommendations }; } ``` ## Best Practices ### 1. Data Generation Strategy ```javascript theme={null} // Good: Incremental generation with validation async function generateDataIncrementally(totalRecords, batchSize = 1000) { const batches = Math.ceil(totalRecords / batchSize); const generatedData = []; for (let i = 0; i < batches; i++) { const batch = await generateBatch({ size: Math.min(batchSize, totalRecords - i * batchSize), offset: i * batchSize }); // Validate each batch const validation = await validateBatch(batch); if (validation.isValid) { generatedData.push(...batch); } else { logger.error(`Batch ${i} failed validation:`, validation.errors); // Retry or handle error } // Progress update logger.info(`Generated ${generatedData.length}/${totalRecords} records`); } return generatedData; } // Bad: Generating all data at once async function generateAllAtOnce(totalRecords) { return generateBatch({ size: totalRecords }); // May timeout or OOM } ``` ### 2. Quality Assurance ```javascript theme={null} class DataQualityAssurance { async validateSyntheticData(data, requirements) { const validations = { schema: await this.validateSchema(data, requirements.schema), statistics: await this.validateStatistics(data, requirements.statistics), business_rules: await this.validateBusinessRules(data, requirements.rules), privacy: await this.validatePrivacy(data) }; const report = { passed: Object.values(validations).every(v => v.passed), validations, recommendations: this.generateRecommendations(validations) }; return report; } async validateStatistics(data, expectedStats) { const actualStats = calculateStatistics(data); const deviations = {}; for (const [metric, expected] of Object.entries(expectedStats)) { const actual = actualStats[metric]; const deviation = Math.abs(actual - expected) / expected; deviations[metric] = { expected, actual, deviation, acceptable: deviation < 0.1 // 10% tolerance }; } return { passed: Object.values(deviations).every(d => d.acceptable), deviations }; } } ``` ### 3. Performance Optimization ```javascript theme={null} // Use streaming for large datasets async function* streamSyntheticData(config) { const pageSize = 1000; let offset = 0; while (offset < config.total) { const response = await fetch(`${SyntheticDataClient.baseURL}/synthdata/stream`, { method: 'POST', headers: { 'Authorization': `Bearer ${SyntheticDataClient.headers.Authorization}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ ...config, offset, limit: pageSize }) }); const data = await response.json(); if (data.records.length === 0) break; yield data.records; offset += data.records.length; } } // Process data as it's generated async function processStreamingData() { const stream = streamSyntheticData({ type: 'customers', total: 1000000 }); for await (const batch of stream) { await processBatch(batch); logger.info(`Processed ${batch.length} records`); } } ``` ## Error Handling ### Comprehensive Error Management ```javascript theme={null} class SyntheticDataErrorHandler { async handleAPIError(error) { const errorHandlers = { RATE_LIMITED: async () => { const retryAfter = error.headers['X-RateLimit-Reset']; await this.delay(retryAfter * 1000); return { retry: true }; }, INVALID_INPUT: () => { logger.error('Invalid input:', error.detail); return { retry: false, fix: this.suggestInputFix(error) }; }, INTERNAL_ERROR: async () => { await this.reportError(error); return { retry: true, delay: 5000 }; }, SERVICE_UNAVAILABLE: () => { return { retry: true, delay: 30000, useBackup: true }; } }; const handler = errorHandlers[error.error_code] || errorHandlers.INTERNAL_ERROR; return handler(); } suggestInputFix(error) { // Analyze error and suggest fixes const suggestions = { 'missing_required_field': `Add required field: ${error.field}`, 'invalid_format': `Expected format: ${error.expected_format}`, 'value_out_of_range': `Value must be between ${error.min} and ${error.max}` }; return suggestions[error.validation_error] || 'Check API documentation'; } } ``` ## Troubleshooting ### Common Issues and Solutions 1. **API Authentication Errors** * **Symptom**: 401 Unauthorized responses * **Solution**: Verify your API key is correctly set in the environment variables and not expired. Regenerate if necessary from your dashboard. 2. **Job Timeout or No Progress** * **Symptom**: WebSocket shows no updates, or job stuck at 0% * **Solution**: Check server status in the dashboard. For large jobs, increase timeout settings or split into smaller batches. 3. **Invalid Data Format** * **Symptom**: 400 Bad Request with format errors * **Solution**: Validate your input data against the schema. Use the preview endpoint to test small samples. 4. **Rate Limit Exceeded** * **Symptom**: 429 Too Many Requests * **Solution**: Implement exponential backoff in your client code. Upgrade your plan for higher limits. 5. **WebSocket Disconnection** * **Symptom**: Monitoring stops unexpectedly * **Solution**: Implement reconnection logic in your WebSocket handler with exponential backoff. If issues persist, contact support with your job ID and error details. ## Security & Compliance ### Privacy-Preserving Generation ```javascript theme={null} class PrivacyPreservingSynthData { async generateCompliantData(config) { const privacyRules = { // No real PII patterns email_format: 'synthetic_[hash]@example.com', phone_format: '555-0[random]', // Differential privacy for statistics differential_privacy: { epsilon: 1.0, delta: 1e-5 }, // K-anonymity for demographics k_anonymity: { k: 5, quasi_identifiers: ['age', 'zipcode', 'gender'] } }; const data = await this.generateWithPrivacy(config, privacyRules); // Validate compliance const compliance = await this.validateCompliance(data, { gdpr: true, ccpa: true, hipaa: config.industry === 'healthcare' }); return { data, compliance_report: compliance }; } } ``` ## Pricing & Limits * 10,000 records/month * Basic customer profiles * Standard QA generation * Community support * 1M records/month * Advanced profiles with ML scores * Custom data schemas * Priority support * \$299/month * Unlimited records * Custom data generators * Private deployment option * SLA guarantee * Contact sales ## Next Steps Complete API documentation with all endpoints Detailed schemas for all data types *** **Pro Tip**: Start with small batches to validate your data generation parameters, then scale up. Use preview endpoints to check data quality before generating large datasets. For support and examples, visit our [GitHub repository](https://github.com/StateSet/synthetic-data-examples) or contact [support@StateSet.com](mailto:support@StateSet.com). # StateSet Synthetic Data Studio Architecture Guide Source: https://docs.stateset.com/guides/synthetic-data-architecture Complete technical architecture documentation for the agentic AI platform ## Executive Overview The StateSet Synthetic Data Studio is an agentic AI platform that combines cutting-edge machine learning techniques with enterprise-grade infrastructure. Built around the innovative Group Relative Policy Optimization (GRPO) algorithm, the platform enables organizations to train, optimize, and deploy sophisticated conversational AI agents. ### Key Architectural Principles Modular, scalable, and maintainable architecture Kubernetes-ready with auto-scaling capabilities Real-time processing with WebSocket support RESTful APIs with GraphQL support planned Multi-layer security with encryption and authentication Sub-200ms API response times at scale ## System Architecture ### High-Level Architecture ```mermaid theme={null} graph TB subgraph "Client Applications" WEB[Web App] MOBILE[Mobile App] CLI[CLI Tool] SDK[SDK] end subgraph "API Gateway Layer" NGINX[Nginx/Load Balancer] RATE[Rate Limiting] CORS[CORS Handler] end subgraph "Application Services" TRAIN[Training Orchestrator] INFER[Inference Engine] SYNTH[Synthetic Data Service] API[API Service] GRPO[GRPO Engine] WS[WebSocket Service] DEPLOY[Agent Deployment] MON[Monitoring Service] end subgraph "Infrastructure Layer" PG[(PostgreSQL)] REDIS[(Redis Cache)] CELERY[Celery Queue] S3[S3 Storage] end WEB --> NGINX MOBILE --> NGINX CLI --> NGINX SDK --> NGINX NGINX --> API NGINX --> WS API --> TRAIN API --> INFER API --> SYNTH API --> DEPLOY TRAIN --> GRPO GRPO --> CELERY TRAIN --> PG INFER --> REDIS SYNTH --> S3 MON --> PG ``` ### Component Communication ```mermaid theme={null} sequenceDiagram participant Client participant API Gateway participant Service participant Database Client->>API Gateway: HTTP Request API Gateway->>Service: Route Request Service->>Database: Query Data Database-->>Service: Return Data Service-->>API Gateway: Response API Gateway-->>Client: HTTP Response ``` ```mermaid theme={null} sequenceDiagram participant Client participant API participant Queue participant Worker participant WebSocket Client->>API: Start Job API->>Queue: Enqueue Task API-->>Client: Job ID Queue->>Worker: Process Task Worker->>WebSocket: Progress Update WebSocket-->>Client: Real-time Update ``` ## Technology Stack ### Frontend Stack * **Framework**: React 18 with TypeScript * **State Management**: Redux Toolkit + RTK Query * **UI Components**: Ant Design (antd) * **Styling**: Tailwind CSS + Custom CSS * **Build Tools**: Create React App with Craco * **Real-time**: Socket.io Client * **Charts**: Recharts, Apache ECharts * **Code Editor**: Monaco Editor * **Forms**: React Hook Form * **Testing**: Jest + React Testing Library ### Backend Stack * **Framework**: FastAPI (Python 3.9+) * **ASGI Server**: Uvicorn * **Database**: PostgreSQL 14+ with SQLAlchemy * **Cache**: Redis 7+ (multi-layer caching) * **Queue**: Celery with Redis broker * **ML Framework**: PyTorch + Transformers * **File Storage**: S3-compatible object storage * **WebSockets**: FastAPI WebSocket support * **Monitoring**: Prometheus + Grafana * **Logging**: ELK Stack ### Infrastructure Stack ```yaml theme={null} Container Platform: - Docker & Docker Compose - Kubernetes (K8s) - Helm Charts Observability: - Prometheus + Grafana (Metrics) - ELK Stack (Logging) - OpenTelemetry + Jaeger (Tracing) CI/CD: - GitHub Actions / GitLab CI - ArgoCD (GitOps) - Tekton Pipelines Service Mesh: - Istio (planned) - Linkerd (alternative) ``` ## Core Components ### 1. GRPO Training Engine The heart of the platform, implementing Group Relative Policy Optimization: ```python theme={null} class GRPOArchitecture: """Core GRPO training architecture""" components = { "trajectory_generator": { "purpose": "Generates multiple response trajectories", "features": ["Parallel generation", "Memory efficient"] }, "reward_computer": { "purpose": "Hierarchical reward calculation", "features": ["Multi-objective", "Custom functions"] }, "advantage_estimator": { "purpose": "Group-relative advantage computation", "features": ["Baseline normalization", "Variance reduction"] }, "policy_optimizer": { "purpose": "PPO-based policy updates", "features": ["Gradient clipping", "KL control"] }, "kl_controller": { "purpose": "Adaptive KL divergence control", "features": ["Dynamic adjustment", "Stability monitoring"] } } ``` * **Distributed Training**: Multi-GPU/multi-node support * **Auto-optimization**: Hyperparameter tuning * **Real-time Monitoring**: Training metrics dashboard * **Version Control**: Model checkpointing * **Resource Management**: Dynamic GPU allocation ### 2. Synthetic Data Generation Pipeline ```mermaid theme={null} graph LR A[Input Documents] --> B[Text Processing] B --> C[Prompt Engineering] C --> D[LLM Generation] D --> E[Quality Filtering] E --> F[Format Conversion] F --> G[Output Storage] B -.-> H[OCR for Images] B -.-> I[PDF Extraction] E -.-> J[ML Quality Score] E -.-> K[Rule Validation] ``` **Pipeline Components:** * Handles multiple formats (PDF, DOCX, TXT, HTML) * Intelligent content extraction * Metadata preservation * Chunking strategies for large documents * Template-based prompt construction * Dynamic variable injection * Context-aware prompting * Multi-language support * Async LLM API calls with retry logic * Load balancing across providers * Token optimization * Response caching * Rule-based validation * ML-powered quality scoring * Duplicate detection * Consistency checking ### 3. Agent Deployment Service ```python theme={null} class AgentDeploymentArchitecture: """Agent deployment and lifecycle management""" features = { "model_registry": { "versioning": "Semantic versioning", "metadata": "Training configs, metrics", "rollback": "One-click rollback support" }, "deployment_manager": { "strategies": ["Blue-green", "Canary", "A/B testing"], "scaling": "Auto-scaling based on load", "health": "Continuous health monitoring" }, "load_balancer": { "routing": "Intelligent request routing", "affinity": "Session affinity support", "failover": "Automatic failover" }, "monitoring": { "metrics": "Latency, throughput, errors", "alerts": "Configurable alerting", "dashboards": "Real-time Grafana dashboards" } } ``` ### 4. Real-time Communication Layer ```mermaid theme={null} graph LR subgraph "Client Side" C1[Client 1] C2[Client 2] CN[Client N] end subgraph "Server Side" GW[WebSocket Gateway] CM[Connection Manager] RP[Redis Pub/Sub] BS[Backend Services] end C1 <--> GW C2 <--> GW CN <--> GW GW <--> CM CM <--> RP RP <--> BS ``` **Features:** * Connection pooling and management * Heartbeat monitoring (30s intervals) * Message queuing with delivery guarantees * Horizontal scaling with Redis clustering * Graceful reconnection handling ## Data Flow Architecture ### Training Data Flow Raw documents uploaded to S3-compatible storage ```python theme={null} POST /api/v1/documents/upload Content-Type: multipart/form-data ``` Documents processed through extraction pipeline ```python theme={null} # Async processing job job_id = process_documents.delay(document_ids) ``` LLM generates variations based on templates ```python theme={null} synthetic_data = generate_synthetic_qa( documents=processed_docs, count=1000, quality_threshold=0.8 ) ``` ML models filter and score generated data ```python theme={null} curated_data = quality_filter.apply( synthetic_data, min_score=0.85 ) ``` Data formatted for GRPO training ```python theme={null} training_dataset = prepare_grpo_dataset( curated_data, reward_function=custom_reward ) ``` GRPO engine trains on prepared data ```python theme={null} model = grpo_trainer.train( dataset=training_dataset, config=grpo_config ) ``` ### Request Processing Flow ```python theme={null} # API Request Flow with Caching async def process_request(request: Request): # 1. Authentication user = await auth_service.validate_token(request.headers) # 2. Rate Limiting if not await rate_limiter.check(user.id): raise HTTPException(429, "Rate limit exceeded") # 3. Cache Check cache_key = generate_cache_key(request) cached = await redis.get(cache_key) if cached: return JSONResponse(cached) # 4. Business Logic result = await business_logic.process(request) # 5. Cache Update await redis.setex(cache_key, 3600, result) # 6. Response return JSONResponse(result) ``` ### API Gateway Features * **Rate Limiting**: Token bucket algorithm * **Authentication**: JWT with refresh tokens * **Authorization**: RBAC + ABAC * **Input Validation**: Pydantic models * **CORS**: Configurable origins * **Response Caching**: ETag support * **Compression**: Gzip/Brotli * **Connection Pooling**: Keep-alive * **Load Balancing**: Round-robin/least-conn * **Circuit Breaker**: Fault tolerance ## Security Architecture ### Multi-Layer Security Model ```mermaid theme={null} graph TD A[WAF/DDoS Protection] --> B[TLS 1.3 Encryption] B --> C[API Gateway] C --> D[Authentication Layer] D --> E[Authorization Layer] E --> F[Application Security] F --> G[Data Encryption] C -.-> H[Rate Limiting] D -.-> I[JWT Validation] E -.-> J[RBAC/ABAC] F -.-> K[OWASP Compliance] G -.-> L[AES-256 Encryption] ``` ### Security Components ```python theme={null} class AuthenticationService: """Multi-factor authentication with JWT""" features = { "jwt_tokens": { "access_token_ttl": "15 minutes", "refresh_token_ttl": "7 days", "algorithm": "RS256" }, "mfa_support": { "methods": ["TOTP", "SMS", "Email"], "backup_codes": True }, "session_management": { "storage": "Redis", "concurrent_limit": 5 } } ``` ```python theme={null} class AuthorizationService: """Fine-grained access control""" features = { "rbac": { "roles": ["admin", "developer", "analyst", "viewer"], "inheritance": True }, "abac": { "attributes": ["department", "project", "clearance"], "policies": "JSON-based policy engine" }, "resource_permissions": { "granularity": "Object-level", "caching": "Redis-based" } } ``` ```python theme={null} class DataSecurityLayer: """Comprehensive data protection""" encryption = { "at_rest": { "algorithm": "AES-256-GCM", "key_rotation": "90 days" }, "in_transit": { "protocol": "TLS 1.3", "cipher_suites": ["TLS_AES_256_GCM_SHA384"] }, "key_management": { "service": "AWS KMS / HashiCorp Vault", "hsm_support": True } } ``` ```python theme={null} class AuditCompliance: """Regulatory compliance and auditing""" features = { "audit_logging": { "events": ["auth", "data_access", "config_change"], "retention": "7 years", "immutable": True }, "compliance": { "gdpr": ["data_portability", "right_to_forget"], "hipaa": ["encryption", "access_controls"], "sox": ["audit_trails", "segregation"] } } ``` ## Performance & Scalability ### Performance Optimizations ```javascript theme={null} // Code splitting with lazy loading const TrainingDashboard = lazy(() => import('./pages/TrainingDashboard') ); // Bundle optimization optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, priority: 10 } } } } // Service Worker caching serviceWorkerRegistration.register({ onUpdate: registration => { // Handle updates } }); // Virtual scrolling for large lists ``` ```python theme={null} # Connection pooling engine = create_async_engine( DATABASE_URL, pool_size=20, max_overflow=40, pool_pre_ping=True, pool_recycle=3600 ) # Query optimization @cached(ttl=300) async def get_user_models(user_id: str): return await db.execute( select(Model) .options(selectinload(Model.metrics)) .where(Model.user_id == user_id) .order_by(Model.created_at.desc()) ) # Async I/O throughout async def process_request(request: Request): async with httpx.AsyncClient() as client: tasks = [ fetch_user_data(client, user_id), fetch_model_data(client, model_id), fetch_metrics(client, metric_ids) ] results = await asyncio.gather(*tasks) ``` ```python theme={null} # Multi-GPU configuration class DistributedTrainer: def __init__(self, num_gpus=4): self.device_ids = list(range(num_gpus)) self.model = nn.DataParallel( model, device_ids=self.device_ids ) def train(self, dataloader): # Gradient accumulation accumulation_steps = 4 for i, batch in enumerate(dataloader): loss = self.model(batch) / accumulation_steps loss.backward() if (i + 1) % accumulation_steps == 0: optimizer.step() optimizer.zero_grad() # Mixed precision training scaler = torch.cuda.amp.GradScaler() with autocast(): output = model(input) loss = criterion(output, target) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() ``` ### Caching Strategy ```python theme={null} class MultiLayerCache: """Three-layer caching architecture""" def __init__(self): # L1: In-memory LRU Cache (microseconds) self.memory_cache = LRUCache(maxsize=1000) # L2: Redis Cache (sub-millisecond) self.redis_cache = Redis( host='redis-cluster', decode_responses=True, socket_keepalive=True ) # L3: Database with optimized queries self.db = Database() async def get(self, key: str): # Check L1 if value := self.memory_cache.get(key): return value # Check L2 if value := await self.redis_cache.get(key): self.memory_cache[key] = value return value # Check L3 if value := await self.db.query(key): await self.redis_cache.setex(key, 3600, value) self.memory_cache[key] = value return value return None ``` ### Scalability Architecture * Stateless services * Load balancing with health checks * Auto-scaling based on metrics * Session affinity when needed * Resource limits and requests * Memory-optimized instances for ML * GPU instances for training * Burst capacity handling * Database sharding strategies * Time-series data partitioning * Object storage for large files * CDN for static assets ### Performance Metrics ```yaml theme={null} Target Metrics: API: response_time_p95: < 200ms throughput: > 10,000 req/s error_rate: < 0.1% Training: samples_per_hour_per_gpu: > 10,000 gpu_utilization: > 90% memory_efficiency: > 85% Infrastructure: concurrent_users: > 10,000 websocket_connections: > 100,000 cache_hit_rate: > 90% uptime: 99.9% Database: query_time_p95: < 50ms connection_pool_efficiency: > 95% replication_lag: < 1s ``` ## Development Guidelines ### Coding Standards ```python theme={null} """ Python Coding Standards """ # 1. Follow PEP 8 style guide from typing import List, Optional, Dict, Any import asyncio from datetime import datetime # 2. Type hints for all functions async def process_training_job( job_id: str, config: Dict[str, Any], timeout: Optional[int] = 3600 ) -> TrainingResult: """ Process a training job asynchronously. Args: job_id: Unique job identifier config: Training configuration timeout: Maximum execution time in seconds Returns: TrainingResult object with metrics Raises: TrainingError: If training fails TimeoutError: If timeout exceeded """ try: async with timeout_context(timeout): result = await train_model(job_id, config) return result except asyncio.TimeoutError: raise TimeoutError(f"Job {job_id} exceeded timeout") except Exception as e: logger.error(f"Training failed: {e}") raise TrainingError(str(e)) # 3. Comprehensive error handling class TrainingError(Exception): """Custom exception for training errors""" pass # 4. Async/await for I/O operations async def fetch_training_data(dataset_id: str) -> Dataset: async with get_db_session() as session: return await session.get(Dataset, dataset_id) ``` ```typescript theme={null} /** * TypeScript Coding Standards */ // 1. Strict TypeScript settings // tsconfig.json: "strict": true // 2. Interface definitions interface TrainingJob { id: string; status: 'pending' | 'running' | 'completed' | 'failed'; progress: number; config: TrainingConfig; metrics?: TrainingMetrics; createdAt: Date; updatedAt: Date; } // 3. Component typing interface DashboardProps { userId: string; onJobSelect: (jobId: string) => void; } const Dashboard: React.FC = ({ userId, onJobSelect }) => { // 4. Custom hooks for logic reuse const { jobs, loading, error } = useTrainingJobs(userId); // 5. Error boundaries if (error) { return ; } return (
{/* Component implementation */}
); }; // 6. Async handling with proper types const fetchJobs = async ( userId: string ): Promise => { try { const response = await api.get( `/users/${userId}/jobs` ); return response.data; } catch (error) { logger.error('Failed to fetch jobs:', error); throw new Error('Failed to load training jobs'); } }; ```
```yaml theme={null} # RESTful API Design Principles # 1. Consistent naming conventions /api/v1/resources # Plural for collections /api/v1/resources/{id} # Singular for items # 2. HTTP methods usage GET - Read operations POST - Create operations PUT - Full updates PATCH - Partial updates DELETE - Delete operations # 3. Status codes 200 OK - Successful GET/PUT/PATCH 201 Created - Successful POST 204 No Content - Successful DELETE 400 Bad Request - Invalid request 401 Unauthorized - Authentication required 403 Forbidden - Insufficient permissions 404 Not Found - Resource not found 422 Unprocessable - Validation errors 429 Too Many Requests - Rate limit exceeded 500 Internal Error - Server error # 4. Response format { "data": { "id": "123", "type": "training_job", "attributes": { "status": "running", "progress": 0.75 } }, "meta": { "timestamp": "2025-01-20T10:00:00Z", "version": "1.0.0" } } # 5. Error format { "error": { "code": "VALIDATION_ERROR", "message": "Invalid training configuration", "details": { "field": "batch_size", "reason": "Must be between 1 and 128" } } } ```
### Testing Architecture ```mermaid theme={null} graph TB subgraph "Testing Pyramid" UT[Unit Tests - 70%] IT[Integration Tests - 20%] E2E[E2E Tests - 10%] end subgraph "Test Types" FUNC[Functional Tests] PERF[Performance Tests] SEC[Security Tests] LOAD[Load Tests] end UT --> FUNC IT --> FUNC E2E --> FUNC IT --> PERF E2E --> PERF IT --> SEC E2E --> SEC E2E --> LOAD ``` ```python theme={null} # Python unit test example import pytest from unittest.mock import AsyncMock, patch @pytest.mark.asyncio async def test_grpo_training(): # Arrange mock_dataset = AsyncMock() mock_dataset.get_batch.return_value = sample_batch trainer = GRPOTrainer(config=test_config) # Act with patch('grpo.save_checkpoint') as mock_save: result = await trainer.train(mock_dataset) # Assert assert result.final_loss < 0.1 assert mock_save.called assert result.epochs == test_config.epochs ``` ```typescript theme={null} // TypeScript integration test describe('Training API Integration', () => { let app: Application; beforeAll(async () => { app = await createTestApp(); }); it('should create and monitor training job', async () => { // Create job const createResponse = await request(app) .post('/api/v1/training/grpo/start') .send({ model_name: 'test-model', dataset_id: 'test-dataset' }) .expect(201); const jobId = createResponse.body.job_id; // Monitor progress const statusResponse = await request(app) .get(`/api/v1/training/grpo/${jobId}/status`) .expect(200); expect(statusResponse.body).toMatchObject({ status: expect.stringMatching(/queued|running/), progress: expect.any(Number) }); }); }); ``` ```javascript theme={null} // Cypress E2E test describe('Training Dashboard E2E', () => { beforeEach(() => { cy.login('test@example.com', 'password'); cy.visit('/dashboard'); }); it('should complete training workflow', () => { // Start new training cy.get('[data-cy=new-training]').click(); cy.get('[data-cy=model-select]').select('gpt-small'); cy.get('[data-cy=dataset-upload]').attachFile('test-data.jsonl'); cy.get('[data-cy=start-training]').click(); // Monitor progress cy.get('[data-cy=progress-bar]', { timeout: 10000 }) .should('be.visible'); // Wait for completion cy.get('[data-cy=training-status]', { timeout: 60000 }) .should('contain', 'Completed'); // Verify model deployment cy.get('[data-cy=deploy-model]').click(); cy.get('[data-cy=deployment-status]') .should('contain', 'Deployed'); }); }); ``` ```python theme={null} # Locust performance test from locust import HttpUser, task, between class SyntheticDataUser(HttpUser): wait_time = between(1, 3) def on_start(self): # Login response = self.client.post("/api/v1/auth/login", json={ "email": "test@example.com", "password": "password" }) self.token = response.json()["access_token"] self.client.headers.update({ "Authorization": f"Bearer {self.token}" }) @task(weight=3) def list_models(self): self.client.get("/api/v1/models") @task(weight=2) def get_model_details(self): self.client.get("/api/v1/models/test-model-id") @task(weight=1) def start_training(self): self.client.post("/api/v1/training/grpo/start", json={ "model_name": "test-model", "dataset_id": "test-dataset" }) ``` ## Future Architecture Roadmap ### Phase 1: Foundation Enhancement (Q1 2025) ```graphql theme={null} type Query { models(filter: ModelFilter, page: Int, limit: Int): ModelConnection! model(id: ID!): Model trainingJobs(status: JobStatus): [TrainingJob!]! } type Mutation { startTraining(input: TrainingInput!): TrainingJob! deployModel(modelId: ID!, config: DeployConfig!): Deployment! } type Subscription { trainingProgress(jobId: ID!): TrainingUpdate! } ``` * Istio deployment for traffic management * mTLS for service-to-service communication * Advanced traffic routing and canary deployments * Distributed tracing with OpenTelemetry * Custom metrics and SLI/SLO tracking * AI-powered anomaly detection * Namespace isolation in Kubernetes * Resource quotas per tenant * Tenant-specific data segregation ### Phase 2: Advanced Features (Q2 2025) * Text + Vision model training * Audio processing capabilities * Cross-modal synthetic data * Privacy-preserving training * Edge device support * Differential privacy integration * Model optimization for edge * ONNX runtime support * Mobile SDK development * Automated hyperparameter tuning * Neural architecture search * Automatic feature engineering ### Phase 3: Enterprise Scale (Q3 2025) * **Global CDN Integration**: CloudFlare/Fastly integration * **Disaster Recovery**: Multi-region failover, automated backups * **Compliance Certifications**: SOC2, HIPAA, ISO 27001 * **White-label Support**: Customizable branding and domains ### Phase 4: Innovation (Q4 2025) * **Quantum-ready Algorithms**: Hybrid classical-quantum training * **Neuromorphic Computing**: Support for brain-inspired chips * **Explainability Dashboard**: SHAP/LIME integration * **Self-optimizing Infrastructure**: AI-driven resource management ## Architecture Decision Records (ADRs) **Status**: Accepted\ **Date**: 2024-10-15 **Context**: Need for scalable, maintainable system that can evolve independently **Decision**: Adopt microservices architecture with clear service boundaries **Consequences**: * ✅ Better scalability and team autonomy * ✅ Technology flexibility per service * ❌ Increased operational complexity * ❌ Network latency between services **Mitigation**: Service mesh for communication, comprehensive monitoring **Status**: Accepted\ **Date**: 2024-11-01 **Context**: Need for stable, efficient RL training without critic model overhead **Decision**: Implement custom GRPO with group-relative advantages **Consequences**: * ✅ 50% memory savings vs PPO * ✅ Faster convergence * ❌ Custom implementation maintenance * ❌ Less community support **Mitigation**: Comprehensive testing, detailed documentation **Status**: Accepted\ **Date**: 2024-11-20 **Context**: Need for high performance at scale with \<200ms response times **Decision**: Implement L1 (memory) + L2 (Redis) + L3 (DB) caching **Consequences**: * ✅ Sub-millisecond response times * ✅ Reduced database load * ❌ Cache invalidation complexity * ❌ Memory overhead **Mitigation**: TTL-based invalidation, cache warming strategies **Status**: Accepted\ **Date**: 2024-12-05 **Context**: Need for real-time updates and loose service coupling **Decision**: Use Redis Pub/Sub for event propagation with WebSockets **Consequences**: * ✅ Real-time user experience * ✅ Decoupled services * ❌ Event ordering challenges * ❌ Potential message loss **Mitigation**: Event sourcing, message persistence, retry mechanisms ## Conclusion The Synthetic Data Studio architecture represents a world-class platform that combines cutting-edge AI research with enterprise-grade engineering. The architecture delivers: * **Performance**: Sub-200ms API responses * **Scalability**: 10,000+ concurrent users * **Reliability**: 99.9% uptime SLA * **Security**: Multi-layer protection * **Time to Market**: Rapid deployment * **Cost Efficiency**: Optimized resource usage * **Flexibility**: Adapt to changing needs * **Innovation**: Future-ready platform This architecture positions the platform to capture significant market share in the rapidly growing conversational AI space while maintaining the flexibility to adapt to future technological advances. *** **Architecture Team Contact**: For questions or contributions to this architecture guide, please contact the Platform Architecture Team at [architecture@StateSet.com](mailto:architecture@StateSet.com) # Universal Commerce Protocol Handler Source: https://docs.stateset.com/guides/universal-commerce-protocol-handler Rust server that implements the Universal Commerce Protocol checkout flow and extensions StateSet UCP Handler is a standalone Rust server that implements the Universal Commerce Protocol (UCP) checkout flow. It exposes discovery, checkout session lifecycle, tokenization, webhook delivery, and optional OAuth identity linking. ## Key capabilities * Discovery at `/.well-known/ucp` * Checkout session lifecycle endpoints * Fulfillment and discount extensions * Order webhooks and audit logs * Tokenization endpoints (`/tokenize`, `/detokenize`) * Optional OAuth 2.0 identity linking and AP2 mandate extension * gRPC API with JSON payloads * Optional iCommerce backend with SQLite persistence ## Quickstart ```bash theme={null} cargo run ``` The HTTP server listens on `http://0.0.0.0:8081` by default. Run the demo flow: ```bash theme={null} ./demo_test.sh ``` ## Required headers By default the handler requires: * `UCP-Agent` on all requests * `Request-Signature` on `POST` and `PUT` You can relax these for local testing with: ```bash theme={null} UCP_REQUIRE_UCP_AGENT=false UCP_REQUIRE_REQUEST_SIGNATURE=false cargo run ``` Optional headers when enabled: * `Request-Id` when `UCP_REQUIRE_REQUEST_ID=true` * `Idempotency-Key` when `UCP_REQUIRE_IDEMPOTENCY=true` ## Create a checkout session ```bash theme={null} curl -X POST https://yourapp.com:8081/api/checkout-sessions \ -H "UCP-Agent: profile=\"https://platform.example/profile\"" \ -H "Request-Signature: " \ -H "Content-Type: application/json" \ -d '{ "line_items": [{ "item": { "id": "item_123" }, "quantity": 2 }], "currency": "USD" }' ``` ## Core endpoints | Method | Endpoint | Description | | ------ | ------------------------------------- | --------------------- | | GET | `/.well-known/ucp` | Discovery document | | GET | `/api/checkout-sessions` | List checkouts | | POST | `/api/checkout-sessions` | Create checkout | | GET | `/api/checkout-sessions/:id` | Retrieve checkout | | PUT | `/api/checkout-sessions/:id` | Update checkout | | POST | `/api/checkout-sessions/:id/complete` | Complete checkout | | POST | `/api/checkout-sessions/:id/cancel` | Cancel checkout | | GET | `/api/orders` | List orders | | GET | `/api/orders/:id` | Retrieve order | | POST | `/tokenize` | Tokenize credential | | POST | `/detokenize` | Detokenize credential | | GET | `/metrics` | Prometheus metrics | | GET | `/health` | Health check | | GET | `/ready` | Readiness check | ## Commerce backend iCommerce is enabled by default and stores checkouts and orders in `./commerce.db`. Disable it for in-memory storage: ```bash theme={null} COMMERCE_ENABLED=false cargo run ``` ## Webhooks and audit trails Set `UCP_ORDER_WEBHOOK_URL` to send order events when a checkout completes. The handler also exposes: * `/api/audit-events` * `/api/webhook-deliveries` ## OAuth and AP2 extensions Enable identity linking with `UCP_OAUTH_ENABLED=true`. Enable AP2 mandate support with `UCP_AP2_ENABLED=true` and `UCP_AP2_MERCHANT_AUTH`. ## gRPC access The gRPC server listens on `0.0.0.0:50051` by default and uses JSON payloads in `payload_json`. Auth can be provided via `authorization` or `x-api-key` metadata. # Vision Quickstart Source: https://docs.stateset.com/guides/vision-quickstart Getting started with StateSet Vision API for image analysis and processing ## Introduction StateSet Vision API enables powerful image analysis capabilities for your applications. From product image verification to visual search and quality control, our Vision API leverages advanced computer vision models to extract meaningful insights from images. ## Prerequisites Before you begin, ensure you have: * A StateSet account with Vision API access enabled * Node.js 16+ installed * StateSet SDK (`npm install StateSet-node`) * Valid API credentials ## Key Features * **Object Detection**: Identify and locate objects within images * **Text Extraction (OCR)**: Extract text from images including labels, receipts, and documents * **Quality Assessment**: Analyze image quality for product listings * **Visual Search**: Find similar products based on image similarity * **Damage Detection**: Identify defects or damage in product images * **Brand Recognition**: Detect logos and brand elements ## Getting Started ```bash theme={null} npm install StateSet-node form-data ``` ```javascript theme={null} const { StateSetClient } = require('StateSet-node'); const FormData = require('form-data'); const fs = require('fs'); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); ``` ```javascript theme={null} async function analyzeImage(imagePath) { try { // Create a form data object const formData = new FormData(); formData.append('image', fs.createReadStream(imagePath)); formData.append('analysis_types', 'object_detection,text_extraction,quality_assessment'); // Upload and analyze the image const analysis = await client.vision.analyze({ formData, options: { confidence_threshold: 0.8, return_coordinates: true } }); return analysis; } catch (error) { logger.error('Vision analysis failed:', error); throw error; } } ``` ## Common Use Cases ### 1. Product Image Verification Verify that uploaded product images meet quality standards: ```javascript theme={null} async function verifyProductImage(imageUrl) { const analysis = await client.vision.analyzeUrl({ url: imageUrl, checks: [ 'resolution_check', // Minimum 800x800 'blur_detection', // Image sharpness 'lighting_quality', // Proper exposure 'background_removal' // Clean background ] }); const passed = analysis.checks.every(check => check.passed); if (!passed) { const failedChecks = analysis.checks .filter(check => !check.passed) .map(check => check.reason); return { approved: false, reasons: failedChecks }; } return { approved: true }; } ``` ### 2. Return Item Condition Assessment Automatically assess the condition of returned items: ```javascript theme={null} async function assessReturnCondition(returnId, imageUrls) { const assessments = await Promise.all( imageUrls.map(async (url) => { const result = await client.vision.analyzeUrl({ url, analysis_types: ['damage_detection', 'wear_assessment'] }); return { imageUrl: url, condition: result.damage_detection.severity, // 'none', 'minor', 'major' damageTypes: result.damage_detection.types, wearLevel: result.wear_assessment.level, confidence: result.confidence }; }) ); // Update return record with condition assessment await client.returns.update({ id: returnId, condition_assessment: assessments, automated_condition: calculateOverallCondition(assessments) }); return assessments; } function calculateOverallCondition(assessments) { const severities = assessments.map(a => a.condition); if (severities.includes('major')) return 'C'; if (severities.includes('minor')) return 'B'; return 'A'; } ``` ### 3. Visual Search for Similar Products Find similar products based on an uploaded image: ```javascript theme={null} async function findSimilarProducts(imagePath, options = {}) { const formData = new FormData(); formData.append('image', fs.createReadStream(imagePath)); const results = await client.vision.similaritySearch({ formData, options: { limit: options.limit || 10, similarity_threshold: options.threshold || 0.75, categories: options.categories || ['all'], include_metadata: true } }); return results.matches.map(match => ({ productId: match.product_id, similarity: match.similarity_score, product: match.metadata, primaryImage: match.image_url })); } ``` ### 4. Receipt and Document Processing Extract structured data from receipts and invoices: ```javascript theme={null} async function processReceipt(receiptImage) { const analysis = await client.vision.analyzeDocument({ image: receiptImage, document_type: 'receipt', extract_fields: [ 'merchant_name', 'total_amount', 'tax_amount', 'date', 'line_items', 'payment_method' ] }); // Validate and structure the extracted data const receipt = { merchant: analysis.fields.merchant_name?.value, total: parseFloat(analysis.fields.total_amount?.value || 0), tax: parseFloat(analysis.fields.tax_amount?.value || 0), date: new Date(analysis.fields.date?.value), items: analysis.fields.line_items?.value || [], confidence: analysis.overall_confidence }; return receipt; } ``` ## Advanced Features ### Batch Processing Process multiple images efficiently: ```javascript theme={null} async function batchAnalyzeImages(imagePaths) { const batchSize = 10; const results = []; for (let i = 0; i < imagePaths.length; i += batchSize) { const batch = imagePaths.slice(i, i + batchSize); const batchPromises = batch.map(path => analyzeImage(path).catch(error => ({ path, error: error.message })) ); const batchResults = await Promise.all(batchPromises); results.push(...batchResults); } return results; } ``` ### Webhook Integration Set up webhooks for async processing: ```javascript theme={null} async function setupVisionWebhook() { const webhook = await client.webhooks.create({ url: 'https://your-app.com/webhooks/vision', events: ['vision.analysis.complete', 'vision.analysis.failed'], secret: process.env.WEBHOOK_SECRET }); return webhook; } // Webhook handler app.post('/webhooks/vision', async (req, res) => { const signature = req.headers['x-StateSet-signature']; if (!verifyWebhookSignature(req.body, signature)) { return res.status(401).send('Invalid signature'); } const { event, data } = req.body; switch (event) { case 'vision.analysis.complete': await handleAnalysisComplete(data); break; case 'vision.analysis.failed': await handleAnalysisFailed(data); break; } res.status(200).send('OK'); }); ``` ## Best Practices ### Image Optimization * Resize images before upload (max 4MB recommended) * Use appropriate formats (JPEG for photos, PNG for graphics) * Compress images without losing quality ### Error Handling ```javascript theme={null} async function safeAnalyzeImage(imagePath) { try { const result = await analyzeImage(imagePath); return { success: true, data: result }; } catch (error) { if (error.code === 'INVALID_IMAGE_FORMAT') { return { success: false, error: 'Please upload a valid image file' }; } else if (error.code === 'IMAGE_TOO_LARGE') { return { success: false, error: 'Image must be less than 4MB' }; } else if (error.code === 'RATE_LIMIT_EXCEEDED') { // Implement exponential backoff await new Promise(resolve => setTimeout(resolve, 5000)); return safeAnalyzeImage(imagePath); // Retry } return { success: false, error: 'Analysis failed. Please try again.' }; } } ``` ### Performance Optimization * Use image URLs instead of uploads when possible * Implement caching for repeated analyses * Process images asynchronously for better UX ## Troubleshooting ### Common Issues 1. **Image Upload Fails** * Check file size (max 4MB) * Verify image format (JPEG, PNG, GIF, BMP) * Ensure proper multipart/form-data headers 2. **Low Confidence Results** * Improve image quality (resolution, lighting) * Ensure subject is clearly visible * Reduce background noise 3. **Slow Processing** * Resize images before upload * Use batch processing for multiple images * Implement webhook callbacks for async processing ## API Reference For detailed API documentation, see: * [Vision API Reference](/api-reference/vision) * [Supported Image Formats](/api-reference/vision/formats) * [Analysis Types](/api-reference/vision/analysis-types) ## Next Steps Use Vision API to automate return condition assessment Create a visual product search experience *** ## Complete Implementation Example Here's a production-ready example that combines all the concepts covered in this guide: ```typescript theme={null} import { StateSetClient } from 'StateSet-node'; import FormData from 'form-data'; import fs from 'fs'; import { logger } from './logger'; class VisionService { private client: StateSetClient; private cache: Map = new Map(); constructor(apiKey: string) { this.client = new StateSetClient({ apiKey }); } /** * Analyze product images with comprehensive error handling */ async analyzeProductImage(imagePath: string, productId: string) { try { // Check cache first const cacheKey = `${productId}_${imagePath}`; if (this.cache.has(cacheKey)) { logger.info('Returning cached analysis', { productId }); return this.cache.get(cacheKey); } // Validate image exists and size const stats = await fs.promises.stat(imagePath); if (stats.size > 4 * 1024 * 1024) { throw new Error('Image size exceeds 4MB limit'); } // Prepare form data const formData = new FormData(); formData.append('image', fs.createReadStream(imagePath)); formData.append('analysis_types', 'object_detection,quality_assessment,text_extraction'); // Perform analysis with timeout const analysis = await this.analyzeWithTimeout(formData, 30000); // Validate results if (analysis.quality_assessment.score < 0.7) { logger.warn('Low quality image detected', { productId, qualityScore: analysis.quality_assessment.score }); } // Cache successful results this.cache.set(cacheKey, analysis); // Clean up old cache entries if (this.cache.size > 100) { const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); } return analysis; } catch (error) { logger.error('Product image analysis failed', { error, productId, imagePath }); // Return graceful degradation response return { success: false, error: this.formatError(error), fallback: { productId, requiresManualReview: true, timestamp: new Date().toISOString() } }; } } /** * Batch process return images with progress tracking */ async processReturnImages(returnId: string, images: string[], onProgress?: (progress: number) => void) { const results = []; const total = images.length; for (let i = 0; i < images.length; i++) { try { const result = await this.assessDamage(images[i]); results.push({ imageIndex: i, imagePath: images[i], ...result }); // Report progress if (onProgress) { onProgress(((i + 1) / total) * 100); } } catch (error) { logger.error('Failed to process return image', { returnId, imageIndex: i, error }); results.push({ imageIndex: i, imagePath: images[i], error: error.message, requiresManualReview: true }); } } // Calculate overall condition const overallCondition = this.calculateReturnCondition(results); // Update return record try { await this.client.returns.update({ id: returnId, condition_assessment: results, overall_condition: overallCondition, assessed_at: new Date().toISOString() }); } catch (error) { logger.error('Failed to update return record', { returnId, error }); } return { returnId, images: results, overallCondition, summary: this.generateConditionSummary(results) }; } private async analyzeWithTimeout(formData: FormData, timeoutMs: number) { return Promise.race([ this.client.vision.analyze({ formData }), new Promise((_, reject) => setTimeout(() => reject(new Error('Analysis timeout')), timeoutMs) ) ]); } private async assessDamage(imagePath: string) { const formData = new FormData(); formData.append('image', fs.createReadStream(imagePath)); const analysis = await this.client.vision.analyzeUrl({ url: imagePath, analysis_types: ['damage_detection', 'wear_assessment'] }); return { damageDetected: analysis.damage_detection.detected, damageSeverity: analysis.damage_detection.severity, damageTypes: analysis.damage_detection.types || [], wearLevel: analysis.wear_assessment.level, confidence: analysis.confidence }; } private calculateReturnCondition(results: any[]): string { const validResults = results.filter(r => !r.error); if (validResults.length === 0) return 'UNKNOWN'; const severities = validResults.map(r => r.damageSeverity); if (severities.includes('major')) return 'C'; if (severities.includes('minor')) return 'B'; return 'A'; } private generateConditionSummary(results: any[]): string { const damageCount = results.filter(r => r.damageDetected).length; const errorCount = results.filter(r => r.error).length; if (errorCount === results.length) { return 'Unable to assess condition - manual review required'; } if (damageCount === 0) { return 'Item appears to be in good condition'; } const damageTypes = [...new Set(results.flatMap(r => r.damageTypes || []))]; return `Damage detected on ${damageCount} of ${results.length} images. Types: ${damageTypes.join(', ')}`; } private formatError(error: any): string { if (error.code === 'INVALID_IMAGE_FORMAT') { return 'Please upload a valid image file (JPEG, PNG, GIF, or BMP)'; } else if (error.code === 'IMAGE_TOO_LARGE') { return 'Image must be less than 4MB'; } else if (error.code === 'RATE_LIMIT_EXCEEDED') { return 'Too many requests. Please try again in a few moments'; } else if (error.message === 'Analysis timeout') { return 'Image analysis is taking longer than expected. Please try again'; } return 'An unexpected error occurred. Please try again'; } } // Usage example async function main() { const visionService = new VisionService(process.env.STATESET_API_KEY!); // Process a product image const productAnalysis = await visionService.analyzeProductImage( './product-images/shoe-1.jpg', 'PROD-12345' ); if (productAnalysis.success !== false) { logger.info('Product analysis complete', { productId: 'PROD-12345', quality: productAnalysis.quality_assessment }); } // Process return images with progress tracking const returnImages = [ './returns/return-001-front.jpg', './returns/return-001-back.jpg', './returns/return-001-detail.jpg' ]; const returnAssessment = await visionService.processReturnImages( 'RET-78901', returnImages, (progress) => { logger.info(`Processing return images: ${progress}% complete`); } ); logger.info('Return assessment complete', { returnId: returnAssessment.returnId, condition: returnAssessment.overallCondition, summary: returnAssessment.summary }); } // Run the example main().catch(console.error); ``` This complete example demonstrates: * Comprehensive error handling with specific error codes * Caching for performance optimization * Progress tracking for batch operations * Graceful degradation when services fail * Proper logging and monitoring * Timeout handling for long operations * Automatic retry logic * Input validation # Voice AI Quickstart Source: https://docs.stateset.com/guides/voice-quickstart Build conversational voice experiences with StateSet's Voice AI capabilities ## Introduction StateSet Voice AI enables natural, human-like voice interactions for your agents. This guide covers everything from basic text-to-speech to advanced real-time voice conversations, helping you create voice experiences that feel genuinely conversational. ## What is StateSet Voice AI? StateSet Voice AI combines multiple technologies to create seamless voice experiences: * **Speech-to-Text (STT)**: Convert customer speech into text with high accuracy * **Natural Language Understanding**: Process and understand spoken requests * **Text-to-Speech (TTS)**: Generate natural-sounding responses * **Real-time Processing**: Sub-second latency for natural conversations * **Emotion Detection**: Understand and respond to customer sentiment ```mermaid theme={null} graph LR A[Customer Voice] --> B[Speech Recognition] B --> C[StateSet Agent] C --> D[Text Generation] D --> E[Voice Synthesis] E --> F[Customer Hears Response] G[Emotion Detection] --> C H[Context Memory] --> C I[Business Logic] --> C ``` ## Use Cases Replace traditional IVR with intelligent voice agents Enable customers to shop using voice commands Provide voice interfaces for better accessibility ## Getting Started ### Prerequisites 1. StateSet account with Voice AI enabled 2. Node.js 18+ or Python 3.8+ 3. Microphone access (for testing) 4. Voice provider API keys (optional) ### Installation ```bash npm theme={null} npm install StateSet-node @StateSet/voice ``` ```bash yarn theme={null} yarn add StateSet-node @StateSet/voice ``` ```bash pip theme={null} pip install StateSet StateSet-voice ``` ### Quick Setup ```javascript theme={null} import { StateSetClient, VoiceClient } from 'StateSet-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); const voice = new VoiceClient({ apiKey: process.env.STATESET_API_KEY, defaultVoice: 'sarah', // Natural female voice language: 'en-US' }); // Initialize voice agent async function setupVoiceAgent() { const agent = await client.agents.create({ name: 'Voice Assistant', type: 'voice', greeting: 'Hello! How can I help you today?', voice_config: { provider: 'StateSet', // or 'elevenlabs', 'azure', 'google' voice_id: 'sarah', speed: 1.0, pitch: 1.0, emotion: 'friendly' } }); return agent; } ``` ## Voice Synthesis (Text-to-Speech) ### Basic Text-to-Speech ```javascript theme={null} async function textToSpeech(text) { try { const audio = await voice.synthesize({ text: text, voice: 'sarah', format: 'mp3', // or 'wav', 'ogg' options: { speed: 1.0, pitch: 1.0, emphasis: 'moderate' } }); // Play audio in browser const audioUrl = URL.createObjectURL(audio); const audioElement = new Audio(audioUrl); await audioElement.play(); return audio; } catch (error) { logger.error('TTS Error:', error); throw error; } } ``` ### Advanced Voice Synthesis with SSML ```javascript theme={null} async function advancedSynthesis(message, customerEmotion) { // Adjust voice based on customer emotion const voiceParams = getVoiceParameters(customerEmotion); const ssml = ` ${voiceParams.emphasis ? `` : ''} ${message} ${voiceParams.emphasis ? '' : ''} Is there anything else I can help you with? `; const audio = await voice.synthesize({ ssml: ssml, voice: voiceParams.voice, format: 'mp3' }); return audio; } function getVoiceParameters(emotion) { const parameters = { happy: { rate: '1.1', pitch: '+5%', voice: 'sarah', emphasis: 'moderate' }, sad: { rate: '0.9', pitch: '-5%', voice: 'sarah-empathetic' }, angry: { rate: '0.95', pitch: '-2%', voice: 'sarah-calm', emphasis: 'reduced' }, neutral: { rate: '1.0', pitch: '0%', voice: 'sarah' } }; return parameters[emotion] || parameters.neutral; } ``` ### Multi-Provider Voice Support ```javascript theme={null} class VoiceProviderManager { constructor() { this.providers = { StateSet: new StateSetVoice(), elevenlabs: new ElevenLabsVoice(process.env.ELEVENLABS_API_KEY), azure: new AzureVoice(process.env.AZURE_SPEECH_KEY), google: new GoogleVoice(process.env.GOOGLE_CLOUD_KEY) }; } async synthesize(text, options = {}) { const provider = this.providers[options.provider || 'StateSet']; try { const audio = await provider.synthesize(text, options); // Log metrics await this.logUsage({ provider: options.provider, characters: text.length, voice: options.voice, duration: audio.duration }); return audio; } catch (error) { // Fallback to another provider logger.error(`${options.provider} failed:`, error); if (options.provider !== 'StateSet') { return this.synthesize(text, { ...options, provider: 'StateSet' }); } throw error; } } } // ElevenLabs implementation class ElevenLabsVoice { constructor(apiKey) { this.apiKey = apiKey; this.baseUrl = 'https://api.elevenlabs.io/v1'; } async synthesize(text, options) { const response = await fetch( `${this.baseUrl}/text-to-speech/${options.voice_id || 'sarah'}`, { method: 'POST', headers: { 'xi-api-key': this.apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text, model_id: 'eleven_multilingual_v2', voice_settings: { stability: options.stability || 0.75, similarity_boost: options.similarity || 0.75, style: options.style || 0.5, use_speaker_boost: true } }) } ); if (!response.ok) { throw new Error(`ElevenLabs error: ${response.status}`); } const audioBuffer = await response.arrayBuffer(); return new Blob([audioBuffer], { type: 'audio/mpeg' }); } } ``` ## Speech Recognition (Speech-to-Text) ### Basic Speech Recognition ```javascript theme={null} async function speechToText(audioBlob) { try { const transcript = await voice.transcribe({ audio: audioBlob, language: 'en-US', options: { punctuation: true, profanity_filter: false, speaker_diarization: false } }); return { text: transcript.text, confidence: transcript.confidence, words: transcript.words, // Word-level timestamps duration: transcript.duration }; } catch (error) { logger.error('STT Error:', error); throw error; } } ``` ### Real-time Streaming Recognition ```javascript theme={null} class StreamingRecognition { constructor(onTranscript, onFinalTranscript) { this.onTranscript = onTranscript; this.onFinalTranscript = onFinalTranscript; this.stream = null; } async start() { // Get microphone access const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); // Create WebSocket connection for streaming this.ws = new WebSocket('wss://api.StateSet.com/v1/voice/stream'); this.ws.onopen = () => { logger.info('Streaming recognition started'); // Set up audio processing const audioContext = new AudioContext(); const source = audioContext.createMediaStreamSource(stream); const processor = audioContext.createScriptProcessor(4096, 1, 1); processor.onaudioprocess = (e) => { const audioData = e.inputBuffer.getChannelData(0); const int16Array = this.float32ToInt16(audioData); if (this.ws.readyState === WebSocket.OPEN) { this.ws.send(int16Array.buffer); } }; source.connect(processor); processor.connect(audioContext.destination); }; this.ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'transcript') { this.onTranscript(data.transcript); } else if (data.type === 'final') { this.onFinalTranscript(data.transcript); } }; } stop() { if (this.ws) { this.ws.close(); } } float32ToInt16(buffer) { const l = buffer.length; const buf = new Int16Array(l); for (let i = 0; i < l; i++) { buf[i] = Math.min(1, buffer[i]) * 0x7FFF; } return buf; } } // Usage const recognition = new StreamingRecognition( (interim) => logger.info('Interim:', interim);, (final) => logger.info('Final:', final); ); await recognition.start(); ``` ### Advanced Transcription with Speaker Diarization ```javascript theme={null} async function transcribeConversation(audioFile) { const transcript = await voice.transcribe({ audio: audioFile, options: { speaker_diarization: true, max_speakers: 2, punctuation: true, word_timestamps: true, language_detection: true } }); // Format conversation const conversation = transcript.utterances.map(utterance => ({ speaker: utterance.speaker, text: utterance.text, start: utterance.start_time, end: utterance.end_time, confidence: utterance.confidence })); return { conversation, speakers: transcript.speaker_labels, language: transcript.detected_language, summary: await generateSummary(conversation) }; } async function generateSummary(conversation) { const agent = await client.agents.get('summary_agent'); const summary = await agent.process({ task: 'summarize_conversation', conversation: conversation }); return summary; } ``` ## Real-time Voice Conversations ### WebRTC Voice Integration ```javascript theme={null} class VoiceConversation { constructor(agentId) { this.agentId = agentId; this.pc = null; this.localStream = null; } async start() { // Get user's microphone this.localStream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true } }); // Create peer connection this.pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.StateSet.com:3478' }] }); // Add local stream this.localStream.getTracks().forEach(track => { this.pc.addTrack(track, this.localStream); }); // Handle remote stream (agent's voice) this.pc.ontrack = (event) => { const audio = new Audio(); audio.srcObject = event.streams[0]; audio.play(); }; // Create offer const offer = await this.pc.createOffer(); await this.pc.setLocalDescription(offer); // Send offer to server const response = await fetch('/api/voice/connect', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agent_id: this.agentId, offer: offer.sdp }) }); const { answer } = await response.json(); await this.pc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: answer })); } async end() { if (this.localStream) { this.localStream.getTracks().forEach(track => track.stop()); } if (this.pc) { this.pc.close(); } } } ``` ### Voice Activity Detection (VAD) ```javascript theme={null} class VoiceActivityDetector { constructor(onSpeechStart, onSpeechEnd) { this.onSpeechStart = onSpeechStart; this.onSpeechEnd = onSpeechEnd; this.isListening = false; this.audioContext = null; this.analyser = null; } async init(stream) { this.audioContext = new AudioContext(); const source = this.audioContext.createMediaStreamSource(stream); this.analyser = this.audioContext.createAnalyser(); this.analyser.fftSize = 2048; this.analyser.smoothingTimeConstant = 0.8; source.connect(this.analyser); const bufferLength = this.analyser.frequencyBinCount; const dataArray = new Uint8Array(bufferLength); let speechStartTime = null; let silenceStartTime = null; const speechThreshold = 30; const silenceThreshold = 20; const speechDebounce = 200; // ms const silenceDebounce = 1500; // ms const checkAudioLevel = () => { if (!this.isListening) return; this.analyser.getByteFrequencyData(dataArray); const average = dataArray.reduce((a, b) => a + b) / bufferLength; if (average > speechThreshold) { if (!speechStartTime) { speechStartTime = Date.now(); } else if (Date.now() - speechStartTime > speechDebounce) { this.onSpeechStart(); silenceStartTime = null; } } else if (average < silenceThreshold) { speechStartTime = null; if (!silenceStartTime) { silenceStartTime = Date.now(); } else if (Date.now() - silenceStartTime > silenceDebounce) { this.onSpeechEnd(); } } requestAnimationFrame(checkAudioLevel); }; this.isListening = true; checkAudioLevel(); } stop() { this.isListening = false; if (this.audioContext) { this.audioContext.close(); } } } ``` ## Voice Agent Configuration ### Creating a Voice-Enabled Agent ```javascript theme={null} async function createVoiceAgent() { const agent = await client.agents.create({ name: 'Voice Customer Service', type: 'voice', description: 'Handles phone and voice chat support', voice_config: { // Voice selection primary_voice: { provider: 'elevenlabs', voice_id: 'sarah_professional', language: 'en-US' }, fallback_voice: { provider: 'StateSet', voice_id: 'sarah', language: 'en-US' }, // Speech parameters speech: { speed: 1.0, pitch: 1.0, volume: 0.9, emotion_adaptation: true }, // Recognition parameters recognition: { language: 'en-US', alternatives: 3, profanity_filter: true, word_confidence: true, automatic_punctuation: true }, // Conversation settings conversation: { interrupt_sensitivity: 'medium', end_of_speech_timeout: 2000, background_noise_suppression: true, echo_cancellation: true } }, // Voice-specific behaviors behaviors: { greeting: { text: "Hello! Thank you for calling. How can I help you today?", emotion: "friendly", pause_after: 500 }, listening_indicators: [ "Mhm", "I see", "Got it", "Okay" ], clarification_phrases: [ "I'm sorry, could you repeat that?", "I didn't quite catch that. Could you say it again?", "Let me make sure I understood correctly..." ], hold_music: { enabled: true, music_url: "https://cdn.StateSet.com/hold-music-calm.mp3", check_in_interval: 30000, check_in_message: "Thank you for waiting. I'm still working on that for you." } } }); return agent; } ``` ### Voice Personality Configuration ```javascript theme={null} const voicePersonalities = { professional: { voice: 'sarah_professional', speech_rate: 0.95, pitch: 0, style: { formality: 'high', enthusiasm: 'moderate', empathy: 'high' }, vocabulary: { greeting: "Good [morning/afternoon/evening]. Thank you for contacting us.", acknowledgment: "I understand your concern.", closing: "Is there anything else I can assist you with today?" } }, friendly: { voice: 'alex_casual', speech_rate: 1.05, pitch: '+2%', style: { formality: 'low', enthusiasm: 'high', empathy: 'high' }, vocabulary: { greeting: "Hey there! How's it going?", acknowledgment: "Oh, I totally get that!", closing: "Anything else I can help you with?" } }, empathetic: { voice: 'sarah_empathetic', speech_rate: 0.9, pitch: '-2%', style: { formality: 'moderate', enthusiasm: 'low', empathy: 'very_high' }, vocabulary: { greeting: "Hello, I'm here to help you today.", acknowledgment: "I can understand how frustrating that must be.", closing: "Please don't hesitate to reach out if you need anything else." } } }; // Apply personality based on context async function applyVoicePersonality(agent, context) { const personality = determinePersonality(context); await agent.updateVoiceConfig({ voice: personality.voice, speech: { rate: personality.speech_rate, pitch: personality.pitch }, style: personality.style }); } function determinePersonality(context) { if (context.customer_sentiment === 'angry' || context.issue_severity === 'high') { return voicePersonalities.empathetic; } else if (context.customer_type === 'business' || context.formal_request) { return voicePersonalities.professional; } else { return voicePersonalities.friendly; } } ``` ## Phone System Integration ### Twilio Integration ```javascript theme={null} import twilio from 'twilio'; class PhoneVoiceAgent { constructor(config) { this.twilioClient = twilio( config.accountSid, config.authToken ); this.StateSetAgent = config.agent; } async handleIncomingCall(req, res) { const twiml = new twilio.twiml.VoiceResponse(); // Initial greeting const gather = twiml.gather({ input: 'speech', timeout: 3, speechTimeout: 'auto', action: '/voice/process', method: 'POST' }); gather.say({ voice: 'Polly.Joanna' }, "Hello! I'm your AI assistant. How can I help you today?"); res.type('text/xml'); res.send(twiml.toString()); } async processVoiceInput(req, res) { const speechResult = req.body.SpeechResult; const callSid = req.body.CallSid; try { // Process with StateSet agent const response = await this.StateSetAgent.process({ input: speechResult, context: { channel: 'phone', call_sid: callSid, caller: req.body.From } }); // Generate voice response const twiml = new twilio.twiml.VoiceResponse(); if (response.action === 'transfer') { twiml.dial(response.transfer_to); } else { const gather = twiml.gather({ input: 'speech', timeout: 3, action: '/voice/process', method: 'POST' }); gather.say({ voice: 'Polly.Joanna' }, response.message); } res.type('text/xml'); res.send(twiml.toString()); } catch (error) { logger.error('Voice processing error:', error); const twiml = new twilio.twiml.VoiceResponse(); twiml.say("I'm sorry, I'm having trouble understanding. Let me transfer you to a human agent."); twiml.dial(process.env.FALLBACK_PHONE_NUMBER); res.type('text/xml'); res.send(twiml.toString()); } } } ``` ## Voice Analytics ### Conversation Analytics ```javascript theme={null} class VoiceAnalytics { async analyzeConversation(conversationId) { const conversation = await client.conversations.get(conversationId); const analytics = { // Basic metrics duration: conversation.duration, speaker_ratio: this.calculateSpeakerRatio(conversation), // Sentiment analysis sentiment_timeline: await this.analyzeSentimentProgression(conversation), emotion_detection: await this.detectEmotions(conversation), // Conversation quality interruptions: this.countInterruptions(conversation), silence_periods: this.analyzeSilence(conversation), speech_pace: this.analyzeSpeechPace(conversation), // Content analysis keywords: await this.extractKeywords(conversation), topics: await this.identifyTopics(conversation), action_items: await this.extractActionItems(conversation), // Performance metrics response_times: this.calculateResponseTimes(conversation), resolution_achieved: conversation.metadata.resolved, escalation_needed: conversation.metadata.escalated }; return analytics; } calculateSpeakerRatio(conversation) { const speakerDurations = {}; conversation.utterances.forEach(utterance => { const speaker = utterance.speaker; const duration = utterance.end_time - utterance.start_time; speakerDurations[speaker] = (speakerDurations[speaker] || 0) + duration; }); const total = Object.values(speakerDurations).reduce((a, b) => a + b, 0); return Object.entries(speakerDurations).reduce((acc, [speaker, duration]) => { acc[speaker] = (duration / total * 100).toFixed(1) + '%'; return acc; }, {}); } async analyzeSentimentProgression(conversation) { const timeline = []; for (const utterance of conversation.utterances) { const sentiment = await this.analyzeSentiment(utterance.text); timeline.push({ time: utterance.start_time, speaker: utterance.speaker, sentiment: sentiment.score, magnitude: sentiment.magnitude }); } return timeline; } } ``` ## Best Practices ### 1. Natural Conversation Flow ```javascript theme={null} // Good: Natural interruption handling const naturalConversation = { allow_interruptions: true, interruption_threshold: 0.7, // Confidence level handle_interruption: async (context) => { // Gracefully stop speaking await voice.stopSpeaking(); // Acknowledge interruption await voice.speak("Oh, sorry, go ahead!"); // Listen for their input return await voice.listen(); } }; // Bad: Rigid turn-taking const rigidConversation = { allow_interruptions: false, force_complete_utterances: true }; ``` ### 2. Error Recovery ```javascript theme={null} class VoiceErrorHandler { async handle(error, context) { switch (error.type) { case 'recognition_failed': return this.handleRecognitionError(context); case 'synthesis_failed': return this.handleSynthesisError(context); case 'network_error': return this.handleNetworkError(context); default: return this.handleGenericError(context); } } async handleRecognitionError(context) { const responses = [ "I'm sorry, I didn't catch that. Could you repeat it?", "There seems to be some background noise. Could you speak up a bit?", "I'm having trouble hearing you clearly. Can you try again?" ]; // Use appropriate response based on context const response = this.selectResponse(responses, context); return { action: 'retry', message: response, adjustments: { noise_suppression: 'aggressive', gain_control: 1.2 } }; } } ``` ### 3. Performance Optimization ```javascript theme={null} class VoiceOptimizer { constructor() { this.cache = new Map(); this.preloadCommonPhrases(); } async preloadCommonPhrases() { const commonPhrases = [ "How can I help you today?", "Let me look that up for you.", "One moment please.", "Is there anything else?" ]; for (const phrase of commonPhrases) { const audio = await voice.synthesize({ text: phrase }); this.cache.set(phrase, audio); } } async speak(text) { // Check cache first if (this.cache.has(text)) { return this.cache.get(text); } // Generate and cache const audio = await voice.synthesize({ text }); // Cache if under size limit if (audio.size < 1000000) { // 1MB this.cache.set(text, audio); } return audio; } } ``` ## Troubleshooting ### Common Issues 1. **Audio Quality Problems** * Enable noise suppression and echo cancellation * Check microphone quality and positioning * Adjust gain control settings 2. **High Latency** * Use regional endpoints * Implement response streaming * Pre-generate common responses 3. **Recognition Accuracy** * Provide vocabulary hints * Use appropriate language models * Implement confidence thresholds 4. **Unnatural Speech** * Adjust prosody parameters * Use SSML for better control * Select appropriate voice models ## Next Steps Best practices for conversational voice interfaces Support multiple languages in voice interactions *** **Pro Tip**: Always test voice interactions with real users in various environments. Background noise, accents, and speaking styles can significantly impact performance. For voice demos and support, visit [voice.StateSet.com](https://voice.StateSet.com) or contact [support@StateSet.com](mailto:support@StateSet.com). # Warehouse Quickstart Source: https://docs.stateset.com/guides/warehouse-quickstart Get started with the StateSet Warehouse Management API for efficient warehouse operations. # StateSet Warehouse Management Quickstart: Optimize Your Operations Imagine you're running a busy warehouse. You're dealing with countless inventory items, complex receiving processes, and a never-ending flow of orders. How do you ensure accuracy, efficiency, and smooth operations while minimizing costs and errors? StateSet's Warehouse Management API provides the tools you need to address these challenges. This guide will walk you through the essentials of using StateSet to: * **Manage Inventory:** Keep accurate track of your stock levels and locations. * **Optimize Warehouse Layout:** Design an efficient layout that minimizes travel time. * **Streamline Receiving:** Handle incoming shipments smoothly and accurately. * **Improve Order Fulfillment:** Optimize picking, packing, and shipping processes. * **Handle Returns:** Process returns efficiently and minimize disruptions. ## Table of Contents 1. [The Importance of Efficient Warehouse Management](#the-importance-of-efficient-warehouse-management) 2. [Getting Started with StateSet](#getting-started-with-StateSet) * [Account Setup](#1-account-setup) * [SDK Installation](#2-sdk-installation) * [Client Initialization](#3-client-initialization) 3. [Core Concepts: The Fundamentals of Warehouse Operations](#core-concepts-the-fundamentals-of-warehouse-operations) * [Inventory Management](#inventory-management) * [Warehouse Layout and Slotting](#warehouse-layout-and-slotting) 4. [Streamlining Key Processes with StateSet](#streamlining-key-processes-with-StateSet) * [Receiving Process](#receiving-process) * [Pick, Pack, and Ship Processes](#pick-pack-and-ship-processes) * [Returns Management](#returns-management) 5. [Advanced Warehouse Optimization Techniques](#advanced-warehouse-optimization-techniques) * [ABC Analysis for Inventory](#abc-analysis-for-inventory) * [Cross-Docking for Fast-Moving Items](#cross-docking-for-fast-moving-items) * [Wave Picking for Order Efficiency](#wave-picking-for-order-efficiency) 6. [Key Integrations for a Seamless System](#key-integrations-for-a-seamless-system) 7. [Essential Considerations](#essential-considerations) * [Error Handling and Logging](#error-handling-and-logging) * [Real-time Monitoring](#real-time-monitoring) * [Security Best Practices](#security-best-practices) 8. [Troubleshooting & Support](#troubleshooting--support) 9. [Quick Links](#quick-links) *** ## 1. The Importance of Efficient Warehouse Management Before we dive in, it's essential to understand why warehouse management is so critical for your business: * **Inventory Accuracy:** Without accurate inventory tracking, you risk stockouts or overstocking, leading to lost sales and higher costs. * **Order Fulfillment:** Slow or inaccurate order fulfillment results in customer dissatisfaction and potential revenue loss. * **Space Utilization:** Inefficient warehouse layouts can waste valuable space, increasing your overhead costs. * **Labor Efficiency:** Optimized processes can significantly reduce labor costs, improve worker morale and throughput. * **Returns Processing:** Without a clear returns management system, you can lose track of inventory and potentially incur additional losses. StateSet provides the tools you need to overcome these challenges, optimize your operations, and keep your warehouse running smoothly. *** ## 2. Getting Started with StateSet Let's get your environment set up so you can start using the StateSet Warehouse Management API. ### 1. Account Setup First, you need a StateSet account and an API key. 1. **Sign Up:** Visit [StateSet.com/sign-up](https://StateSet.com/sign-up) to create your free account. 2. **Access Cloud Console:** After signing in, go to the [StateSet Cloud Console](https://cloud.StateSet.com/api-keys). 3. **Generate API key:** Create a new API key—you'll use this to authenticate your API requests. ### 2. SDK Installation Next, install the StateSet Node.js SDK to simplify interactions with the API. **Using npm:** ```bash theme={null} npm install StateSet-node ``` **Using yarn:** ```bash theme={null} yarn add StateSet-node ``` ### 3. Client Initialization Finally, initialize the StateSet client in your application using your API key. ```javascript theme={null} import { StateSet } from 'StateSet-node'; const client = new StateSet(process.env.STATESET_API_KEY); // Verify connection async function verifyConnection() { try { const status = await client.system.healthCheck(); logger.info('Connection status:', status); } catch (error) { logger.error('Failed to connect:', error); } } verifyConnection(); ``` **Actionable Next Step:** Ensure your API key is properly configured and your client connection is successful. *** ## 3. Core Concepts: The Fundamentals of Warehouse Operations Before diving into the specifics, let's cover the basic concepts that form the core of warehouse operations. ### Inventory Management Inventory management involves tracking stock levels, maintaining accurate records, and managing items efficiently. Here’s how it works in StateSet: First, you add an item to your system, this includes a unique identifier, name, dimensions, and other details: ```javascript theme={null} async function createItem() { try { const newItem = await client.inventoryItems.create({ sku: 'WIDGET-001', name: 'Premium Widget', description: 'High-quality widget for various applications', category: 'Widgets', unit_of_measure: 'EA', weight: 0.5, dimensions: { length: 10, width: 5, height: 2 } }); logger.info('New item created:', newItem); } catch (error) { logger.error('Failed to create item:', error); } } createItem(); ``` Next, you can update the quantity of this item at a specific location: ```javascript theme={null} const updatedItem = await client.inventoryItems.updateQuantity(newItem.id, { quantity: 100, location_id: 'loc_A1' }); logger.info('Item quantity updated:', updatedItem); ``` **Benefits of inventory management with StateSet:** * Accurate real-time tracking of your inventory. * Easily update stock levels, locations, and other details. * Reduced risk of stockouts and overstocking. **Actionable Next Step:** Try creating your first inventory item using the code above. For more detailed information on inventory management, see the [Inventory Quickstart](/guides/inventory-quickstart). ### Warehouse Layout and Slotting Warehouse layout and slotting define how items are stored in your warehouse. This includes the location, how much can be stored there, and what type of area it is: ```javascript theme={null} const newLocation = await client.storageLocations.create({ name: 'A1-01', type: 'SHELF', zone: 'PICKING', capacity: { units: 100, weight: 50 } }); logger.info('New storage location created:', newLocation); ``` You can also use StateSet to help optimize your slotting, this is a process that takes into account historical data to make recommendations on where each item should go: ```javascript theme={null} const slottingPlan = await client.warehouse.optimizeSlotting({ optimization_criteria: ['pick_frequency', 'item_affinity'] }); logger.info('Slotting plan:', slottingPlan); ``` **Benefits of optimized slotting:** * Reduced travel time for picking orders. * Maximized use of available space. * Improved picking accuracy. **Actionable Next Step:** Explore creating storage locations and optimizing your warehouse slotting. *** ## 4. Streamlining Key Processes with StateSet Now, let's explore how StateSet can help with various key processes in your warehouse. ### Receiving Process The receiving process involves the handling of incoming shipments, counting and verifying items, and putting them away. Here's how you can do it with StateSet: ```javascript theme={null} const receivingOrder = await client.receivingOrders.create({ supplier_id: 'sup_123', expected_delivery_date: '2024-10-01', items: [ { sku: 'WIDGET-001', expected_quantity: 500 } ] }); logger.info('Receiving order created:', receivingOrder); ``` Next, record the items you actually received: ```javascript theme={null} const receivedItems = await client.receivingOrders.recordReceivedItems(receivingOrder.id, { items: [ { sku: 'WIDGET-001', received_quantity: 498, location_id: 'loc_A1' } ] }); logger.info('Received items recorded:', receivedItems); ``` **Benefits of using StateSet for receiving:** * Track incoming shipments effectively. * Record received items accurately and efficiently. * Reduce errors and time spent on manual processes. **Actionable Next Step:** Try creating a new receiving order and record the received items. See also: [Supplier Quickstart](/guides/supplier-quickstart) for managing suppliers. ### Pick, Pack, and Ship Processes The pick, pack, and ship processes are fundamental to order fulfillment. Here's how you can do it in StateSet: First, you create a pick order: ```javascript theme={null} const pickOrder = await client.pickOrders.create({ order_id: 'ord_456', items: [ { sku: 'WIDGET-001', quantity: 5 } ] }); logger.info('Pick order created:', pickOrder); ``` Next, you record the picked items: ```javascript theme={null} const pickedItems = await client.pickOrders.recordPickedItems(pickOrder.id, { items: [ { sku: 'WIDGET-001', picked_quantity: 5, location_id: 'loc_A1' } ] }); logger.info('Picked items recorded:', pickedItems); ``` Now, you create a packing list for the picked items: ```javascript theme={null} const packingList = await client.packingLists.create({ pick_order_id: pickOrder.id, items: pickedItems }); logger.info('Packing list created:', packingList); ``` Finally, you create a shipment to be sent out: ```javascript theme={null} const shipment = await client.shipments.create({ packing_list_id: packingList.id, carrier: 'UPS', service_level: 'GROUND', tracking_number: '1Z999AA1234567890' }); logger.info('Shipment created:', shipment); ``` **Benefits of using StateSet for pick, pack, and ship:** * Track order fulfillment progress. * Optimize pick paths to save time. * Create shipping documentation quickly and easily. **Actionable Next Step:** Create pick orders and walk through the pick, pack, and ship process. For more on orders, see [Orders Quickstart](/guides/orders-quickstart). ### Returns Management Handling returns efficiently is essential for customer satisfaction and inventory management. Here's a basic example of how you can initiate a return in StateSet: ```javascript theme={null} // Create a return order const returnOrder = await client.returnOrders.create({ order_id: 'ord_456', items: [ { sku: 'WIDGET-001', quantity: 1, reason: 'Damaged' } ] }); logger.info('Return order created:', returnOrder); ``` Once a return is created, you can approve it: ```javascript theme={null} // Approve the return const approvedReturn = await client.returnOrders.approve(returnOrder.id); logger.info('Return approved:', approvedReturn); ``` After processing, close the return: ```javascript theme={null} // Close the return const closedReturn = await client.returnOrders.close(returnOrder.id); logger.info('Return closed:', closedReturn); ``` **Benefits of using StateSet for returns:** * Easily track returns from customers. * Maintain accurate inventory records. * Streamline return processes. **Actionable Next Step:** Simulate a product return using the example code above. For comprehensive returns handling, refer to the [Returns Quickstart](/guides/returns-quickstart). *** ## 5. Advanced Warehouse Optimization Techniques Now that you've explored the basic processes, let's look at some advanced optimization techniques. ### ABC Analysis for Inventory ABC analysis helps categorize items based on their value and pick frequency. This helps you optimize storage locations. ```javascript theme={null} async function performABCAnalysis() { const items = await client.inventoryItems.list({ limit: 1000 }); const totalValue = items.reduce((sum, item) => sum + item.value * item.quantity, 0); const totalPicks = items.reduce((sum, item) => sum + item.pick_frequency, 0); const categorizedItems = items.map(item => ({ ...item, value_score: (item.value * item.quantity) / totalValue, pick_score: item.pick_frequency / totalPicks })).sort((a, b) => b.value_score + b.pick_score - (a.value_score + a.pick_score)); let cumulativeScore = 0; const abcCategories = categorizedItems.map(item => { cumulativeScore += item.value_score + item.pick_score; if (cumulativeScore <= 0.8) return { ...item, category: 'A' }; if (cumulativeScore <= 0.95) return { ...item, category: 'B' }; return { ...item, category: 'C' }; }); // Update items with their ABC category for (const item of abcCategories) { await client.inventoryItems.update(item.id, { abc_category: item.category }); } return abcCategories; } const abcResults = await performABCAnalysis(); logger.info('ABC Analysis complete:', abcResults); ``` **Benefit:** * Improves warehouse organization and efficiency by prioritizing high-value, frequently picked items. **Actionable Next Step:** Implement and review the results of your ABC analysis. ### Cross-Docking for Fast-Moving Items Cross-docking minimizes storage time for high-demand items by moving them directly from receiving to shipping. ```javascript theme={null} async function setupCrossDocking(receivingOrderId) { const receivingOrder = await client.receivingOrders.get(receivingOrderId); const crossDockItems = receivingOrder.items.filter(item => item.cross_dock_eligible); if (crossDockItems.length > 0) { const crossDockOrder = await client.crossDockOrders.create({ receiving_order_id: receivingOrderId, items: crossDockItems }); // Assign cross-dock items to pending shipments await assignCrossDockItemsToShipments(crossDockOrder); } } async function assignCrossDockItemsToShipments(crossDockOrder) { const pendingShipments = await client.shipments.list({ status: 'PENDING' }); for (const item of crossDockOrder.items) { const matchingShipment = pendingShipments.find(shipment => shipment.items.some(shipmentItem => shipmentItem.sku === item.sku) ); if (matchingShipment) { await client.shipments.update(matchingShipment.id, { items: matchingShipment.items.map(shipmentItem => shipmentItem.sku === item.sku ? { ...shipmentItem, cross_dock: true, location_id: crossDockOrder.id } : shipmentItem ) }); } } } const crossDockingResults = await setupCrossDocking('rec_123'); logger.info('Cross docking setup completed:', crossDockingResults); ``` **Benefit:** * Reduces storage time, speeds up order fulfillment, and minimizes handling costs. **Actionable Next Step:** Set up cross-docking for applicable items. ### Wave Picking for Order Efficiency Wave picking involves grouping multiple orders into waves for more efficient picking, reducing the time spent in travel: ```javascript theme={null} async function createPickingWave() { const pendingOrders = await client.orders.list({ status: 'PENDING', limit: 50 }); const wave = await client.pickingWaves.create({ orders: pendingOrders.map(order => order.id) }); const optimizedPickPath = await client.warehouse.optimizePickPath(wave.id); return { wave, optimizedPickPath }; } async function processPickingWave(waveId) { const wave = await client.pickingWaves.get(waveId); for (const orderId of wave.orders) { const pickedItems = await pickOrderItems(orderId); await createPackingList(orderId, pickedItems); } await client.pickingWaves.complete(waveId); } const wavePickingResults = await createPickingWave(); logger.info("Wave picking created:", wavePickingResults); ``` **Benefit:** * Improves picker efficiency, reduces travel time, and increases overall throughput. **Actionable Next Step:** Start implementing wave picking for your orders. *** ## 6. Key Integrations for a Seamless System To maximize the benefits of StateSet, consider integrating it with other systems: * **E-Commerce Platforms:** Integrate with platforms like Shopify, Magento, or WooCommerce for automatic order syncing. See [Shopify Quickstart](/guides/shopify-quickstart). * **ERP Systems:** Connect with your ERP system for centralized data management. * **Carrier APIs:** Integrate with carriers like UPS, FedEx, or USPS for real-time shipping updates. * **WMS Systems:** Connect with other Warehouse Management Systems if you need more specialized functionality. For specific integrations, check out our integration guides such as [Shopify Quickstart](/guides/shopify-quickstart) and [Gorgias Quickstart](/guides/gorgias-quickstart). *** ## 7. Essential Considerations ### Error Handling and Logging * Implement `try-catch` blocks around API calls to handle potential errors. * Log errors for analysis and debugging. * Set up alerts for critical errors to notify you immediately. ### Real-time Monitoring * Use StateSet’s webhook functionality to get real-time updates on warehouse events. * Monitor inventory changes, order progress, and other key metrics. ### Security Best Practices * Store API keys securely, using environment variables or secret managers. * Follow best practices for protecting your application and data. *** ## 8. Troubleshooting & Support If you have issues or questions, check these resources: * **StateSet API Documentation:** [https://docs.StateSet.com/api-reference](https://docs.StateSet.com/api-reference) * **StateSet Community:** [https://StateSet.com/community](https://StateSet.com/community) * **Support Email:** [support@StateSet.com](mailto:support@StateSet.com) ## 9. Quick Links * 📚 [API Documentation](https://docs.StateSet.com/api-reference) * ☁️ [Cloud Console](https://cloud.StateSet.com/api-keys) * 📝 [Sign Up](https://StateSet.com/sign-up) * 💬 [Community](https://StateSet.com/community) * 🎥 [Tutorials](https://docs.StateSet.com/tutorials) * 📧 **Support Email**: [support@StateSet.com](mailto:support@StateSet.com) *** By following this quickstart guide, you are now equipped to use StateSet to optimize your warehouse operations. Explore the documentation and integrate with other systems to build a powerful, efficient warehouse management solution. # Warranties Quickstart Source: https://docs.stateset.com/guides/warranties-quickstart Getting started with the StateSet Warranty API StateSet One provides a REST and GraphQL API for Warranty Management. The Warranty Management module in StateSet includes various objects that facilitate replacement processes. These objects typically encompass: * Warranty * Warranty Line Items * Redemptions * Orders * Shipments ### Warranty Management Overview Warranty Management is a process that helps businesses manage their warranties. It involves tracking the status of warranties, processing claims, and providing customer support. StateSet's Warranty Management solution automates the entire warranty process, from generating warranty labels to processing claims. This helps in streamlining the process and reducing the time and effort required to manage warranties. The solution leverages the Temporal workflow orchestration framework to automate the various steps involved in warranty management. This includes generating and emailing warranty labels, creating warranties in StateSet, providing search capabilities for efficient record retrieval, updating customer support platforms with tracking information, and processing instant refunds. By automating the warranty process, StateSet enables businesses to effectively manage and track warranties, thereby enhancing customer experience and improving operational efficiency. #### Challenges with Warranties Management Warranty Management is a complex process that involves multiple steps and stakeholders. This makes it difficult for businesses to effectively manage and track warranties. Some of the key challenges include: #### StateSet's Warranty Management Solution StateSet's Warranty Management solution automates the entire warranty process, from generating warranty labels to processing claims. This helps in streamlining the process and reducing the time and effort required to manage warranties. The solution leverages the Temporal workflow orchestration framework to automate the various steps involved in warranty management. This includes generating and emailing warranty labels, creating warranties in StateSet, providing search capabilities for efficient record retrieval, updating customer support platforms with tracking information, and processing instant refunds. By automating the warranty process, StateSet enables businesses to effectively manage and track warranties, thereby enhancing customer experience and improving operational efficiency. ### Quickstart Guide 1. Setup your company's StateSet One instance by signing up at StateSet.com/sign-up 2. Create a new API key in the StateSet Cloud Console cloud.StateSet.com/api-keys 3. Install the StateSet-node SDK in your project: ```jsx theme={null} npm install StateSet-node ``` 4. Create a new Warranty ```jsx theme={null} import { StateSet } from 'StateSet-node'('API_KEY'); const warranty = await StateSet.warranties.create({ id: 'W-123313', order_id: 'O-12332312', serial_number: 'st123976879tm', 'description:' 'Warranty Replacement for different type', 'status': 'NEW' 'reported_condition': 'A', 'tracking_number': '132908231098120921', 'zendesk_number': '123313', 'action_needed': 'Replacement' 'rma': 'W-123312', 'country': 'US', warranty_line_items: [ {id: 'WI-232133223'}, ], }); ``` 5. Approve Warranty Once a Warranty is approved a replacement order will be created in your store. ```jsx theme={null} import { StateSet } from 'StateSet-node'('API_KEY'); const warranty = await StateSet.warranties.approve( 'W-123313' ); ``` ### Advanced Warranty Automation using Temporal ```jsx javascript theme={null} import { condition, proxyActivities } from '@temporalio/workflow'; import * as wf from '@temporalio/workflow'; const { userReturnedProduct, createZendeskComment, voidInvoice, updateWarranty, updateWorkflowId } = proxyActivities({ startToCloseTimeout: '1 minute', }); /** A workflow that simply calls an activity */ export async function warrantyConditionUpdatedWorkflow(body, zendesk_number) { let workflow_state = []; var condition = _condition; var replacement_order_created = _replacement_order_created; var ticket_id_int = zendesk_number; if ((replacement_order_created == true && condition == "A") || (replacement_order_created == true && condition == "B") || (replacement_order_created == true && condition == "C")) { // Void Invoice await voidInvoice(customer_email); // Create Zendesk Comment await createZendeskComment(ticket_id_int); } else if ((replacement_order_created == true && condition == "F")) { // Create Zendesk Comment await createZendeskComment(ticket_id_int); } await userReturnedProduct(customer_email); // Update Warranty var warranty_id = await updateWarranty(); // Update Workflow Id await updateWorkflowId(warranty_id, wf.workflowInfo().workflowId); return 'updated' } ``` ### Warranties Support If you have any questions or need help, please contact us at: [support@StateSet.com](mailto:support@StateSet.com) # Warranty Vision Workflow User Guide Source: https://docs.stateset.com/guides/warranty-vision-guide Understanding and using the StateSet warranty process with Vision API. # Warranty Workflow Guide **Last Updated:** January 16, 2025 ## Table of Contents 1. [Introduction](#introduction) 2. [High-Level Workflow](#high-level-workflow) 3. [Detailed Process Steps](#detailed-process-steps) * [1. Warranty Claim Creation in Zendesk](#1-warranty-claim-creation-in-zendesk) * [2. Data Sent to StateSet via Webhook](#2-data-sent-to-StateSet-via-webhook) * [3. Data Processing in StateSet](#3-data-processing-in-StateSet) * [4. Address Verification](#4-address-verification) * [5. ShipStation Order Creation](#5-shipstation-order-creation) * [6. StateSet Warranty Record Creation](#6-StateSet-warranty-record-creation) * [7. AI-Driven Product and Issue Identification](#7-ai-driven-product-and-issue-identification) * [8. Zendesk Ticket Updates](#8-zendesk-ticket-updates) 4. [Troubleshooting & Common Issues](#troubleshooting--common-issues) 5. [Best Practices and Tips](#best-practices-and-tips) 6. [Appendix: Technical Implementation](#appendix-technical-implementation) * [Zendesk Signature Validation](#zendesk-signature-validation) * [Logging Errors in StateSet](#logging-errors-in-StateSet) * [Creating a Ship-To Address Record](#creating-a-ship-to-address-record) * [Checking for Duplicate Orders in ShipStation](#checking-for-duplicate-orders-in-shipstation) * [Creating ShipStation Orders](#creating-shipstation-orders) * [StateSet Warranty Record: Create and Update](#StateSet-warranty-record-create-and-update) * [AI Function Calls Overview](#ai-function-calls-overview) * [Updating Zendesk](#updating-zendesk) * [Address Verification (Google Address Validation API)](#address-verification-google-address-validation-api) * [Image Analysis for Brand, Model, and Accessories](#image-analysis-for-brand-model-and-accessories) *** ## Introduction Manages warranty claims through a multi-system integration involving Zendesk, ShipStation, and StateSet. * **Zendesk** is used to create and track customer support tickets. * **StateSet** orchestrates the workflow, including data normalization, AI-driven analysis, and record-keeping. * **ShipStation** automates order creation, shipping label generation, and delivery tracking. This document aims to help you understand how data flows between these platforms, how to handle exceptions, and how to customize or troubleshoot the system. *** ## High-Level Workflow 1. **Customer Submits Warranty Claim**\ A customer contacts via a Zendesk support form or email, providing details and any attachments (e.g., product images). 2. **Data Transferred to StateSet**\ Zendesk, via a webhook, sends the warranty ticket data to StateSet for processing. 3. **StateSet Processes Data** * **Normalization**: StateSet consolidates the ticket data, customer information, and product details. * **Address Verification**: An external service (Google Address Validation) verifies or corrects the shipping address. * **AI Analysis**: The system uses OpenAI’s Vision API for brand/model identification, accessories detection, and issue code determination. 4. **Order Creation in ShipStation**\ StateSet automatically creates a new replacement order in ShipStation with an RMA number. ShipStation returns a unique `shipstation_order_id`. 5. **Warranty Record Management in StateSet**\ A new or updated “warranty” record is created in StateSet, storing all relevant info: * RMA number * Original order ID * Product/issue details * ShipStation order ID * Customer details * AI analysis outputs (defective item, issue code, brand) 6. **Zendesk Ticket Updates**\ StateSet updates the Zendesk ticket with: * A private note (internal) * Custom fields (defective item, quantity, issue code) * A customer-facing message 7. **Fulfillment and Shipment**\ ShipStation processes the replacement order and generates shipment details. Communication continues via Zendesk if needed. *** ## Detailed Process Steps ### 1. Warranty Claim Creation in Zendesk The customer’s first step is to open a new ticket, either by: * Filling out a warranty form that leads to a Zendesk ticket. * Sending an email to support email, which is captured by Zendesk. **Key Fields in Zendesk Ticket:** * **Subject**: General summary of the issue or complaint. * **Description**: Full text of the customer’s issue, often containing production codes or details about leaks, defects, etc. * **Attachments**: Photos or videos demonstrating the defect or product type. ### 2. Data Sent to StateSet via Webhook Once the ticket is created in Zendesk: 1. A **Webhook** is triggered in Zendesk with the ticket data. 2. The **Webhook** targets a StateSet endpoint that begins the warranty workflow. **Zendesk Signature Validation** ensures that the incoming request is authentic (see [Appendix](#zendesk-signature-validation)). ### 3. Data Processing in StateSet **StateSet** receives the payload and extracts or normalizes relevant data into a standardized format: * **Zendesk Ticket Data** * `ticket_id` * `order_id` (if the customer has it) * `subject` * `description` * `image_description` (analysis from attached images) * **Customer Data** * `customer_email`, `billing_email` * Name, address (street, city, state, zip, country) * `phone` * **Product Data** * `product` * `quantity` * `volume` * `color` * `defective_product` * `defective_quantity` * `warranty_issue` ### 4. Address Verification Before creating an order, StateSet checks the customer’s address via an external service (Google Address Validation). * If verification is successful, the normalized address fields (`verified_address_street`, `verified_address_city`, etc.) are used. * If no verified address is found, the workflow reverts to the original address fields, but a note may be logged indicating a potential address mismatch. ### 5. ShipStation Order Creation Using the verified address and product info, StateSet calls the **ShipStation API** to create a “Replacement Order” under a unique RMA number (`W-`). * **Unique RMA Check**: The system queries ShipStation to see if an order with the same RMA already exists. If so, the new order creation is skipped to avoid duplicates. If successful, ShipStation responds with a `shipstation_order_id`. This indicates the order is queued for fulfillment. If unsuccessful, StateSet logs an error and halts further processing. ### 6. StateSet Warranty Record Creation Next, a **Warranty Record** is created (or updated) in StateSet’s database. This record includes: * **Identifiers**: `id` (Zendesk ticket number), `order_id` (original if known), `rma` (replacement order RMA) * **ShipStation**: `shipstation_order_id` * **Timestamps**: `created_date` * **Status**: E.g., `NEW`, or any subsequent statuses (like `IN_PROGRESS`, `COMPLETED`). * **Customer**: `customerEmail`, `first_name`, `last_name`, address fields * **AI Output**: `defective_item`, `issue_code` ### 7. AI-Driven Product and Issue Identification To streamline data entry and reduce manual guesswork, the system may use **OpenAI’s** API to interpret: 1. **Brand Determination** 2. **Model and Volume** 3. **Accessory Detection** 4. **Issue Codes** **How it Works** * The AI model looks at text descriptions and/or images. * Custom function calls in the StateSet backend parse out the brand, product SKU, or accessories needed. * If the AI is uncertain, it may default to `unknown`, prompting manual intervention. ### 8. Zendesk Ticket Updates Finally, StateSet updates Zendesk to ensure full visibility for agents and customers: 1. **Private Note (Internal)** * Lists newly created `shipstation_order_id`, determined SKU, product description, brand, quantity, defective item, and issue code. 2. **Custom Fields** * Defective Item * Quantity * Issue Code 3. **Customer-Facing Message** * Automatically generated courtesy message explaining the outcome. * May provide next steps or tracking information. *** ## Troubleshooting & Common Issues 1. **Duplicate Order Error** * **Symptoms**: An order with the same RMA (“W-###”) already exists in ShipStation, causing the system to skip new creation. * **Fix**: Check if the original ticket was re-sent, or if the same RMA was triggered more than once. Confirm with the customer if multiple orders are needed. 2. **Address Verification Failure** * **Symptoms**: Address not found or partially matched. * **Fix**: Confirm with the customer for correctness. StateSet may revert to the original address if the verification fails. Consider a manual review step if address validation is crucial. 3. **AI Misidentification** * **Symptoms**: Brand or product incorrectly identified. * **Fix**: Update the warranty record in StateSet and correct fields in Zendesk. Provide feedback to the AI logic (e.g., adjusting prompts or default logic). 4. **ShipStation API key Issues** * **Symptoms**: “Unauthorized” or “Invalid credentials” errors. * **Fix**: Verify your ShipStation API credentials and test them in a known environment. 5. **Webhook Not Triggering** * **Symptoms**: Data never arrives in StateSet after a new Zendesk ticket. * **Fix**: Check Zendesk Admin -> Webhooks for correct endpoint and authentication. Ensure the signature validation code is up to date. 6. **Order Creation Succeeds but No Zendesk Update** * **Symptoms**: A replacement order is created, but the Zendesk ticket lacks any new notes. * **Fix**: Check the logs in StateSet for errors when calling Zendesk’s API. Validate Zendesk API tokens and ticket permissions. *** ## Best Practices and Tips * **Maintain Clean Data**\ Encourage customers to provide clear, detailed descriptions and pictures. The better the data, the more accurate AI-driven brand and accessory identification will be. * **AI Confidence Levels**\ If your AI returns a “low” confidence level, consider adding a manual review step before shipping a replacement. * **Address Verification**\ Use the verified address fields whenever available. This reduces shipping costs, undeliverable packages, and delays. * **Use Custom Fields Wisely**\ Storing the defective item, quantity, and issue code in Zendesk custom fields simplifies reporting and search. * **Monitor Logs**\ Regularly check StateSet logs to spot recurring issues, especially around shipping errors or AI misclassifications. * **Stay Current with API Credentials**\ Regularly rotate or confirm credentials for Zendesk, ShipStation, and Google Address Validation to avoid unexpected downtimes. * **Edge Cases** * **No matching SKU**: If the product can’t be matched, consider a manual process to clarify SKU and color. * **International Addresses**: Ensure the country field is accurate. If your ShipStation store is restricted to the U.S. or certain countries, handle out-of-scope addresses carefully. *** ## Appendix: Technical Implementation Below are selected excerpts and explanations from the code that power this workflow. This section is intended for developers or administrators who need to dive deeper into how the system functions. *** ### Zendesk Signature Validation Before processing the incoming data, StateSet verifies that the webhook request actually came from Zendesk: ```javascript theme={null} export async function isValidSignature(signature, body, timestamp) { let hmac = crypto.createHmac(SIGNING_SECRET_ALGORITHM, PROD_SIGNING_SECRET); let sig = hmac.update(timestamp + body).digest("base64"); return ( Buffer.compare( Buffer.from(signature), Buffer.from(sig.toString("base64")) ) === 0 ); }; ``` * **Purpose**: Prevents spoofed or malicious requests. * **Implementation**: Compares the HMAC from Zendesk with one generated locally using shared secrets. *** ### Logging Errors in StateSet Whenever an error occurs (e.g., ShipStation creation failure), StateSet logs it: ```javascript theme={null} export async function logError(rma, description) { logger.info('logging_StateSet_error'); var log_id = uuidv4(); const log = { "id": log_id, "rma": rma, "description": description, "rma_type": "warranty" }; return "logged_StateSet_error"; }; ``` * **Usage**: Simplifies debugging by capturing the RMA, error description, and timestamp. *** ### Creating a Ship-To Address Record StateSet can create a dedicated “Ship-To” address record in its own database: ```graphql theme={null} mutation CreateShipToAddress($ship_to: ship_to_insert_input!) { insert_ship_to(objects: [$ship_to]) { returning { id first_name last_name street1 city state country } } } ``` * **Best Practice**: Keep shipping addresses versioned or historically traceable. If a package is returned or lost, having an immutable record helps in audits. *** ### Checking for Duplicate Orders in ShipStation StateSet queries ShipStation before attempting to create a new order: ```javascript theme={null} const response = await fetch(`https://ssapi.shipstation.com/orders?orderNumber=${order_id}`, requestOptions); if (response.ok) { // ... if (result && result.orders[0]) { return res.status(200).json({ status: "duplicate_request_order_and_invoice_already_processed" }); } } ``` * **Prevents** sending multiple replacement orders for the same ticket, avoiding duplication and wasted shipping. *** ### Creating ShipStation Orders When no duplicates are found, StateSet issues a `POST` request to ShipStation: ```javascript theme={null} export async function createShipStationOrder(rma, customer_email, ...) { // ... var shipstation_replacement_order = JSON.stringify({ "orderNumber": rma, "orderKey": uuidv4(), // ... "items": [{ "sku": sku, "name": name, "quantity": quantity }], // ... "billTo": { /* Customer billing info */ }, "shipTo": { /* Verified shipping info */ }, "internalNotes": "Ticket #" + ticket_id, "advancedOptions": { "warehouseId": 442610, "storeId": 242000 } }); // ... } ``` * **Key Fields**: `orderNumber` (the RMA), `customerEmail`, `items` (SKU, quantity). * **`storeId`**: Make sure this references the correct store in ShipStation for production. *** ### StateSet Warranty Record: Create and Update * **Create** ```graphql theme={null} mutation CreateWarrantyRecord($warranty: warranties_insert_input!) { insert_warranties(objects: [$warranty]) { returning { id ... } } } ``` * **Update** ```graphql theme={null} mutation UpdateWarrantyRecord($id: String!, $defective_item: String!, $issue_code: String!) { update_warranties(where: {id: {_eq: $id}}, _set: {defective_item: $defective_item, issue_code: $issue_code}) { returning { id } } } ``` * **Stored Fields**: brand, model, defective item, issue code, RMA, email, creation dates, etc. *** ### AI Function Calls Overview StateSet uses specialized function calls to the OpenAI API. Examples include: * **determineBrandAndModel** * **determineAccessories** * **determineHydraPakDefectiveItem** These calls parse user descriptions, images, or relevant ticket data to infer brand, model, or SKU. If it fails or returns an “unknown” result, a manual review might be required. *** ### Updating Zendesk **Private Note**: ```javascript theme={null} export async function addPrivateNoteToHydraPakZendeskTicket(ticket_id, message) { // ... const zendeskPayload = JSON.stringify({ "ticket": { "comment": { "body": message, "public": false } } }); // ... } ``` **Custom Fields**: ```javascript theme={null} export async function updateHydraPakZendeskTicketCustomFields(ticket_id, defective_item, quantity, issue_code) { const ticketPayload = { "ticket": { "custom_fields": [ { "id": 360031805313, "value": defective_item }, { "id": 81571188, "value": quantity }, { "id": 360006941114, "value": issue_code } ], "status": "open" } }; // ... } ``` These updates ensure that support agents can see all relevant details in one place. *** ### Address Verification (Google Address Validation API) **Key Points**: * Uses Google’s Address Validation to standardize addresses, checking for street, city, state, postal code, and country. * If a partially matched address is returned, the system logs it and sets a lower “confidence” rating. * On failure or missing fields, the workflow continues with the original address unless it’s critically incomplete. ```javascript theme={null} export const verifyAddress = async (address) => { // ... const response = await fetch(`${baseUrl}?key=${apiKey}`, { method: 'POST', body: JSON.stringify({ ... }) }); // ... } ``` *** ### Image Analysis for Brand, Model, and Accessories For tickets with attachments: 1. **Extract Attachment URLs** from the Zendesk ticket description (or from an `image_description` field). 2. **Analyze** the images with the OpenAI endpoint. 3. **Combine** the textual analysis with any brand references in the subject or description. 4. **Function Calls** determine brand, accessories needed (e.g., “bite valve”), and whether to replace them. ```javascript theme={null} async function analyzeBrandAndModelImages(imageUrls) { // ... // Sends each image URL to OpenAI // ... } ``` * This approach reduces manual identification efforts and speeds up the resolution time for customer claims. *** ## Final Notes 1. **Document Updates**\ This guide will be revised as the warranty workflow evolves. Keep track of any new fields, updated code references, or changes to APIs. 2. **Contacts for Support** * **StateSet**: For issues with automation or AI function calls. * **Zendesk**: For webhook setup or ticket configuration issues. * **ShipStation**: For shipping label, order creation, or fulfillment issues. * **Support Admin**: For internal changes to workflows, custom fields, or approvals. 3. **Version Control**\ Always maintain version control of your StateSet environment and any custom scripts for quick rollbacks if an update introduces errors. *** ### Thank You We hope this expanded guide provides the clarity you need to successfully deploy, manage, and troubleshoot the Warranty Workflow. For any additional questions or contributions, please reach out to your system administrator or the StateSet support team. # Webhook Security Guide Source: https://docs.stateset.com/guides/webhook-security Comprehensive guide to securing StateSet webhooks with signature verification, replay protection, and security best practices # Webhook Security Guide Learn how to securely handle StateSet webhooks with comprehensive security patterns, signature verification, replay attack prevention, and production-ready implementation examples. ## Prerequisites Before you begin, ensure you have: * A StateSet account with webhook endpoints configured * Understanding of HMAC signature verification * HTTPS endpoint for receiving webhooks * Basic knowledge of Node.js/Express (examples provided) * Production environment security considerations ## Security Fundamentals Configure your webhook secret in the StateSet dashboard: ```bash theme={null} # .env STATESET_WEBHOOK_SECRET=whsec_3rK9pL7nQ2xS5mT8... WEBHOOK_ENDPOINT_URL=https://api.yourstore.com/webhooks/StateSet # Security Settings WEBHOOK_TIMEOUT_MS=5000 MAX_WEBHOOK_BODY_SIZE=1048576 # 1MB ENABLE_REPLAY_PROTECTION=true REPLAY_TOLERANCE_SECONDS=300 # 5 minutes ``` Ensure your webhook endpoint uses HTTPS: ```javascript theme={null} // webhook-server.js import express from 'express'; import https from 'https'; import fs from 'fs'; const app = express(); // Production HTTPS setup if (process.env.NODE_ENV === 'production') { const options = { key: fs.readFileSync('/path/to/private-key.pem'), cert: fs.readFileSync('/path/to/certificate.pem'), // Additional security headers secureProtocol: 'TLSv1_2_method', ciphers: [ 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES128-SHA256', 'ECDHE-RSA-AES256-SHA384' ].join(':'), honorCipherOrder: true }; https.createServer(options, app).listen(443, () => { logger.info('Secure webhook server running on port 443'); }); } else { app.listen(3000, () => { logger.info('Development webhook server running on port 3000'); }); } ``` Implement comprehensive request validation: ```javascript theme={null} import rateLimit from 'express-rate-limit'; import helmet from 'helmet'; // Security middleware app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'none'"], styleSrc: ["'none'"], imgSrc: ["'none'"] } } })); // Rate limiting for webhook endpoints const webhookLimiter = rateLimit({ windowMs: 1 * 60 * 1000, // 1 minute max: 100, // Limit each IP to 100 requests per windowMs message: 'Too many webhook requests from this IP', standardHeaders: true, legacyHeaders: false, skip: (req) => { // Skip rate limiting for known StateSet IPs const StateSetIPs = ['52.89.214.238', '54.187.174.169', '54.187.205.235']; return StateSetIPs.includes(req.ip); } }); app.use('/webhooks', webhookLimiter); ``` ## Signature Verification ### Basic HMAC Verification Implement secure signature verification: ```javascript theme={null} import crypto from 'crypto'; import express from 'express'; class WebhookVerifier { constructor(secret) { this.secret = secret; this.tolerance = 300; // 5 minutes in seconds } verifySignature(payload, signature, timestamp) { try { // Verify timestamp to prevent replay attacks const currentTime = Math.floor(Date.now() / 1000); if (Math.abs(currentTime - timestamp) > this.tolerance) { throw new Error('Webhook timestamp is too old'); } // Create expected signature const expectedSignature = this.computeSignature(payload, timestamp); // Use constant-time comparison to prevent timing attacks return this.secureCompare(signature, expectedSignature); } catch (error) { logger.error('Signature verification failed:', error.message); return false; } } computeSignature(payload, timestamp) { const signedPayload = `${timestamp}.${payload}`; return crypto .createHmac('sha256', this.secret) .update(signedPayload, 'utf8') .digest('hex'); } secureCompare(a, b) { if (a.length !== b.length) { return false; } let result = 0; for (let i = 0; i < a.length; i++) { result |= a.charCodeAt(i) ^ b.charCodeAt(i); } return result === 0; } extractSignature(header) { const elements = header.split(','); const signatures = {}; for (const element of elements) { const [key, value] = element.split('='); if (key === 'v1') { signatures.v1 = value; } else if (key === 't') { signatures.timestamp = parseInt(value, 10); } } return signatures; } } // Initialize verifier const verifier = new WebhookVerifier(process.env.STATESET_WEBHOOK_SECRET); // Middleware to capture raw body app.use('/webhooks/StateSet', express.raw({ type: 'application/json', limit: '1mb' })); // Webhook verification middleware function verifyWebhook(req, res, next) { const signature = req.headers['StateSet-signature']; const payload = req.body.toString(); if (!signature) { return res.status(401).json({ error: 'Missing signature header' }); } try { const { v1: sig, timestamp } = verifier.extractSignature(signature); if (!sig || !timestamp) { return res.status(401).json({ error: 'Invalid signature format' }); } const isValid = verifier.verifySignature(payload, sig, timestamp); if (!isValid) { return res.status(401).json({ error: 'Invalid signature' }); } // Parse JSON only after verification req.body = JSON.parse(payload); next(); } catch (error) { logger.error('Webhook verification error:', error); return res.status(400).json({ error: 'Webhook verification failed' }); } } ``` ### Advanced Signature Verification Production-ready implementation with enhanced security: ```javascript theme={null} class AdvancedWebhookVerifier extends WebhookVerifier { constructor(secret, options = {}) { super(secret); this.tolerance = options.tolerance || 300; this.enableReplayProtection = options.enableReplayProtection !== false; this.processedWebhooks = new Map(); // In production, use Redis this.maxCacheSize = options.maxCacheSize || 10000; } async verifyWebhookWithReplayProtection(payload, signature, timestamp, webhookId) { // Check for replay attacks if (this.enableReplayProtection && this.processedWebhooks.has(webhookId)) { throw new Error('Webhook has already been processed (replay attack detected)'); } // Verify signature const isValid = this.verifySignature(payload, signature, timestamp); if (isValid && this.enableReplayProtection) { // Store webhook ID to prevent replay this.processedWebhooks.set(webhookId, Date.now()); // Clean up old entries to prevent memory leaks this.cleanupCache(); } return isValid; } cleanupCache() { if (this.processedWebhooks.size > this.maxCacheSize) { const cutoff = Date.now() - (this.tolerance * 1000); for (const [id, timestamp] of this.processedWebhooks.entries()) { if (timestamp < cutoff) { this.processedWebhooks.delete(id); } } } } // Verify multiple signature versions for backward compatibility verifyMultipleSignatures(payload, signatureHeader, timestamp) { const signatures = this.extractSignature(signatureHeader); // Try v1 signature first if (signatures.v1) { const isValid = this.secureCompare( signatures.v1, this.computeSignature(payload, timestamp) ); if (isValid) return true; } // Fallback to other versions if needed // This allows for graceful migration between signature versions return false; } } // Production webhook handler const advancedVerifier = new AdvancedWebhookVerifier( process.env.STATESET_WEBHOOK_SECRET, { tolerance: 300, enableReplayProtection: true, maxCacheSize: 10000 } ); async function advancedVerifyWebhook(req, res, next) { const signature = req.headers['StateSet-signature']; const webhookId = req.headers['StateSet-webhook-id']; const payload = req.body.toString(); if (!signature || !webhookId) { return res.status(401).json({ error: 'Missing required headers', required: ['StateSet-signature', 'StateSet-webhook-id'] }); } try { const { v1: sig, timestamp } = advancedVerifier.extractSignature(signature); const isValid = await advancedVerifier.verifyWebhookWithReplayProtection( payload, sig, timestamp, webhookId ); if (!isValid) { // Log security event console.warn('Webhook security violation:', { ip: req.ip, userAgent: req.headers['user-agent'], timestamp: new Date().toISOString(), webhookId, signatureProvided: !!signature }); return res.status(401).json({ error: 'Webhook verification failed' }); } req.body = JSON.parse(payload); req.webhookId = webhookId; next(); } catch (error) { logger.error('Advanced webhook verification error:', error); return res.status(400).json({ error: error.message }); } } ``` ## Event Processing Security ### Secure Event Handler Implement secure and resilient event processing: ```javascript theme={null} class SecureWebhookProcessor { constructor() { this.eventHandlers = new Map(); this.processingQueue = []; this.maxRetries = 3; this.retryDelays = [1000, 5000, 15000]; // Progressive backoff } registerHandler(eventType, handler, options = {}) { this.eventHandlers.set(eventType, { handler, requiresAuth: options.requiresAuth !== false, timeout: options.timeout || 30000, retryable: options.retryable !== false }); } async processWebhook(webhookData, context = {}) { const { event, data, id: webhookId } = webhookData; // Input validation if (!event || !data) { throw new Error('Invalid webhook payload structure'); } const handlerConfig = this.eventHandlers.get(event); if (!handlerConfig) { console.warn(`No handler registered for event: ${event}`); return { status: 'ignored', reason: 'no_handler' }; } // Security context validation if (handlerConfig.requiresAuth && !context.authenticated) { throw new Error('Authentication required for this event type'); } return await this.executeWithRetry( handlerConfig, data, { ...context, event, webhookId } ); } async executeWithRetry(handlerConfig, data, context) { let lastError; for (let attempt = 0; attempt <= this.maxRetries; attempt++) { try { // Set timeout for handler execution const result = await Promise.race([ handlerConfig.handler(data, context), this.timeoutPromise(handlerConfig.timeout) ]); return { status: 'success', result, attempt: attempt + 1 }; } catch (error) { lastError = error; logger.error(`Webhook handler failed (attempt ${attempt + 1});:`, { event: context.event, webhookId: context.webhookId, error: error.message, stack: error.stack }); // Don't retry certain types of errors if (!handlerConfig.retryable || this.isNonRetryableError(error)) { break; } // Wait before retrying (except on last attempt) if (attempt < this.maxRetries) { await this.delay(this.retryDelays[attempt] || 15000); } } } throw new Error( `Webhook processing failed after ${this.maxRetries + 1} attempts: ${lastError.message}` ); } timeoutPromise(timeout) { return new Promise((_, reject) => { setTimeout(() => reject(new Error('Handler timeout')), timeout); }); } isNonRetryableError(error) { const nonRetryablePatterns = [ /validation/i, /authentication/i, /authorization/i, /not found/i, /duplicate/i ]; return nonRetryablePatterns.some(pattern => pattern.test(error.message) ); } delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // Initialize processor and register handlers const processor = new SecureWebhookProcessor(); // Order event handlers processor.registerHandler('order.created', async (orderData, context) => { // Validate order data if (!orderData.id || !orderData.customer_email) { throw new Error('Invalid order data: missing required fields'); } // Process order creation logger.info(`Processing order creation: ${orderData.id}`); // Your business logic here await processNewOrder(orderData); return { processed: true, orderId: orderData.id }; }, { timeout: 30000 }); processor.registerHandler('order.cancelled', async (orderData, context) => { // Handle order cancellation logger.info(`Processing order cancellation: ${orderData.id}`); await processOrderCancellation(orderData); return { processed: true, orderId: orderData.id }; }); processor.registerHandler('payment.failed', async (paymentData, context) => { // Handle payment failures (non-retryable) logger.info(`Processing payment failure: ${paymentData.payment_id}`); await handlePaymentFailure(paymentData); return { processed: true, paymentId: paymentData.payment_id }; }, { retryable: false }); ``` ### Complete Webhook Endpoint Production-ready webhook endpoint with all security measures: ```javascript theme={null} // Complete secure webhook endpoint app.post('/webhooks/StateSet', advancedVerifyWebhook, async (req, res) => { const startTime = Date.now(); try { // Add request context const context = { ip: req.ip, userAgent: req.headers['user-agent'], timestamp: new Date().toISOString(), authenticated: true, // Set by verification middleware webhookId: req.webhookId }; // Process webhook const result = await processor.processWebhook(req.body, context); // Log successful processing logger.info('Webhook processed successfully:', { event: req.body.event, webhookId: req.webhookId, processingTime: Date.now(); - startTime, result: result.status }); // Return success response res.status(200).json({ received: true, processed: result.status === 'success', webhookId: req.webhookId, processingTime: Date.now() - startTime }); } catch (error) { // Log error with context logger.error('Webhook processing error:', { event: req.body?.event, webhookId: req.webhookId, error: error.message, stack: error.stack, processingTime: Date.now(); - startTime }); // Return appropriate error response const statusCode = error.message.includes('authentication') ? 401 : error.message.includes('validation') ? 400 : 500; res.status(statusCode).json({ received: true, processed: false, error: error.message, webhookId: req.webhookId }); } } ); ``` ## IP Allowlisting ### StateSet IP Ranges Configure IP allowlisting for enhanced security: ```javascript theme={null} class IPAllowlist { constructor() { // StateSet webhook IP ranges (update as needed) this.allowedRanges = [ '52.89.214.238/32', '54.187.174.169/32', '54.187.205.235/32', // Add more StateSet IP ranges as provided ]; this.compiledRanges = this.compileRanges(); } compileRanges() { return this.allowedRanges.map(range => { const [ip, cidr] = range.split('/'); const mask = ~(0xFFFFFFFF >>> parseInt(cidr, 10)); return { network: this.ipToInt(ip) & mask, mask: mask }; }); } ipToInt(ip) { return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0; } isAllowed(ip) { const ipInt = this.ipToInt(ip); return this.compiledRanges.some(range => (ipInt & range.mask) === range.network ); } } // IP allowlist middleware const ipAllowlist = new IPAllowlist(); function checkIPAllowlist(req, res, next) { // Skip in development if (process.env.NODE_ENV !== 'production') { return next(); } const clientIP = req.ip || req.connection.remoteAddress; if (!ipAllowlist.isAllowed(clientIP)) { console.warn('Webhook request from unauthorized IP:', { ip: clientIP, userAgent: req.headers['user-agent'], timestamp: new Date().toISOString() }); return res.status(403).json({ error: 'IP not allowed', ip: clientIP }); } next(); } // Apply IP allowlist before webhook processing app.use('/webhooks/StateSet', checkIPAllowlist); ``` ## Monitoring and Alerting ### Security Event Monitoring Implement comprehensive security monitoring: ```javascript theme={null} import winston from 'winston'; class WebhookSecurityMonitor { constructor() { this.logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ new winston.transports.File({ filename: 'webhook-security.log' }), new winston.transports.Console() ] }); this.securityEvents = new Map(); this.alertThresholds = { failedVerifications: 10, suspiciousIPs: 5, timeWindow: 300000 // 5 minutes }; } logSecurityEvent(eventType, data) { const event = { type: eventType, timestamp: Date.now(), data: data }; this.logger.warn('Security event detected', event); // Track events for alerting this.trackEventForAlerting(eventType, data); } trackEventForAlerting(eventType, data) { const key = `${eventType}:${data.ip || 'unknown'}`; const now = Date.now(); if (!this.securityEvents.has(key)) { this.securityEvents.set(key, []); } const events = this.securityEvents.get(key); events.push(now); // Clean old events const cutoff = now - this.alertThresholds.timeWindow; const recentEvents = events.filter(timestamp => timestamp > cutoff); this.securityEvents.set(key, recentEvents); // Check for alert conditions this.checkAlertConditions(eventType, data, recentEvents.length); } checkAlertConditions(eventType, data, eventCount) { let shouldAlert = false; if (eventType === 'signature_verification_failed' && eventCount >= this.alertThresholds.failedVerifications) { shouldAlert = true; } if (eventType === 'suspicious_ip' && eventCount >= this.alertThresholds.suspiciousIPs) { shouldAlert = true; } if (shouldAlert) { this.sendSecurityAlert(eventType, data, eventCount); } } async sendSecurityAlert(eventType, data, eventCount) { const alert = { type: 'webhook_security_alert', eventType, count: eventCount, timeWindow: this.alertThresholds.timeWindow / 1000 / 60, // minutes data, timestamp: new Date().toISOString() }; this.logger.error('Security alert triggered', alert); // Send to monitoring service (PagerDuty, Slack, etc.) try { await this.sendToMonitoringService(alert); } catch (error) { logger.error('Failed to send security alert:', error); } } async sendToMonitoringService(alert) { // Example: Send to Slack webhook if (process.env.SLACK_WEBHOOK_URL) { const message = { text: `🚨 Webhook Security Alert: ${alert.eventType}`, attachments: [{ color: 'danger', fields: [ { title: 'Event Type', value: alert.eventType, short: true }, { title: 'Count', value: alert.count, short: true }, { title: 'Time Window', value: `${alert.timeWindow} minutes`, short: true }, { title: 'IP Address', value: alert.data.ip || 'Unknown', short: true } ], timestamp: Math.floor(Date.now() / 1000) }] }; // Send to Slack (implement HTTP request) // await fetch(process.env.SLACK_WEBHOOK_URL, { ... }); } } } // Initialize security monitor const securityMonitor = new WebhookSecurityMonitor(); // Enhanced verification middleware with monitoring function monitoredVerifyWebhook(req, res, next) { const signature = req.headers['StateSet-signature']; const webhookId = req.headers['StateSet-webhook-id']; const payload = req.body.toString(); const clientIP = req.ip; if (!signature || !webhookId) { securityMonitor.logSecurityEvent('missing_headers', { ip: clientIP, userAgent: req.headers['user-agent'], missingHeaders: [ !signature && 'StateSet-signature', !webhookId && 'StateSet-webhook-id' ].filter(Boolean) }); return res.status(401).json({ error: 'Missing required headers' }); } try { const { v1: sig, timestamp } = advancedVerifier.extractSignature(signature); const isValid = advancedVerifier.verifySignature(payload, sig, timestamp); if (!isValid) { securityMonitor.logSecurityEvent('signature_verification_failed', { ip: clientIP, userAgent: req.headers['user-agent'], webhookId, hasSignature: !!signature, hasTimestamp: !!timestamp }); return res.status(401).json({ error: 'Invalid signature' }); } req.body = JSON.parse(payload); req.webhookId = webhookId; next(); } catch (error) { securityMonitor.logSecurityEvent('verification_error', { ip: clientIP, error: error.message, webhookId }); return res.status(400).json({ error: 'Webhook verification failed' }); } } ``` ## Testing Webhook Security ### Security Test Suite Comprehensive test suite for webhook security: ```javascript theme={null} // webhook-security.test.js import crypto from 'crypto'; import request from 'supertest'; import app from '../webhook-server.js'; describe('Webhook Security', () => { const webhookSecret = 'test_webhook_secret'; function createValidSignature(payload, timestamp) { const signedPayload = `${timestamp}.${payload}`; const signature = crypto .createHmac('sha256', webhookSecret) .update(signedPayload, 'utf8') .digest('hex'); return `t=${timestamp},v1=${signature}`; } describe('Signature Verification', () => { it('should accept valid signatures', async () => { const payload = JSON.stringify({ event: 'order.created', data: { id: '123' } }); const timestamp = Math.floor(Date.now() / 1000); const signature = createValidSignature(payload, timestamp); const response = await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', 'test-webhook-id') .send(payload) .expect(200); expect(response.body.received).toBe(true); }); it('should reject invalid signatures', async () => { const payload = JSON.stringify({ event: 'order.created', data: { id: '123' } }); await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', 'invalid-signature') .set('StateSet-webhook-id', 'test-webhook-id') .send(payload) .expect(401); }); it('should reject old timestamps', async () => { const payload = JSON.stringify({ event: 'order.created', data: { id: '123' } }); const oldTimestamp = Math.floor(Date.now() / 1000) - 600; // 10 minutes ago const signature = createValidSignature(payload, oldTimestamp); await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', 'test-webhook-id') .send(payload) .expect(401); }); it('should prevent replay attacks', async () => { const payload = JSON.stringify({ event: 'order.created', data: { id: '123' } }); const timestamp = Math.floor(Date.now() / 1000); const signature = createValidSignature(payload, timestamp); const webhookId = 'unique-webhook-id'; // First request should succeed await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', webhookId) .send(payload) .expect(200); // Second request with same ID should fail await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', webhookId) .send(payload) .expect(401); }); }); describe('Rate Limiting', () => { it('should rate limit excessive requests', async () => { const payload = JSON.stringify({ event: 'test.event', data: {} }); const timestamp = Math.floor(Date.now() / 1000); // Make many requests quickly const requests = Array.from({ length: 150 }, (_, i) => { const signature = createValidSignature(payload, timestamp); return request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', `webhook-${i}`) .send(payload); }); const responses = await Promise.allSettled(requests); const rateLimited = responses.filter(r => r.status === 'fulfilled' && r.value.status === 429 ); expect(rateLimited.length).toBeGreaterThan(0); }); }); describe('Input Validation', () => { it('should reject oversized payloads', async () => { const largePayload = 'x'.repeat(2 * 1024 * 1024); // 2MB const timestamp = Math.floor(Date.now() / 1000); const signature = createValidSignature(largePayload, timestamp); await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', 'test-webhook-id') .send(largePayload) .expect(413); // Payload too large }); it('should reject malformed JSON', async () => { const invalidJson = '{ invalid json }'; const timestamp = Math.floor(Date.now() / 1000); const signature = createValidSignature(invalidJson, timestamp); await request(app) .post('/webhooks/StateSet') .set('StateSet-signature', signature) .set('StateSet-webhook-id', 'test-webhook-id') .send(invalidJson) .expect(400); }); }); }); ``` ## Best Practices Summary ### Security Checklist ✅ Always verify webhook signatures using HMAC-SHA256 ✅ Use constant-time comparison to prevent timing attacks ✅ Implement timestamp validation to prevent replay attacks ✅ Store processed webhook IDs to prevent duplicates ✅ Use HTTPS for all webhook endpoints ✅ Implement IP allowlisting for StateSet IP ranges ✅ Use rate limiting to prevent abuse ✅ Validate request headers and content types ✅ Log security events for monitoring ✅ Return appropriate HTTP status codes ✅ Implement retry logic with exponential backoff ✅ Set reasonable timeouts for webhook processing ✅ Track failed verification attempts ✅ Alert on suspicious activity patterns ✅ Monitor processing times and error rates ✅ Log all webhook events with context ### Production Deployment ```bash theme={null} # Environment variables for production STATESET_WEBHOOK_SECRET=whsec_prod_9K2xL5pN... WEBHOOK_TIMEOUT_MS=30000 MAX_WEBHOOK_BODY_SIZE=1048576 ENABLE_REPLAY_PROTECTION=true REPLAY_TOLERANCE_SECONDS=300 # Security headers ENABLE_HELMET=true ENABLE_RATE_LIMITING=true ALLOWED_IPS=52.89.214.238,54.187.174.169,54.187.205.235 # Monitoring ENABLE_SECURITY_MONITORING=true SLACK_WEBHOOK_URL=https://hooks.slack.com/services/your/slack/webhook ALERT_EMAIL=security@yourstore.com # SSL/TLS SSL_CERT_PATH=/path/to/ssl/cert.pem SSL_KEY_PATH=/path/to/ssl/private-key.pem ``` ## Next Steps Learn how to test your webhook implementations Set up comprehensive monitoring and alerting Best practices for integrating with external systems Optimize webhook processing performance ## Conclusion Implementing robust webhook security is critical for protecting your application and ensuring data integrity. This guide provides comprehensive security patterns including signature verification, replay protection, IP allowlisting, and monitoring. Key takeaways: * ✅ Always verify webhook signatures using HMAC-SHA256 * ✅ Implement replay attack prevention with timestamp validation * ✅ Use HTTPS and IP allowlisting for network security * ✅ Monitor security events and set up alerting * ✅ Test your security implementation thoroughly With these security measures in place, you can confidently process StateSet webhooks while maintaining the highest security standards. # Wholesale Quickstart Source: https://docs.stateset.com/guides/wholesale-quickstart Get started with StateSet's wholesale order management solution. Automate B2B order processing and integrate with SYSPRO ERP. # StateSet Wholesale Order Management: Your Comprehensive Guide This guide provides everything you need to start using StateSet's powerful Wholesale Order Management API. Learn how to streamline your B2B order processing, from capturing email orders to integrating with SYSPRO ERP. ## Table of Contents 1. [Introduction](#1-introduction) 2. [Why Use StateSet for Wholesale Order Management?](#2-why-use-StateSet-for-wholesale-order-management) 3. [Understanding the Challenges](#3-understanding-the-challenges) 4. [StateSet's Solution](#4-StateSets-solution) 5. [Quickstart: Getting Started](#5-quickstart-getting-started) 6. [Core API Components](#6-core-api-components) * [6.1 GraphQL API](#61-graphql-api) * [6.2 SYSPRO API Helper](#62-syspro-api-helper) 7. [Integrating with SYSPRO ERP](#7-integrating-with-syspro-erp) * [7.1 Logging into SYSPRO](#71-logging-into-syspro) * [7.2 Checking Customer Status](#72-checking-customer-status) * [7.3 Checking Inventory Status](#73-checking-inventory-status) * [7.4 Sending Orders to SYSPRO](#74-sending-orders-to-syspro) 8. [Order Processing Workflow](#8-order-processing-workflow) * [8.1 Fetching and Initial Processing](#81-fetching-and-initial-processing) * [8.2 Splitting and Transforming Orders to XML](#82-splitting-and-transforming-orders-to-xml) * [8.3 Updating Order Status](#83-updating-order-status) 9. [Error Handling and Notifications](#9-error-handling-and-notifications) 10. [Support](#10-support) ## 1. Introduction StateSet's Wholesale Order Management API is a robust solution designed for businesses managing large-volume B2B orders. Our API automates critical processes, from extracting order data from emails to seamlessly integrating with ERP systems like SYSPRO. This guide will walk you through the key features and how to implement them. ## 2. Why Use StateSet for Wholesale Order Management? StateSet provides a purpose-built solution to simplify and automate the complexities of wholesale ordering. By leveraging our platform, you can: * **Save Time**: Automate tasks previously done manually. * **Reduce Errors**: Eliminate manual data entry, reducing errors and improving data accuracy. * **Streamline Operations**: Improve order flow from capture to fulfillment. * **Improve Efficiency**: Manage wholesale orders efficiently and at scale. * **Integrate Seamlessly**: Connect with critical ERP systems like SYSPRO. ## 3. Understanding the Challenges Wholesale order management presents unique challenges compared to B2C sales. Some key hurdles include: * **Complex Pricing**: Handling tiered pricing, bulk discounts, and customer-specific rates. * **Large Order Volumes**: Managing orders with many line items and high quantities. * **Custom Terms**: Accommodating varying customer payment, shipping, and other terms. * **ERP Integration**: Ensuring smooth data exchange with your core ERP system. * **Inventory Management**: Synchronizing inventory levels across wholesale and retail channels. * **Approval Workflows**: Supporting multi-stage approvals before fulfilling orders. ## 4. StateSet's Solution StateSet's Wholesale Order Management API addresses these challenges with powerful features: * **Automated Email Order Capture**: Extracts order details from emails in various formats. * **Flexible Pricing**: Handles complex pricing models including tiered and customer-specific rates. * **Bulk Order Processing**: Efficiently processes orders with large numbers of items. * **Customizable Workflows**: Allows custom approval processes and business rules. * **ERP Integration**: Creates standardized XML output for easy integration with SYSPRO and similar systems. * **Inventory Synchronization**: Offers real-time inventory updates across all channels. ## 5. Quickstart: Getting Started Ready to begin? Follow these steps to set up and configure your StateSet integration. Create your company's StateSet instance by signing up at [StateSet.com/sign-up](https://StateSet.com/sign-up). Create a new API key in the StateSet Cloud Console at [cloud.StateSet.com/api-keys](https://cloud.StateSet.com/api-keys). Ensure you have Node.js installed. Install the required npm package: ```bash theme={null} npm install StateSet-node ``` Clone our sample project from [GitHub](https://github.com/StateSet/wholesale-order-management). *(Note: Replace with the correct repository link)*. This provides a working example to get you started quickly. Create a `.env` file in the project's root directory and add your API keys and configurations: ```env theme={null} STATESET_API_KEY=your_StateSet_api_key SENDGRID_API_KEY=your_sendgrid_api_key SYSPRO_BASE_URL=your_syspro_base_url SYSPRO_OPERATOR=your_syspro_operator SYSPRO_COMPANY=your_syspro_company SYSPRO_PASSWORD=your_syspro_password ``` ## 6. Core API Components Here's an overview of the core API components you'll use. ### 6.1 GraphQL API StateSet utilizes a GraphQL API for interacting with wholesale orders and line items. Here are examples of the queries and mutations you will use: #### 6.1.1 Fetching a Wholesale Order Use the `GET_MY_WHOLESALE_ORDER` query to retrieve a wholesale order and its associated line items: ```javascript theme={null} const GET_MY_WHOLESALE_ORDER = gql` query getMyWholesaleOrders($id: uuid!) { wholesale_orders(where: { id: { _eq: $id } }) { id order_number customer_name customer_number delivery_date created_date } wholesale_order_line_items( where: { wholesale_order_id: { _eq: $id } _and: { include_in_export: { _eq: true } } } ) { id product_id product_name quantity unit price_unit product_class } } `; ``` #### 6.1.2 Updating a Wholesale Order After processing, update the wholesale order's status using the `UPDATE_WHOLESALE_ORDER` mutation: ```javascript theme={null} const UPDATE_WHOLESALE_ORDER = gql` mutation updateWholesaleOrder( $id: uuid! $imported_status: String! $imported_date: timestamptz! ) { update_wholesale_orders( where: { id: { _eq: $id } } _set: { imported_status: $imported_status, imported_date: $imported_date } ) { affected_rows } } `; ``` ### 6.2 SYSPRO API Helper The following helper function is used to interact with the SYSPRO API: ```javascript theme={null} async function callSysproApi({ method = 'GET', endpoint, sessionId = '', queryParams = '', xmlIn = '', headers = {}, body = null }) { const baseUrl = process.env.SYSPRO_BASE_URL; let url = `${baseUrl}${endpoint}`; // Add 'UserId' parameter if 'sessionId' is provided const params = []; if (sessionId) { params.push(`UserId=${sessionId}`); } if (queryParams) { params.push(queryParams); } if (params.length > 0) { url += `?${params.join('&')}`; } const response = await fetch(url, { method, headers: { 'Content-Type': 'application/xml', 'User-Agent': 'StateSet SYSPRO Client', ...headers, }, body, }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return await response.text(); } ``` ## 7. Integrating with SYSPRO ERP StateSet's integration with SYSPRO allows for automated order processing and inventory management. ### 7.1 Logging into SYSPRO Start by obtaining a session ID by logging into SYSPRO: ```javascript theme={null} async function logonToSyspro() { const url = `/Rest/Logon`; const queryParams = `Operator=${process.env.SYSPRO_OPERATOR}&Company=${process.env.SYSPRO_COMPANY}&OperatorPassword=${encodeURIComponent(process.env.SYSPRO_PASSWORD)}&LanguageCode=ENG&LogLevel=2`; const sessionId = await callSysproApi({ endpoint: url, queryParams }); return sessionId; } ``` ### 7.2 Checking Customer Status Check if a customer is on hold within SYSPRO before placing an order: ```javascript theme={null} async function checkCustomer(sessionId, customerNumber) { const customerQueryXml = ` `; const endpoint = `/Rest/Query/Query`; const queryParams = `&BusinessObject=ARSQRY&XmlIn=${encodeURIComponent(customerQueryXml)}`; const data = await callSysproApi({ endpoint, sessionId, queryParams }); // Parse the XML response to check if the customer is on hold } ``` ### 7.3 Checking Inventory Status Check if inventory items are on hold before fulfilling an order: ```javascript theme={null} async function checkInventory(sessionId, stockCode) { const inventoryQueryXml = ` `; const endpoint = `/Rest/Query/Query`; const queryParams = `&BusinessObject=INVQRY&XmlIn=${encodeURIComponent(inventoryQueryXml)}`; const data = await callSysproApi({ endpoint, sessionId, queryParams }); // Parse the XML response to check if the stock item is on hold } ``` ### 7.4 Sending Orders to SYSPRO Send the transformed XML order data to SYSPRO to create a sales order: ```javascript theme={null} async function sendToSyspro(sessionId, xmlIn) { const xmlParameters = ` Y IMPORT A1 Y PR Y 1 Y `; const endpoint = `/Rest/Transaction/Post`; const queryParams = `&BusinessObject=SORTOI&XmlParameters=${encodeURIComponent( xmlParameters )}&XmlIn=${encodeURIComponent(xmlIn)}`; const data = await callSysproApi({ endpoint, sessionId, queryParams }); return data; } ``` ## 8. Order Processing Workflow This section details the flow of order processing within the StateSet system. ### 8.1 Fetching and Initial Processing First, retrieve the wholesale order and validate its contents: ```javascript theme={null} async function processOrder(order_id, customer_number, graphQLClient) { const data = await graphQLClient.request(GET_MY_WHOLESALE_ORDER, { id: order_id }); if (data.wholesale_order_line_items.length === 0) { return { skipped: true }; } const sessionId = await logonToSyspro(); const customerCheck = await checkCustomer(sessionId, customer_number); const lineItemsWithInventory = await Promise.all( data.wholesale_order_line_items.map(async (item) => { const onHold = await checkInventory(sessionId, item.product_id); return { ...item, onHold }; }) ); return { lineItemsWithInventory }; } ``` ### 8.2 Splitting and Transforming Orders to XML The following functions allow you to prepare your order data for SYSPRO. First the items are split into produce and non-produce, and then transformed into the correct XML format ```javascript theme={null} function splitOrder(lineItems) { return lineItems.reduce( (acc, lineItem) => { if (lineItem.product_class === 'PRO') { acc.produceLines.push(lineItem); } else { acc.otherLines.push(lineItem); } return acc; }, { produceLines: [], otherLines: [] } ); } function transformToXML(order, lineItems, version) { const formatDate = (dateString) => dateString ? new Date(dateString).toISOString().split('T')[0] : ''; const formatTime = () => new Date().toTimeString().split(' ')[0].substring(0, 5); const formatNumber = (value) => { const num = Number(value); return isNaN(num) ? '0.00' : num.toFixed(2); }; const createXmlObj = (lines, suffix = '') => ({ TransmissionHeader: { TransmissionReference: `${order.order_number}${suffix}-${version}` || '', ReceiverCode: 'HO', DatePrepared: formatDate(new Date().toISOString()), TimePrepared: formatTime(), }, Orders: { OrderHeader: { CustomerPoNumber: `${order.order_number}${suffix}-${version}` || '', OrderActionType: 'A', Customer: order.customer_number || '', OrderDate: formatDate(order.created_date), OrderType: 'DE', RequestedShipDate: formatDate(order.delivery_date), }, OrderDetails: { StockLine: lines.map((item, index) => ({ CustomerPoLine: (index + 1).toString(), LineActionType: 'A', StockCode: item.product_id || '', OrderQty: formatNumber(item.quantity), OrderUom: item.unit, PriceUom: item.price_unit, })), }, }, }); return { otherLineXmlObj: createXmlObj(lineItems.filter(item => item.product_class !== 'PRO')), produceLineXmlObj: createXmlObj(lineItems.filter(item => item.product_class === 'PRO'), '-PR'), }; } ``` ### 8.3 Updating Order Status Finally, update the order status in StateSet after the order has been processed in SYSPRO: ```javascript theme={null} const updatedWholesaleOrder = await graphQLClient.request(UPDATE_WHOLESALE_ORDER, { id: order_id, imported_status: 'IMPORTED', imported_date: new Date().toISOString(), }); ``` ## 9. Error Handling and Notifications ### 9.1 Error Handling StateSet incorporates robust error handling to manage potential issues: * **Detailed Logging**: Errors are logged with comprehensive information for debugging. * **Exception Management**: `try-catch` blocks are used throughout the code. ### 9.2 Email Notifications Email notifications can be sent using SendGrid, providing updates on the status of orders and any encountered issues: ```javascript theme={null} async function sendEmail(emailContent) { try { await sgMail.send(emailContent); logger.info('Email sent successfully'); } catch (error) { logger.error('Error sending email:', error); throw error; } } ``` Prepare the email content with attachments of the generated XMLs and SYSPRO responses, including any held items or warnings. ## 10. Support Need further assistance? Contact StateSet support at [support@StateSet.com](mailto:support@StateSet.com) for any questions or implementation help. # iCommerce Intro Source: https://docs.stateset.com/icommerce Definition, laws, ICP, and vision for the iCommerce category led by StateSet # Welcome to iCommerce > "iCommerce is the new standard for intelligent, autonomous commerce operations—built to end ops firefighting and deliver measurable outcomes." ## What is iCommerce? iCommerce (Intelligent Commerce) is a category for AI‑native, agentic operations that unify and autonomously run every critical commerce workflow end‑to‑end. It replaces app sprawl, brittle rules, and BPO with a single system that is intelligent, integrated, instant, invisible, iterative, and impactful. At StateSet, iCommerce also includes **agentic commerce**: AI agents that can safely take a buyer from conversation → checkout → payment → fulfillment → post‑purchase support without leaving the chat. ### The Six i's of iCommerce AI‑native, self‑learning agents transform rule‑based tasks into adaptive, outcome‑driven processes Unifies front office, back office, and data silos—eliminates API/spreadsheet sprawl Real‑time, autonomous execution across orders, inventory, returns, and CX—no human wait states Ops heavy lifting disappears; complexity is abstracted so teams focus on strategy and growth System continuously improves from every transaction; workflows self‑optimize over time Outcomes are measurable (ROI, margin, retention) with outcome‑based pricing tied to results *** ## Category Law: What belongs in iCommerce These criteria define inclusion in the iCommerce category. | Attribute | Definition | What is NOT iCommerce | | ----------- | ---------------------------------------------- | ------------------------------------------ | | Intelligent | AI‑native, self‑learning agents drive outcomes | Pure rules or dumb automations | | Integrated | Unifies front/back office and data | Point apps, silos, batch jobs | | Instant | Real‑time autonomous execution | Manual, delayed, batch | | Invisible | Ops complexity abstracted from humans | Ops firefighting, ticket triage | | Iterative | System improves with every transaction | Static/frozen workflows | | Impactful | Measurable outcomes and outcome‑based pricing | Seats/usage pricing with unmeasured impact | > Focus evaluation on outcomes delivered, not specific ML techniques. iCommerce is defined by the impact, not the algorithm. *** ## What iCommerce is not * Not just automation, iPaaS, or point SaaS—must replace manual ops, not add more tools * Not BPO—scale via software, not external labor * Not legacy eCommerce platforms—storefronts and shipping are insufficient for modern ops * Not static workflow bots—rules break as processes evolve; agents must learn and improve ### Competitive frame * Legacy SaaS → App sprawl, manual glue, silos; static point‑and‑click interfaces * iPaaS → Moves data but not outcomes; requires specialist setup and constant maintenance * BPO → Delayed, costly, opaque; knowledge walks out the door * Workflow automation → Brittle, rules‑driven; no continuous improvement * Early "AI agents" → Shallow integrations; no measurable business outcomes at scale *** ## Who iCommerce is for (ICP) * Industry: Modern DTC/DNVB and subscription brands with high order volume and AOV * Size: \$100M+ GMV is ideal; focus on Shopify Plus mid‑market and up * Geography: North America and UK/EU * Stack: Shopify Plus, composable commerce, ERP integrations (e.g., NetSuite), major 3PLs * Ops maturity: Lean ops/data teams seeking unified, intelligent operations * Anti‑ICP: Micro/long‑tail merchants; heavily bespoke legacy stacks; DIY IT refusing SaaS/cloud *** ## Outcomes and pricing * Outcome‑based model aligns value with results * Illustrative floor pricing tied to GMV: 0.004% of annual GMV, billed monthly * Unit economics example per Autonomous Outcome (AO): \~$0.11 cost → ~$1.20 recovered margin For brands at $100M GMV, minimum monthly charge ≈ $33,333. True iCommerce systems charge for successfully executed autonomous outcomes, not seats. *** ## The StateSet iCommerce Engine StateSet is the iCommerce company. Our iCommerce Engine is an AI‑native, self‑improving system that orchestrates and automates every operation end‑to‑end—delivering measurable outcomes with speed and simplicity. ### Why StateSet 10–15x ROI, 40%+ ARR expansion, 90%+ ops/BPO cost reduction One engine orchestrating orders, inventory, CX, finance, and supply chain in real time Pay for impact—not seats; full audit trails and guardrails Data/network effects: every transaction strengthens the engine ### Core capabilities * 100+ commerce integrations (Shopify, NetSuite, ERP, WMS, 3PL, CX, etc.) * Invisible onboarding with low‑code/no‑code admin * Durable orchestration with exception handling, continuous learning, and generative analytics across orders, fulfillment, and CX data *** ## The Agentic Commerce Offering (ACP + iCommerce) StateSet’s agentic commerce offering is the conversational, AI‑initiated transaction layer of the iCommerce Engine. It lets customers buy, track, return, and get support in one continuous dialogue while the platform handles every back‑office step. ### What’s included * **Agentic Commerce Protocol (ACP)** — A secure, standardized checkout and delegated‑payment protocol for AI agents. Agents can create a cart, update buyer/shipping details, request a scoped payment token, and complete checkout with explicit user consent. * **Commerce Agent Suite** — Specialized agents for product discovery, checkout, post‑purchase support, and operations (inventory, routing, sync). Each agent is tool‑driven and idempotent. * **Unified commerce backend** — The StateSet API and Sync Server execute the transaction end‑to‑end: orders, inventory reservations, payments, fulfillment routing, accounting entries, and real‑time status updates. * **MCP integration** — Agents plug into ChatGPT and other AI surfaces through the Model Context Protocol (MCP) for tool execution and rich in‑chat widgets. ### Why it matters * **New revenue channel**: purchases happen inside ChatGPT/voice/SMS with no site friction. * **Higher conversion**: one‑conversation checkout typically converts 3–5× better than web flows. * **Lower support cost**: AI resolves \~90% of “where’s my order / return / warranty” tickets instantly. * **Stronger trust**: scoped, time‑boxed payment tokens + full audit trails keep buyers in control. ### Learn more Build and integrate Agentic Commerce Protocol checkout and delegated payment flows. See how conversation‑to‑fulfillment runs end‑to‑end on the iCommerce Engine. *** ## From → To: The iCommerce transformation | From (Old World) | To (iCommerce Engine) | | ----------------------- | -------------------------------- | | Manual processes, BPO | Intelligent, autonomous agents | | SaaS sprawl, 10+ tools | Integrated, unified engine | | Batch delays, lag | Instant, real‑time orchestration | | Ops firefighting | Invisible, drama‑free operations | | Frozen/rule‑based flows | Iterative, self‑improving engine | | Unmeasured impact | Impactful, outcome‑based value | *** ## Proof and positioning * Lighthouse results: ARMRA, Mienne, and others demonstrating rapid, compounding value * Competitive differentiation: self‑learning agents, unified engine, outcome‑based pricing, referenceable proof * Category stewardship: StateSet defines, tests, and defends the iCommerce standard *** ## Learn more and get started Deep‑dive on the category definition, laws, ICP, and competitive context See iCommerce in action with the StateSet iCommerce Engine *** ### Commerce that runs itself. The iCommerce era is here. Build on the iCommerce Engine and replace ops firefighting with compounding outcomes. [Talk to our team →](https://calendly.com/stateset/icommerce-demo) # iCommerce Architecture Source: https://docs.stateset.com/icommerce-architecture How Stateset powers agentic commerce from conversation to fulfillment # Stateset iCommerce Architecture ## AI‑powered order flow from conversation to fulfillment Stateset iCommerce is a vertically integrated commerce operating system. It lets AI agents run a complete purchase and support lifecycle inside a natural conversation while the platform executes every operational step in the background. At a high level, the system combines: * **Conversational AI agents** for shopping, support, and operations * **Agentic Commerce Protocol (ACP)** for secure AI‑initiated checkout and delegated payment * **Model Context Protocol (MCP)** for tool execution and in‑chat widgets * **StateSet API** as the unified backend for orders, inventory, payments, fulfillment, returns, and finance * **StateSet Sync Server** for multi‑tenant routing and integrations (Shopify, ERPs, 3PLs, marketplaces) This document is the technical + business explainer for how those layers work together. For implementation details, see the linked guides at the end. *** ## System architecture ```mermaid theme={null} graph TD subgraph "Conversation & Agent Layer" U[Customer in ChatGPT / Voice / SMS] A[Commerce Agent] S[Customer Service Agent] O[Operations Agent] M[MCP Server & Widgets] end subgraph "Transaction Layer" ACP[Agentic Commerce Protocol] PAY[Delegated Payment Providers
Stripe, PayPal, etc.] end subgraph "Core iCommerce Engine" API[StateSet API
Orders · Inventory · Payments · Returns · Finance] SYNC[StateSet Sync Server
Multi‑tenant routing & jobs] DB[(PostgreSQL + Redis)] EVT[Event Bus / Outbox] end subgraph "External Integrations" MP[Marketplaces
Shopify · Amazon · TikTok · Walmart] ERP[ERP / Accounting
NetSuite · SAP · QuickBooks] WMS[3PL / WMS / Carriers
DCL · Cart.com · UPS] end U --> M M --> A M --> S M --> O A --> ACP ACP --> PAY ACP --> API ACP --> SYNC API <--> DB API --> EVT EVT --> SYNC SYNC <--> MP SYNC <--> ERP SYNC <--> WMS ``` ### Conversation & Agent Layer Three specialized agents collaborate in one session: * **Commerce Agent**: product discovery, recommendations, cart building, ACP checkout. * **Customer Service Agent**: tracking, returns, warranties, order modifications, escalation. * **Operations Agent**: inventory checks, fulfillment routing, sync jobs, exception handling. Agents invoke platform tools through **MCP**, which also renders rich widgets (product carousels, order records, tracking views) inline in the conversation. ### Transaction Layer (ACP) ACP is the secure “handshake” that allows an AI agent to initiate and complete purchases: 1. **Create checkout** with line items and currency. 2. **Update checkout** with buyer identity and shipping/billing details. 3. **Delegate payment** to get a *scoped, time‑boxed, single‑use token*. 4. **User confirms** in‑chat. 5. **Complete checkout** to capture payment and create the order. ACP guarantees explicit consent, auditability, and safe retries via idempotency. ### Core iCommerce Engine Once ACP completes, the iCommerce Engine executes the lifecycle: * **Orders**: creation, state machine, line items, split shipments. * **Inventory**: multi‑location availability, reservations, backorder logic. * **Payments**: capture, refunds, chargebacks (gateway‑agnostic). * **Fulfillment**: routing to the best warehouse/3PL, shipment records, tracking. * **Returns & warranties**: eligibility, labels, restock, replacement orders. * **Finance**: double‑entry postings for revenue, COGS, refunds. Everything is **event‑driven**: order/payment/fulfillment events flow through an outbox and fan out to integrations and UI updates. ### External Integrations The Sync Server provides: * Multi‑tenant configuration per merchant/brand. * Real‑time webhooks + batch sync jobs. * Field mapping and normalization. * Circuit breakers, retries, and per‑tenant rate limits. This is what lets iCommerce coexist with (or replace) existing stacks. *** ## End‑to‑end flow (conversation → fulfillment) 1. **Customer asks for a product** in natural language. 2. **Commerce Agent searches catalog** and presents options in a widget. 3. **Customer selects an item**; agent creates an **ACP checkout session**. 4. **Agent collects shipping/buyer details** conversationally and updates checkout. 5. **Agent delegates payment**; customer sees summary and explicitly confirms. 6. **ACP completes checkout**: payment captured and order created. 7. **Sync Server routes order** to the optimal fulfillment center. 8. **Inventory is reserved** at the chosen location. 9. **Fulfillment partner ships**; tracking updates stream back via webhooks. 10. **Customer Service Agent handles post‑purchase** (tracking, returns, warranty) in the same conversation. For a concrete multi‑agent Shopify → NetSuite → 3PL pipeline, see the workflows guide below. *** ## Security and trust model Agentic commerce must be safe by default. iCommerce enforces: * **Scoped delegated payments**: tokens are bound to a checkout session, amount, and expiry. * **Explicit consent**: the buyer must confirm before payment capture. * **Time limits + single use**: tokens expire quickly and cannot be replayed. * **Idempotency keys**: retries never double‑charge or duplicate orders. * **Audit trail**: every agent action and ACP call is logged with request IDs. * **PCI isolation**: sensitive payment data stays with the gateway. *** ## Adoption paths ### Merchants on an existing stack 1. **Enable ACP endpoints** for checkout and delegated payment. 2. **Register MCP tools** for product search, add‑to‑cart, order/return/tracking actions. 3. **Connect systems to the Sync Server** (Shopify/marketplaces, ERP, 3PL). 4. **Start with one workflow** (orders + tracking), then expand to returns, warranties, finance, and proactive ops. ### Marketplaces or multi‑brand operators 1. **Onboard each tenant** with isolated credentials, mappings, and rate limits. 2. **Share the agent layer** across tenants while keeping data and outcomes isolated. 3. **Route orders per tenant policy** (warehouse rules, SLA, costs). *** # iCommerce Paper Source: https://docs.stateset.com/icommerce-paper A technical paper on embedded, verifiable commerce systems for AI agents # StateSet iCommerce: Infrastructure for Autonomous Commerce **A Technical Paper on Embedded, Verifiable Commerce Systems for AI Agents** *** ## Abstract StateSet iCommerce is a comprehensive infrastructure stack enabling autonomous AI agents to conduct commerce operations with cryptographic verifiability. The system comprises five integrated components: (1) an embedded commerce engine providing 700+ API methods across 32 commerce domains, compiled to 10 language runtimes; (2) a distributed event sequencer implementing Verifiable Event Sync (VES) with Merkle commitments and end-to-end encryption; (3) Set Chain, an Ethereum Layer-2 optimistic rollup for on-chain settlement and proof verification; (4) the x402 HTTP-native payment protocol for stablecoin micropayments between AI agents; and (5) a multi-channel messaging gateway connecting commerce agents to 9 communication platforms. This paper presents the architecture, implementation details, and design rationale for building commerce infrastructure where AI agents are first-class participants in economic transactions. **Keywords:** embedded databases, event sourcing, AI agents, commerce, blockchain, Merkle trees, optimistic rollups, MCP, x402, vector search, messaging gateway *** ## 1. Introduction ### 1.1 The Problem Traditional commerce platforms were designed for human operators accessing centralized services via network APIs. This architecture introduces several limitations for autonomous AI agents: 1. **Latency:** Network round-trips add 50-500ms per operation 2. **Availability:** Agents cannot operate without network connectivity 3. **Auditability:** No cryptographic proof that operations occurred correctly 4. **Cost:** Per-API-call pricing creates unpredictable marginal costs 5. **Trust:** Agents must trust centralized providers for data integrity 6. **Payments:** No native mechanism for agent-to-agent economic settlement 7. **Communication:** No unified channel for agent-customer interaction across platforms As AI agents increasingly participate in economic activity—managing inventory, processing orders, coordinating supply chains, handling customer service across messaging platforms—these limitations become critical barriers. ### 1.2 Our Contribution We present StateSet iCommerce, a five-layer infrastructure stack addressing these challenges: | Layer | Component | Function | | ----------------- | ------------------ | ------------------------------- | | **Compute** | stateset-embedded | In-process commerce engine | | **Coordination** | stateset-sequencer | Distributed event ordering | | **Settlement** | Set Chain (L2) | On-chain verification | | **Payments** | x402 Protocol | HTTP-native stablecoin payments | | **Communication** | Messaging Gateway | 9-channel agent interaction | The system enables: * **Offline-first operation:** Complete commerce functionality without network * **Cryptographic verifiability:** Merkle proofs for any transaction * **Multi-agent coordination:** Deterministic ordering across distributed agents with end-to-end encryption * **Settlement finality:** Ethereum-backed proof anchoring * **Native payments:** Stablecoin micropayments via HTTP 402 * **Omnichannel presence:** AI agents operating across WhatsApp, Telegram, Discord, Slack, and more * **Semantic search:** Hybrid vector + BM25 search across all commerce entities * **Voice interaction:** Speech-to-text and text-to-speech for conversational commerce ### 1.3 Paper Organization Section 2 describes the embedded commerce engine architecture. Section 3 details the Verifiable Event Sync protocol. Section 4 presents Set Chain and on-chain settlement. Section 5 introduces the x402 payment protocol. Section 6 discusses the Model Context Protocol integration for AI agents. Section 7 covers the multi-channel messaging gateway. Section 8 presents operational infrastructure including heartbeat monitoring, permission sandboxing, and persistent memory. Section 9 evaluates performance and security properties. Section 10 surveys related work, and Section 11 concludes. *** ## 2. Embedded Commerce Engine ### 2.1 Design Philosophy The embedded commerce engine follows the SQLite model: a library that runs in the application's process, storing state in a local file with zero external dependencies. This architecture provides: * **Deterministic execution:** Same inputs always produce identical outputs * **Portable state:** Single file contains complete operational data * **Zero marginal cost:** No per-operation pricing * **Instant availability:** No network connection required ### 2.2 System Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ stateset-icommerce │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ │ │ │ stateset-core │ Pure domain models (400+ types) │ │ │ ~45,000 LOC │ Zero I/O dependencies │ │ └────────┬────────┘ Business logic, traits, metrics │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ stateset-db │ Database abstraction layer │ │ │ ~55,000 LOC │ SQLite + PostgreSQL backends │ │ └────────┬────────┘ 70+ tables, 28 migrations │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │stateset-embedded│ Unified high-level API │ │ │ ~39,000 LOC │ 700+ public methods │ │ └────────┬────────┘ Sync + Async, event emission, transactions │ │ │ │ ├────────────┼────────────────────────────────────────────────────────┤ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Language Bindings (10) │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │Node.js │ │ Python │ │ WASM │ │ Ruby │ │ PHP │ │ │ │ │ │ (NAPI) │ │ (PyO3) │ │(wasm) │ │(Magnus)│ │(ext-rs)│ │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ Java │ │ Kotlin │ │ Swift │ │ .NET │ │ Go │ │ │ │ │ │ (JNI) │ │ (JNI) │ │ (FFI) │ │(P/Inv) │ │ (cgo) │ │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 2.3 Domain Model The core domain consists of 32 modules covering complete commerce and back-office operations: **Commerce Operations:** | Module | Entities | Key Operations | | ----------------- | --------------------------- | ------------------------------------- | | **Customers** | Customer, Address | CRUD, profile management | | **Products** | Product, Variant, Attribute | Catalog, pricing, inventory links | | **Inventory** | Item, Balance, Reservation | Multi-location tracking, reservations | | **Orders** | Order, OrderItem, Status | Full lifecycle, fulfillment | | **Carts** | Cart, CartItem | Shopping, checkout flow | | **Payments** | Payment, Refund, Method | Multi-method processing | | **Returns** | Return, ReturnItem, RMA | Return authorization workflow | | **Shipments** | Shipment, Event, Tracking | Carrier integration | | **Promotions** | Promotion, Coupon, Rule | Discounts, BOGO, tiered | | **Subscriptions** | Plan, Subscription, Cycle | Recurring billing | **Supply Chain & Warehouse:** | Module | Entities | Key Operations | | ------------------- | ---------------------------------------- | ------------------------------------ | | **Warehouse** | Warehouse, Zone, Location | Location hierarchy, bin management | | **Receiving** | Receipt, ReceiptItem, PutAway | Inbound goods, put-away tracking | | **Fulfillment** | Wave, PickTask, PackTask, ShipTask | Pick/pack/ship workflow | | **Lot Tracking** | Lot, LotCertificate, LotTransaction | Traceability, COA/COC management | | **Serial Numbers** | SerialNumber, SerialHistory | Unit-level tracking, warranty lookup | | **Backorders** | Backorder, Allocation, Fulfillment | Priority queuing, allocation | | **Manufacturing** | BOM, WorkOrder, Task | Bill of materials | | **Purchase Orders** | PO, Supplier | Procurement | | **Quality** | Inspection, NCR, QualityHold, DefectCode | Multi-stage QC, non-conformance | **Financial:** | Module | Entities | Key Operations | | ----------------------- | -------------------------------------------- | ----------------------------------------- | | **General Ledger** | GlAccount, JournalEntry, GlPeriod | Double-entry, auto-posting, trial balance | | **Accounts Receivable** | CreditMemo, WriteOff, CollectionActivity | AR aging, statements, collections | | **Accounts Payable** | Bill, BillPayment, PaymentRun | AP aging, payment scheduling | | **Invoices** | Invoice, Item, AR | Accounts receivable | | **Cost Accounting** | CostLayer, CostAdjustment, CostVariance | FIFO/LIFO/weighted average, valuation | | **Credit** | CreditAccount, CreditApplication, CreditHold | Credit review, risk rating | | **Tax** | Jurisdiction, Rate, Exemption | US/EU/CA multi-jurisdiction | | **Currency** | ExchangeRate, Money | 35+ currencies | **Platform:** | Module | Entities | Key Operations | | ----------------- | ------------------------------------------- | ------------------------------- | | **x402** | PaymentIntent, PaymentReceipt, PaymentBatch | HTTP-native stablecoin payments | | **Vector Search** | VectorSearchResult, EmbeddingMetadata | Hybrid semantic + BM25 search | | **Analytics** | Summary, Forecast | Business intelligence | | **Warranties** | Warranty, Claim | Coverage tracking | | **Forecasting** | ForecastModel, DemandSignal | Demand planning | | **Sync** | Outbox, SyncState | Event synchronization | **Total:** 400+ domain types with full serde serialization. ### 2.4 Database Layer The database layer provides a unified interface over multiple backends: **SQLite (Embedded)** * Zero-configuration deployment * Single-file state portability * ACID transactions via WAL mode * \~200μs typical query latency * FTS5 full-text search for BM25 ranking * BLOB-based vector embedding storage **PostgreSQL (Enterprise)** * Horizontal scalability * Advanced query optimization * Point-in-time recovery * Connection pooling * True async operations via `AsyncCommerce` API **Schema Design Principles:** 1. **Normalized core entities:** Customers, products, orders 2. **Denormalized analytics:** Pre-aggregated summary tables 3. **Event tables:** Append-only for audit trail 4. **Version columns:** Optimistic concurrency control 5. **Vector tables:** Embedding storage with metadata for semantic search 6. **FTS5 tables:** Full-text search indexes for BM25 ranking **Database Infrastructure:** | Feature | Description | | ------------------------ | ------------------------------------------------------------------- | | **Saga Orchestration** | Multi-step distributed transactions with rollback | | **Backup & Restore** | Full backups (VACUUM INTO), SHA256 verification, retention policies | | **Idempotency Keys** | Deduplication at the database level | | **Performance Indexes** | Dedicated migration for query optimization | | **Parse Helpers** | Type-safe row parsing with proper error propagation | | **Repository Macros** | Code generation to eliminate duplicate implementations | | **32 Repository Traits** | One trait per domain with full CRUD + domain operations | ### 2.5 Vector Search The embedded engine supports hybrid semantic + keyword search, feature-gated behind the `vector` flag: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Hybrid Search Pipeline │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Query: "red running shoes under $100" │ │ │ │ │ ├──────────────────┬───────────────────┐ │ │ ▼ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Semantic │ │ BM25 │ │ Filters │ │ │ │ (Cosine) │ │ (FTS5) │ │ (price<100) │ │ │ │ 1536-dim │ │ Tokenized │ │ Structured │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ └──────────────────┼───────────────────┘ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Reciprocal Rank │ │ │ │ Fusion (RRF) │ │ │ └────────┬─────────┘ │ │ ▼ │ │ Ranked Results │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` **Components:** * **Embedding Service:** OpenAI `text-embedding-3-small` (1536 dimensions) for generating vectors * **Vector Store:** Pure Rust cosine similarity computation over SQLite BLOB columns * **BM25 Store:** SQLite FTS5 full-text search for keyword relevance * **RRF Fusion:** Reciprocal Rank Fusion combines semantic and keyword scores * **Entity Coverage:** Products, customers, orders, and inventory items **API:** ```rust theme={null} // Index a product for search commerce.vector().index_product(&product_id).await?; // Hybrid search let results = commerce.vector().search_products("red shoes", 10).await?; ``` ### 2.6 Multi-Runtime Compilation The Rust core compiles to 10 target runtimes: | Runtime | Technology | Use Case | | ----------- | -------------- | ---------------------------------- | | Native Rust | Direct linking | High-performance backends | | Node.js | NAPI-RS | JavaScript/TypeScript applications | | Python | PyO3 + Maturin | Data science, ML pipelines | | Browser | wasm-pack | Client-side applications | | Edge | WASM | Cloudflare Workers, Vercel Edge | | **Ruby** | Magnus | Rails applications | | **PHP** | ext-php-rs | Laravel/WordPress integrations | | **Java** | JNI | Enterprise JVM applications | | **Kotlin** | JNI | Android, server-side Kotlin | | **Swift** | C FFI | iOS/macOS applications | | **.NET/C#** | P/Invoke | ASP.NET, Unity applications | | **Go** | cgo | Go microservices | Each binding exposes the full 700+ method API with native type mappings. ### 2.7 Async Commerce API For PostgreSQL deployments, a fully async API is provided: ```rust theme={null} // Feature-gated behind `postgres` let commerce = AsyncCommerce::builder() .postgres_url("postgresql://localhost/stateset") .max_connections(20) .build() .await?; let orders = commerce.orders().list(None, Some(50)).await?; let customer = commerce.customers().get(&customer_id).await?; ``` The `AsyncCommerce` struct mirrors the synchronous `Commerce` API, providing `AsyncOrders`, `AsyncCustomers`, `AsyncInventory`, and all 32 domain accessors with true non-blocking I/O. *** ## 3. Verifiable Event Sync (VES) ### 3.1 Motivation When multiple AI agents operate on commerce data—one managing inventory, another processing orders, a third handling returns—they must coordinate without central authority. VES provides: 1. **Canonical ordering:** Global sequence numbers eliminate ambiguity 2. **Eventual consistency:** Offline agents sync when reconnected 3. **Conflict detection:** Optimistic concurrency with explicit handling 4. **Cryptographic proofs:** Merkle trees enable verification 5. **End-to-end encryption:** Agent-to-agent encrypted communication groups 6. **Key management:** Ed25519/X25519 key generation, rotation, and registration ### 3.2 Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ VES Architecture │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ Agent A │ │ Agent B │ │ Agent C │ │ │ │ (Orders) │ │ (Inventory) │ │ (Returns) │ │ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ │ │ SQLite │ │ │ │ SQLite │ │ │ │ SQLite │ │ │ │ │ │ Outbox │ │ │ │ Outbox │ │ │ │ Outbox │ │ │ │ │ └────┬────┘ │ │ └────┬────┘ │ │ └────┬────┘ │ │ │ │ ┌────┴────┐ │ │ ┌────┴────┐ │ │ ┌────┴────┐ │ │ │ │ │Ed25519 │ │ │ │Ed25519 │ │ │ │Ed25519 │ │ │ │ │ │Keystore │ │ │ │Keystore │ │ │ │Keystore │ │ │ │ │ └────┬────┘ │ │ └────┬────┘ │ │ └────┬────┘ │ │ │ └───────┼───────┘ └───────┼───────┘ └───────┼───────┘ │ │ │ │ │ │ │ └─────────────────────┼─────────────────────┘ │ │ │ │ │ Encrypted Push/Pull │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ stateset-sequencer │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ │ │ Ingest │ │ Sequencer │ │ Commitment Engine │ │ │ │ │ │ (Dedup) │──│ (Order) │──│ (Merkle Roots) │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │Key Registry │ │ Encryption │ │ │ │ │ │ (Ed25519) │ │ Groups │ │ │ │ │ └─────────────┘ └─────────────┘ │ │ │ │ │ │ │ │ │ │ ▼ ▼ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ PostgreSQL Event Store │ │ │ │ │ │ events │ sequence_counters │ commitments │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 3.3 Event Envelope Every operation emits an event envelope: ```rust theme={null} pub struct EventEnvelope { // Identity pub event_id: Uuid, // Global idempotency key pub command_id: Option, // Intent-level deduplication // Routing pub tenant_id: TenantId, // Organization isolation pub store_id: StoreId, // Store within tenant // Classification pub entity_type: EntityType, // order, product, inventory... pub entity_id: String, // Entity identifier pub event_type: EventType, // order.created, inventory.adjusted... // Payload pub payload: serde_json::Value, // JSON event data pub payload_hash: Hash256, // SHA-256 of canonical JSON // Ordering pub base_version: Option, // OCC version at authoring pub sequence_number: Option, // Assigned by sequencer // Provenance pub created_at: DateTime, pub source_agent: AgentId, pub signature: Option>, } ``` ### 3.4 Sequencing Algorithm The sequencer assigns canonical sequence numbers: ``` Algorithm: EventSequencing Input: EventBatch from agent Output: IngestReceipt with assigned sequences 1. DEDUPLICATION for each event in batch: if event.event_id exists in events table: reject as DuplicateEventId if event.command_id exists in events table: reject as DuplicateCommandId 2. VALIDATION for each event in batch: computed_hash = SHA256(canonical_json(event.payload)) if computed_hash != event.payload_hash: reject as InvalidPayloadHash validate schema for event.entity_type, event.event_type 3. SEQUENCE ALLOCATION (atomic) count = batch.events.length (start, end) = UPDATE sequence_counters SET current_sequence = current_sequence + count WHERE tenant_id = ? AND store_id = ? RETURNING current_sequence - count, current_sequence - 1 4. STORAGE (atomic) for i, event in enumerate(batch.events): event.sequence_number = start + i INSERT INTO events (event) ON CONFLICT (event_id) DO NOTHING 5. RETURN IngestReceipt { batch_id: new_uuid(), events_accepted: count - rejected_count, assigned_sequence_start: start, assigned_sequence_end: end, head_sequence: end } ``` ### 3.5 Merkle Commitment Events are batched into Merkle trees for cryptographic commitment: ``` Merkle Tree Construction: Root Hash / \ / \ H(01) H(23) / \ / \ H(0) H(1) H(2) H(3) | | | | Leaf0 Leaf1 Leaf2 Leaf3 Leaf[i] = SHA256(payload_hash || sequence || entity_type || entity_id) ``` **BatchCommitment Structure:** ```rust theme={null} pub struct BatchCommitment { pub batch_id: Uuid, pub tenant_id: TenantId, pub store_id: StoreId, pub prev_state_root: Hash256, // State before batch pub new_state_root: Hash256, // State after batch pub events_root: Hash256, // Merkle root of events pub event_count: u32, pub sequence_range: (u64, u64), pub committed_at: DateTime, pub chain_tx_hash: Option, // On-chain anchor } ``` ### 3.6 Optimistic Concurrency Control VES uses optimistic concurrency without blocking: ``` OCC Flow: 1. Agent authors event with base_version = 5 (current entity version) 2. Event pushed to sequencer, stored with base_version = 5 3. Projector applies event: - Get current entity version (now = 7) - Check: base_version (5) != current (7) - CONFLICT DETECTED 4. Projector emits: event.rejected { reason: VersionConflict } 5. Event log remains immutable; rejection tracked 6. Agent receives rejection notification ``` **Key Principle:** Events are never rejected at sequencing time due to version conflicts. The event log is immutable. Conflicts are detected and recorded at projection time. ### 3.7 Conflict Resolution Strategies When conflicts are detected, VES supports multiple resolution strategies: | Strategy | Behavior | Use Case | | --------------- | ------------------------ | ------------------------ | | **Remote-wins** | Accept sequencer version | Default for inventory | | **Local-wins** | Prefer local agent state | Agent-authoritative data | | **Merge** | Field-level merge | Non-conflicting updates | | **Manual** | Queue for human review | High-value transactions | Conflict resolution is configurable per entity type, allowing different strategies for different domains. ### 3.8 Key Management and Encryption VES includes a complete cryptographic key management system: **Key Generation and Registration:** ``` Agent Key Lifecycle: 1. GENERATE: Ed25519 signing key + X25519 encryption key 2. REGISTER: Publish public keys to sequencer key registry 3. ROTATE: Time-based or usage-based rotation policies 4. REVOKE: Mark keys as revoked in registry ``` **Encryption Groups:** * Multi-agent groups with shared encryption contexts * X25519 key exchange for group secret derivation * Per-message encryption for sensitive commerce data (payment details, PII) * Group membership management (add/remove agents) **Rotation Policies:** | Policy | Trigger | Description | | ----------- | --------------------- | --------------------------------- | | Time-based | Configurable interval | Rotate keys every N hours/days | | Usage-based | Operation count | Rotate after N signing operations | | Manual | Admin action | Force rotation on demand | ### 3.9 Local Outbox Pattern Each agent maintains a local SQLite outbox: ```sql theme={null} CREATE TABLE outbox ( local_seq INTEGER PRIMARY KEY AUTOINCREMENT, event_id TEXT UNIQUE NOT NULL, command_id TEXT, tenant_id TEXT NOT NULL, store_id TEXT NOT NULL, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, event_type TEXT NOT NULL, payload TEXT NOT NULL, payload_hash TEXT NOT NULL, base_version INTEGER, source_agent TEXT NOT NULL, created_at TEXT NOT NULL, -- Sync tracking sync_status TEXT DEFAULT 'pending', remote_sequence INTEGER, synced_at TEXT, rejection_reason TEXT ); ``` **Sync Flow:** 1. Mutation occurs locally → event appended to outbox 2. Agent pushes pending events to sequencer 3. Sequencer returns IngestReceipt with sequence numbers 4. Agent updates outbox with remote\_sequence, synced\_at 5. Agent pulls events from other agents 6. Events applied locally, entity versions updated *** ## 4. Set Chain: On-Chain Settlement ### 4.1 Overview Set Chain is an Ethereum Layer-2 optimistic rollup built on the OP Stack, providing cryptographic finality for commerce events. **Chain Parameters:** | Parameter | Value | | ---------------- | -------------------------- | | Chain ID | 84532001 | | Block Time | 2 seconds | | Gas Limit | 30M per block | | Settlement Layer | Ethereum (Sepolia/Mainnet) | | Native Token | ETH | ### 4.2 Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Set Chain Architecture │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ stateset-sequencer │ │ │ │ (Batch Commitments) │ │ │ └────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ GET /v1/commitments/pending │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ set-anchor │ │ │ │ (Rust Service) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ Poll → Validate → Submit → Notify │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─► POST /anchored │ │ │ │ │ │ │ │ └─► SetRegistry.commitBatch() │ │ │ │ │ │ │ └─► Min events, hash verification │ │ │ │ │ │ └─► Sequencer API │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ Ethereum Transaction │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Set Chain L2 (OP Stack) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ SetRegistry.sol │ │ │ │ │ │ - commitBatch(batchId, roots, sequences) │ │ │ │ │ │ - verifyInclusion(batchId, leafHash, proof) │ │ │ │ │ │ - getLatestStateRoot(tenantId, storeId) │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ SetPaymaster.sol │ │ │ │ │ │ - Gas sponsorship for merchants │ │ │ │ │ │ - Tiered limits (Starter/Growth/Enterprise) │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ Batch Submission (L2 → L1) │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Ethereum L1 (Sepolia/Mainnet) │ │ │ │ OptimismPortal │ L2OutputOracle │ SystemConfig │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 4.3 SetRegistry Contract The SetRegistry stores batch commitments and enables proof verification: ```solidity theme={null} contract SetRegistry is UUPSUpgradeable, OwnableUpgradeable { struct BatchCommitment { bytes32 eventsRoot; // Merkle root of events bytes32 prevStateRoot; // State root before batch bytes32 newStateRoot; // State root after batch uint64 sequenceStart; // First sequence in batch uint64 sequenceEnd; // Last sequence in batch uint32 eventCount; // Number of events uint256 committedAt; // Block timestamp } // Storage mapping(bytes32 => BatchCommitment) public batches; mapping(bytes32 => bytes32) public latestStateRoot; // tenant+store → root mapping(bytes32 => uint64) public headSequence; // tenant+store → seq mapping(address => bool) public authorizedSequencers; function commitBatch( bytes32 batchId, bytes32 tenantId, bytes32 storeId, bytes32 eventsRoot, bytes32 prevStateRoot, bytes32 newStateRoot, uint64 sequenceStart, uint64 sequenceEnd, uint32 eventCount ) external onlyAuthorizedSequencer { // Validate state continuity bytes32 key = keccak256(abi.encodePacked(tenantId, storeId)); require(prevStateRoot == latestStateRoot[key], "State discontinuity"); // Store commitment batches[batchId] = BatchCommitment({ eventsRoot: eventsRoot, prevStateRoot: prevStateRoot, newStateRoot: newStateRoot, sequenceStart: sequenceStart, sequenceEnd: sequenceEnd, eventCount: eventCount, committedAt: block.timestamp }); // Update latest state latestStateRoot[key] = newStateRoot; headSequence[key] = sequenceEnd; emit BatchCommitted(batchId, tenantId, storeId, eventsRoot); } function verifyInclusion( bytes32 batchId, bytes32 leafHash, bytes32[] calldata proof, uint256 leafIndex ) external view returns (bool) { bytes32 computedRoot = leafHash; for (uint256 i = 0; i < proof.length; i++) { if (leafIndex % 2 == 0) { computedRoot = keccak256(abi.encodePacked(computedRoot, proof[i])); } else { computedRoot = keccak256(abi.encodePacked(proof[i], computedRoot)); } leafIndex /= 2; } return computedRoot == batches[batchId].eventsRoot; } } ``` ### 4.4 Anchor Service The Rust anchor service bridges sequencer to chain: ```rust theme={null} pub struct AnchorService { sequencer_client: SequencerClient, registry_client: SetRegistryClient, config: AnchorConfig, } impl AnchorService { pub async fn run(&self) -> Result<()> { loop { // 1. Fetch pending commitments let pending = self.sequencer_client .get_pending_commitments() .await?; // 2. Filter by minimum events threshold let eligible: Vec<_> = pending .into_iter() .filter(|c| c.event_count >= self.config.min_events) .collect(); // 3. Submit each to SetRegistry for commitment in eligible { match self.submit_commitment(&commitment).await { Ok(tx_hash) => { // 4. Notify sequencer of success self.sequencer_client .notify_anchored(&commitment.batch_id, &tx_hash) .await?; self.metrics.anchored_batches.inc(); } Err(e) => { self.metrics.failed_anchors.inc(); // Retry on next iteration } } } tokio::time::sleep(self.config.poll_interval).await; } } } ``` ### 4.5 Settlement Finality The system provides progressive finality guarantees: | Stage | Latency | Guarantee | | ---------------- | -------- | ------------------------ | | Local SQLite | \~1ms | Single-agent consistency | | Sequencer | \~100ms | Global ordering | | L2 Block | \~2s | Chain inclusion | | L1 Batch | \~10min | Optimistic finality | | Challenge Period | \~7 days | Cryptographic finality | **Verification Flow:** 1. User requests proof for event E 2. Sequencer returns Merkle proof from batch B 3. User calls SetRegistry.verifyInclusion(B, E.leafHash, proof) 4. Contract recomputes root, compares to stored eventsRoot 5. Returns true if event is included in anchored batch *** ## 5. x402 Payment Protocol ### 5.1 Overview The x402 protocol enables HTTP-native stablecoin micropayments between AI agents. Using the HTTP 402 (Payment Required) status code, agents can negotiate and settle payments inline with commerce API calls. ### 5.2 Protocol Flow ``` ┌─────────────────────────────────────────────────────────────────────┐ │ x402 Payment Flow │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Agent A (Buyer) Agent B (Seller) │ │ │ │ │ │ │ 1. GET /api/products/123 │ │ │ │─────────────────────────────────►│ │ │ │ │ │ │ │ 2. HTTP 402 Payment Required │ │ │ │ { │ │ │ │ asset: "USDC", │ │ │ │ amount: "0.001", │ │ │ │ network: "set-chain", │ │ │ │ recipient: "0x...", │ │ │ │ validity: 300 │ │ │ │ } │ │ │ │◄─────────────────────────────────│ │ │ │ │ │ │ │ 3. Sign PaymentIntent │ │ │ │ (Ed25519 signature) │ │ │ │ │ │ │ │ 4. GET /api/products/123 │ │ │ │ X-Payment: │ │ │ │─────────────────────────────────►│ │ │ │ │ │ │ │ 5. Verify → Settle → Respond │ │ │ │ X-Payment-Receipt: │ │ │ │◄─────────────────────────────────│ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 5.3 Supported Networks | Network | Chain ID | Assets | Status | | --------- | -------- | ----------- | ---------- | | Set Chain | 84532001 | ssUSD, USDC | Production | | Arc | — | ssUSD | Production | | Base | 8453 | USDC | Production | | Ethereum | 1 | USDC, USDT | Production | | Arbitrum | 42161 | USDC | Production | | Optimism | 10 | USDC | Production | | Solana | — | USDC | Production | Testnets are supported for all networks. ### 5.4 Core Types ```rust theme={null} pub struct X402PaymentIntent { pub version: String, // "x402/1.0" pub asset: X402Asset, // USDC, ssUSD, etc. pub amount: String, // Decimal amount pub network: X402Network, // Target chain pub recipient: String, // Recipient address pub validity_seconds: u64, // Payment window pub nonce: String, // Replay protection pub domain_separator: String, // EIP-712 domain pub signature: Vec, // Ed25519 signature } pub struct X402PaymentReceipt { pub intent_hash: Hash256, // Hash of signed intent pub tx_hash: Option, // On-chain settlement tx pub settled_at: DateTime, pub network: X402Network, pub status: PaymentStatus, // Pending, Settled, Failed } pub struct X402PaymentBatch { pub batch_id: Uuid, pub intents: Vec, pub merkle_root: Hash256, // Batch Merkle root pub total_amount: String, } ``` ### 5.5 Agent Wallet Integration Agent wallets are derived from VES signing keys, enabling unified identity across event signing and payment settlement: ``` VES Ed25519 Key → Derive payment address → Sign x402 intents → Verify receipts ``` Multi-chain balance checking allows agents to inspect their holdings across all supported networks via the `stateset-pay` CLI. *** ## 6. Model Context Protocol Integration ### 6.1 MCP Architecture The CLI exposes commerce operations via the Model Context Protocol (MCP), enabling AI agents to invoke tools directly: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Agent SDK Integration (v0.3.1) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ @stateset/cli │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ claude-harness.js (62KB) │ │ │ │ │ │ - Multi-agent routing + skills injection │ │ │ │ │ │ - Session management + persistent memory │ │ │ │ │ │ - Voice mode + multi-provider switching │ │ │ │ │ │ - Sync integration + event capture │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ mcp-server.js (221KB) │ │ │ │ │ │ - MCP tools across 32 domains │ │ │ │ │ │ - Permission gating (--apply flag) │ │ │ │ │ │ - Schema validation + tool composition │ │ │ │ │ │ - Telemetry integration │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Specialized Agents │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │checkout│ │ orders │ │ inv │ │returns │ │ sync │ │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌─────────┐ │ │ │ │ │ promo │ │ subs │ │ tax │ │analytics│ │ │ │ │ └────────┘ └────────┘ └────────┘ └─────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Skills System (38) │ │ │ │ Domain knowledge injected per-agent from SKILL.md files │ │ │ │ accounts-payable │ fulfillment │ general-ledger │ quality │ │ │ │ warehouse │ receiving │ lots-and-serials │ vector-search │ │ │ │ cost-accounting │ credit │ backorders │ autonomous-engine │ │ │ │ ... and 26 more │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ AI Providers (4) │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ Claude │ │ OpenAI │ │ Gemini │ │ Ollama │ │ │ │ │ │ (Full) │ │ (Chat) │ │ (Chat) │ │(Local) │ │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 6.2 Tool Categories **MCP Tools by Domain:** | Domain | Examples | | ------------------- | ------------------------------------------------- | | Customers | list\_customers, get\_customer, create\_customer | | Orders | create\_order, ship\_order, cancel\_order | | Products | list\_products, create\_product | | Inventory | get\_stock, adjust\_inventory, reserve\_inventory | | Returns | create\_return, approve\_return | | Carts/Checkout | create\_cart, add\_cart\_item, complete\_checkout | | Payments | create\_payment, process\_refund | | Analytics | get\_sales\_summary, get\_demand\_forecast | | Currency | convert\_currency, set\_exchange\_rate | | Tax | calculate\_tax, calculate\_cart\_tax | | Promotions | create\_promotion, validate\_coupon | | Subscriptions | create\_subscription, pause\_subscription | | Warehouse | create\_warehouse, assign\_location | | Fulfillment | create\_wave, assign\_pick\_task | | Quality | create\_inspection, record\_ncr | | Lots/Serials | create\_lot, assign\_serial | | General Ledger | post\_journal\_entry, get\_trial\_balance | | Accounts Payable | create\_bill, schedule\_payment | | Accounts Receivable | apply\_payment, generate\_statement | | Cost Accounting | record\_cost\_layer, get\_valuation | | **Sync** | sync\_status, sync\_push, sync\_pull | ### 6.3 Skills System The CLI includes a skills system that injects domain-specific knowledge into agent prompts: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Skills Architecture │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ skills/ │ │ ├── general-ledger/ │ │ │ └── SKILL.md # GL domain expertise, double-entry │ │ │ accounting rules, period management │ │ ├── fulfillment/ │ │ │ └── SKILL.md # Pick/pack/ship workflows, wave │ │ │ planning, carrier integration │ │ ├── quality/ │ │ │ └── SKILL.md # Inspection types, NCR handling, │ │ │ quality hold procedures │ │ └── ... (38 total) │ │ │ │ Infrastructure: │ │ ├── loader.js # Load skills from filesystem │ │ ├── parser.js # Parse SKILL.md files │ │ ├── registry.js # In-memory skill registry │ │ ├── injector.js # Inject into agent system prompts │ │ └── marketplace.js # Browse/install community skills │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` Each SKILL.md file contains structured domain knowledge: entity descriptions, workflow steps, troubleshooting guides, and usage examples. When an agent is routed to handle a request, its relevant skills are injected into the system prompt, giving it deep domain expertise. **38 Built-in Skills:** accounts-payable, accounts-receivable, analytics, autonomous-engine, autonomous-runbook, backorders, checkout, cost-accounting, credit, currency, customer-service, customers, embedded-sdk, engine-setup, events, fulfillment, general-ledger, inventory, invoices, lots-and-serials, manufacturing, mcp-tools, orders, payments, products, promotions, quality, receiving, returns, shipments, storefront, subscriptions, suppliers, sync, tax, vector-search, warehouse, warranties. ### 6.4 Multi-Provider AI Support The CLI supports multiple AI providers with a unified interface: | Provider | Models | MCP Tools | Mode | | ---------- | -------------------------------- | --------- | ----------------- | | **Claude** | claude-sonnet-4-20250514 | Full | Agent SDK + MCP | | **OpenAI** | gpt-4o, gpt-4, o1 | None | Chat-only | | **Gemini** | gemini-2.0-flash, gemini-2.0-pro | None | Chat-only | | **Ollama** | llama3, mistral, etc. | None | Chat-only (local) | Claude operates as the primary agent with full MCP tool access. Non-Claude providers operate in chat-only mode, providing conversational assistance without direct commerce operations. This allows users to choose their preferred model while maintaining full functionality through Claude. ### 6.5 Voice Mode The CLI supports voice-based interaction for conversational commerce: ``` stateset-chat --voice --tts-provider elevenlabs --stt-provider whisper ``` | Component | Provider | Description | | ------------------ | ------------------- | ----------------------------- | | Speech-to-Text | OpenAI Whisper | Audio transcription | | Text-to-Speech | ElevenLabs | Natural voice synthesis | | Session Management | VoiceModeController | Per-session state, 30-min TTL | Voice sessions maintain state with automatic cleanup of stale sessions. ### 6.6 Permission Model All write operations require explicit opt-in: ```javascript theme={null} // Read operations - always allowed stateset "list orders" stateset "what's my inventory for SKU-001?" // Write operations - blocked by default stateset "create an order for alice@example.com" // → Shows preview, does not execute // Write operations - enabled with --apply stateset --apply "create an order for alice@example.com" // → Executes operation, captures event to outbox ``` ### 6.7 Agent Routing The harness automatically routes requests to specialized agents: ```javascript theme={null} const AGENT_KEYWORDS = { 'checkout': ['cart', 'checkout', 'add to cart', 'buy'], 'orders': ['order', 'ship', 'tracking', 'fulfill'], 'inventory': ['stock', 'inventory', 'reserve'], 'returns': ['return', 'rma', 'refund'], 'sync': ['sync', 'push events', 'outbox', 'sequencer'], // ... }; function routeToAgent(request) { // Score each agent based on keyword matches // Return agent with highest score // Default to 'customer-service' (all tools) } ``` ### 6.8 Event Capture Integration When sync is configured, commerce operations automatically emit events: ```javascript theme={null} // In claude-harness.js const rawSyncConfig = loadSyncConfig(); if (rawSyncConfig) { commerce = wrapCommerceWithEvents(commerce, syncConfig); } // Every mutation now: // 1. Executes the operation // 2. Appends event to _ves_outbox // 3. Available for sync_push to sequencer ``` *** ## 7. Multi-Channel Messaging Gateway ### 7.1 Overview The messaging gateway enables AI commerce agents to operate across 9 communication platforms, providing omnichannel customer service, order management, and proactive notifications. ### 7.2 Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Messaging Gateway Architecture │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │WhatsApp│ │Telegram│ │Discord │ │ Slack │ │ Signal │ │ │ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ │ │ │ │ │ │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ GChat │ │WebChat │ │iMessage│ │ Teams │ │ │ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ │ │ │ │ │ │ │ │ └──────────┴──────────┴──────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Gateway Core │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ Session │ │Middleware│ │ Identity │ │ Reply │ │ │ │ │ │ Store │ │ Stack │ │ Resolver │ │ Pipeline │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ Event │ │ Handoff │ │ Rich │ │ Command │ │ │ │ │ │ Bridge │ │ Queue │ │ Messages │ │ Registry │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ └──────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Commerce Engine + MCP │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 7.3 Channel Support | Channel | Protocol | Status | Features | | --------------- | ---------------- | ------------ | ------------------------------------ | | **WhatsApp** | Cloud API | GA | Rich media, templates, quick replies | | **Telegram** | Bot API | GA | Inline keyboards, commands, groups | | **Discord** | Gateway + REST | GA | Slash commands, embeds, threads | | **Slack** | Events + Web API | GA | Blocks, modals, slash commands | | **Signal** | signal-cli | GA | Encrypted messaging | | **Google Chat** | Spaces API | GA | Cards, dialogs | | **WebChat** | WebSocket | GA | Embeddable widget, real-time | | **iMessage** | AppleScript | Experimental | macOS only | | **Teams** | Bot Framework | Experimental | Adaptive cards | ### 7.4 Gateway Infrastructure **Session Store:** SQLite-backed persistent sessions with per-conversation state, allowing agents to maintain context across messages and platform reconnections. **Middleware Stack:** Koa-style onion model with composable middleware: * Rate limiting (per-user, per-channel) * Content filtering (profanity, PII detection) * Language detection * Request logging and metrics **Identity Resolution:** Maps platform-specific user IDs to commerce customer records, enabling personalized service across channels. **Event Bridge:** Connects commerce engine events to channel notifications—when an order ships, the customer receives a notification on their preferred channel. **Handoff Queue:** AI-to-human escalation system for cases requiring human judgment, with full conversation context transfer. **Plugin System:** Extensible architecture allowing custom plugins for channel-specific functionality. ### 7.5 Orchestrator The multi-channel orchestrator launches and manages gateway instances from configuration: ```bash theme={null} # Launch all configured channels stateset-channels # Launch specific channels stateset-whatsapp stateset-discord stateset-telegram stateset-slack ``` *** ## 8. Operational Infrastructure ### 8.1 Heartbeat Monitor The heartbeat monitor provides proactive health checking for commerce operations: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Heartbeat Monitor │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────┐ │ │ │ HeartbeatMonitor│ (EventEmitter, configurable interval) │ │ └───────┬────────┘ │ │ │ │ │ ├── low-stock Items below threshold │ │ ├── abandoned-carts Stale carts past timeout │ │ ├── revenue-milestone Revenue target monitoring │ │ ├── pending-returns Returns aging beyond threshold │ │ ├── overdue-invoices Overdue B2B invoices │ │ └── subscription-churn Cancellation rate monitoring │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │AutonomousEngine │ Trigger automated responses │ │ └────────┬────────┘ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ Event Bridge │ Route to notification channels │ │ └────────┬────────┘ │ │ ▼ │ │ ┌─────────────────┐ │ │ │Channel Notifier │ WhatsApp, Slack, Discord, etc. │ │ └─────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` **6 Built-in Commerce Checkers:** | Checker | Trigger | Action | | -------------------- | --------------------- | ----------------------- | | `low-stock` | Stock below threshold | Alert, auto-reorder | | `abandoned-carts` | Cart idle > timeout | Recovery notification | | `revenue-milestone` | Target reached/missed | Dashboard alert | | `pending-returns` | Return aging > days | Escalation | | `overdue-invoices` | Invoice past due | Collection notification | | `subscription-churn` | Cancellation spike | Retention campaign | **HTTP API:** ``` GET /heartbeat/status - Overall health GET /heartbeat/checks - All checker states POST /heartbeat/checks/:id/run - Trigger immediate check POST /heartbeat/checks/:id/enable - Enable checker POST /heartbeat/checks/:id/disable - Disable checker ``` ### 8.2 Permission Sandboxing Fine-grained permission control for API access: **Permission Levels:** ``` none (0) < read (1) < preview (2) < write (3) < delete (4) < admin (5) ``` **Features:** * API key authentication (Bearer token + query parameter) * Per-route permission levels with longest-prefix matching * Per-HTTP-method overrides * Sandbox mode blocking dangerous operations (browser automation, shell execution) * Timing-safe key comparison * Every MCP tool mapped to a required permission level ### 8.3 Persistent Memory SQLite-backed conversation memory for maintaining context across sessions: | Feature | Description | | ------------------------------ | --------------------------------------- | | **Per-conversation summaries** | Automatic summarization of interactions | | **Fact extraction** | Key facts stored for future reference | | **Token tracking** | Usage monitoring per conversation | | **Keyword search** | Find relevant past interactions | | **Vector retrieval** | Semantic similarity search over memory | | **Auto-cleanup** | Configurable retention policies | ### 8.4 Browser Automation Chrome DevTools Protocol (CDP) integration for web interaction: * Headless Chrome spawning and lifecycle management * Navigation, DOM queries, JavaScript evaluation * Screenshot capture * No Puppeteer dependency (pure CDP implementation) * Use cases: storefront testing, catalog sync, web scraping ### 8.5 Daemon Mode Systemd service manager for production deployments: ```bash theme={null} stateset-daemon start # Launch gateway as service stateset-daemon stop # Stop service stateset-daemon logs # View logs stateset-daemon health # Health check ``` Includes Tailscale VPN management and SSH tunnel support for secure remote access. ### 8.6 Scaffold Server Code generation system for bootstrapping e-commerce storefronts: ```bash theme={null} stateset scaffold --template next-commerce ``` Generates complete, runnable storefronts with commerce engine integration, reducing time-to-first-store. ### 8.7 Prometheus Metrics Feature-gated observability (`metrics` feature flag): ```rust theme={null} // Operation latency histograms pub static ref OPERATION_LATENCY: HistogramVec; // Operation counters (total + failed) pub static ref OPERATION_TOTAL: CounterVec; pub static ref OPERATION_FAILED: CounterVec; // Active reservation gauges pub static ref ACTIVE_RESERVATIONS: Gauge; ``` Metrics are exported in Prometheus text format for integration with Grafana, Datadog, and other monitoring tools. *** ## 9. Evaluation ### 9.1 Performance **Embedded Engine Benchmarks:** | Operation | SQLite | PostgreSQL | | ----------------------------- | ------ | ---------- | | Create Order | 1.2ms | 3.5ms | | List Orders (100) | 0.8ms | 2.1ms | | Inventory Adjustment | 0.9ms | 2.8ms | | Tax Calculation | 0.3ms | 0.3ms | | Cart Checkout | 4.5ms | 8.2ms | | Vector Search (1000 products) | \~15ms | \~20ms | | Hybrid Search (RRF) | \~25ms | \~30ms | **Sequencer Throughput:** | Metric | Value | | ------------------------- | ----------------- | | Events/second (sustained) | 10,000+ | | Batch size | 100-1000 events | | Sequencing latency (p99) | 50ms | | Merkle tree construction | \~5ms/1000 events | **L2 Settlement:** | Metric | Value | | ------------------- | ------------ | | Block time | 2 seconds | | commitBatch gas | \~150,000 | | verifyInclusion gas | \~30,000 | | L1 batch submission | \~10 minutes | ### 9.2 Security Properties **Cryptographic Guarantees:** 1. **Event Integrity:** SHA-256 payload hashes prevent tampering 2. **Inclusion Proofs:** Merkle trees enable O(log n) verification 3. **Ordering Finality:** Sequence numbers are immutable once assigned 4. **State Continuity:** Each batch links to previous state root 5. **Agent Authentication:** Ed25519 signatures with key rotation 6. **Encryption Groups:** X25519-based end-to-end encryption for sensitive data 7. **Payment Security:** x402 signed intents with replay protection via nonces **Attack Resistance:** | Attack | Mitigation | | ---------------------- | ------------------------------------- | | Event replay | UUID event\_id deduplication | | Intent replay | command\_id deduplication | | Payment replay | Nonce-based x402 intent deduplication | | Sequencer equivocation | State root chain verification | | Data tampering | Merkle proofs, on-chain anchoring | | Agent impersonation | Ed25519 signing with key registry | | Unauthorized access | Permission sandboxing, API key auth | | Channel injection | Middleware content filtering | ### 9.3 Scalability **Horizontal Scaling:** | Component | Strategy | | ----------------- | ------------------------------------ | | Embedded Engine | Per-agent instances, no coordination | | Sequencer | Read replicas, partition by tenant | | Event Store | PostgreSQL partitioning by sequence | | L2 Settlement | OP Stack inherent scalability | | Messaging Gateway | Per-channel horizontal scaling | **State Growth:** | Timeframe | Events | Storage (est.) | | --------- | ------ | -------------- | | 1 month | 10M | 5 GB | | 1 year | 120M | 60 GB | | 5 years | 600M | 300 GB | Event archival and pruning strategies maintain operational efficiency. *** ## 10. Related Work ### 10.1 Embedded Databases **SQLite** pioneered the embedded database model, demonstrating that client-server architecture is unnecessary for most applications. iCommerce applies this principle to commerce. **DuckDB** extends embedded analytics, inspiring our embedded forecasting capabilities. ### 10.2 Event Sourcing **EventStore** and **Kafka** provide event streaming infrastructure. VES differs by: * Targeting agent-to-agent coordination * Providing cryptographic commitments * Supporting offline-first operation * Including end-to-end encryption groups ### 10.3 Commerce Platforms **Shopify**, **Stripe**, and **BigCommerce** provide SaaS commerce infrastructure. iCommerce differs by: * Embedded architecture (no network dependency) * Agent-first design (MCP tools, not dashboards) * Verifiable execution (Merkle proofs) * Native stablecoin payments (x402) ### 10.4 Layer-2 Solutions **Optimism** and **Arbitrum** provide general-purpose L2 scaling. Set Chain specializes for commerce with: * SetRegistry for event anchoring * SetPaymaster for merchant gas sponsorship * Integration with off-chain sequencer * x402 payment settlement ### 10.5 Agent Payment Protocols **x402** builds on the HTTP 402 status code to enable machine-to-machine payments. Unlike traditional payment processors that require human-facing checkout flows, x402 operates entirely at the protocol level, enabling autonomous agents to negotiate and settle payments as part of standard HTTP request/response cycles. ### 10.6 Conversational Commerce **Twilio**, **MessageBird**, and **Vonage** provide messaging APIs. The StateSet messaging gateway differs by: * Deep commerce engine integration (not just messaging) * AI-native design (agents as first-class participants) * Event-driven notifications from commerce operations * Identity resolution across platforms *** ## 11. Conclusion StateSet iCommerce represents a new paradigm for commerce infrastructure: embedded, verifiable, and agent-first. The five-layer architecture provides: 1. **Local autonomy** via the embedded engine with 32 commerce domains 2. **Global coordination** via Verifiable Event Sync with end-to-end encryption 3. **Cryptographic finality** via Set Chain settlement 4. **Native payments** via the x402 HTTP payment protocol 5. **Omnichannel presence** via the 9-channel messaging gateway As AI agents become primary participants in economic activity, infrastructure must evolve beyond human-operated dashboards and rate-limited APIs. iCommerce provides the foundation for this autonomous commerce future—from warehouse operations and quality control to general ledger accounting and stablecoin payments, all accessible to AI agents through a unified, verifiable, embedded engine. ### 11.1 Future Work **Near-term (2026):** * Zero-knowledge validity proofs for event batches * Agent-to-agent negotiation protocol * Cross-chain settlement bridges * Expanded vector search with custom embedding models * Additional messaging channels (Matrix, RCS) **Medium-term (2026-2027):** * Decentralized identity integration * Federated learning across tenants * On-device ML models for demand prediction * Real-time collaborative editing of commerce data **Long-term (2027+):** * Fully autonomous supply chain orchestration * Cross-border compliance automation * Global commerce network federation * Autonomous agent marketplaces with x402 settlement *** ## References 1. SQLite Consortium. "SQLite: A Self-Contained SQL Database Engine." [https://sqlite.org](https://sqlite.org) 2. Ethereum Foundation. "Optimistic Rollups." [https://ethereum.org/en/developers/docs/scaling/optimistic-rollups/](https://ethereum.org/en/developers/docs/scaling/optimistic-rollups/) 3. Anthropic. "Model Context Protocol Specification." [https://modelcontextprotocol.io](https://modelcontextprotocol.io) 4. Merkle, R.C. "A Digital Signature Based on a Conventional Encryption Function." CRYPTO 1987. 5. Lamport, L. "Time, Clocks, and the Ordering of Events in a Distributed System." CACM 1978. 6. Coinbase. "x402: HTTP-Native Payments Protocol." [https://www.x402.org](https://www.x402.org) 7. OpenAI. "Text Embedding Models." [https://platform.openai.com/docs/guides/embeddings](https://platform.openai.com/docs/guides/embeddings) *** ## Appendix A: System Statistics | Component | Metric | Value | | --------------------- | ------------- | ---------- | | stateset-core | Lines of Code | \~45,000 | | stateset-db | Lines of Code | \~55,000 | | stateset-embedded | Lines of Code | \~39,000 | | Total Rust (3 crates) | Lines of Code | \~139,000 | | Node.js binding | Technology | NAPI-RS | | Python binding | Technology | PyO3 | | Ruby binding | Technology | Magnus | | PHP binding | Technology | ext-php-rs | | Java binding | Technology | JNI | | Kotlin binding | Technology | JNI | | Swift binding | Technology | C FFI | | .NET binding | Technology | P/Invoke | | Go binding | Technology | cgo | | WASM binding | Technology | wasm-pack | | CLI (mcp-server) | Size | 221 KB | | CLI (harness) | Size | 62 KB | | Domain Modules | Count | 32 | | Domain Types | Count | 400+ | | Database Tables | Count | 70+ | | Database Migrations | Count | 28 | | API Methods | Count | 700+ | | Language Bindings | Count | 10 | | Commerce Skills | Count | 38 | | AI Providers | Count | 4 | | Messaging Channels | Count | 9 | | Heartbeat Checkers | Count | 6 | | CLI Programs | Count | 26+ | | Sequencer | Lines of Code | \~5,000 | | Set Chain Contracts | Lines of Code | \~1,000 | | Anchor Service | Lines of Code | \~2,250 | *** ## Appendix B: API Summary ### Embedded Engine (per domain) **Commerce Operations:** ``` customers: list, get, getByEmail, create, update, delete, count products: list, get, getBySku, create, update, delete, listVariants inventory: getStock, create, adjust, reserve, release, confirm orders: list, get, create, updateStatus, ship, cancel, addItem carts: list, get, create, addItem, updateItem, removeItem, checkout payments: list, get, create, markCompleted, markFailed, refund returns: list, get, create, approve, reject, complete promotions: list, get, create, activate, deactivate, validateCoupon subscriptions: listPlans, createPlan, subscribe, pause, resume, cancel shipments: list, get, create, addEvent, updateTracking ``` **Supply Chain & Warehouse:** ``` warehouse: list, get, create, addZone, addLocation, getInventory, move receiving: list, get, create, receiveItems, putAway, complete fulfillment: createWave, listWaves, assignPick, completePick, pack, ship lots: list, get, create, split, merge, transfer, traceForward, traceBack serials: list, get, create, bulkCreate, transfer, lookupWarranty backorders: list, get, create, allocate, fulfill, getSummary manufacturing: listBOMs, createBOM, createWorkOrder, completeTask purchase_orders: list, get, create, receive, close quality: createInspection, recordResult, createNCR, placeHold, releaseHold ``` **Financial:** ``` general_ledger: createAccount, postEntry, getTrialBalance, getBalanceSheet, getIncomeStatement, openPeriod, closePeriod accounts_recv: getAging, createCreditMemo, writeOff, applyPayment, generateStatement, createCollection accounts_pay: createBill, schedulePay, createPaymentRun, getAging invoices: list, get, create, markPaid, markVoid cost_accounting: recordLayer, adjust, getValuation, getVariance credit: createAccount, applyCredit, reviewApplication, placeHold tax: calculate, calculateCart, getRate, listJurisdictions currency: convert, getRate, setRate, format ``` **Platform:** ``` x402: createIntent, signIntent, verifyReceipt, batchSettle vector: indexProduct, searchProducts, indexCustomer, searchCustomers analytics: getSales, getTopProducts, getForecast, getHealth warranties: list, get, create, fileClaim, resolveClaim forecasting: getDemand, generateForecast, getSeasonality sync: status, push, pull, outbox, retryFailed, entityHistory, full ``` ### Sequencer API ``` POST /api/v1/events/ingest - Batch event ingestion GET /api/v1/events - List events by sequence GET /api/v1/head - Get current head sequence GET /api/v1/commitments/:id - Get batch commitment GET /api/v1/commitments/:id/proof - Get inclusion proof GET /api/v1/entities/:type/:id - Get entity history POST /api/v1/keys/register - Register agent public key GET /api/v1/keys/:agent_id - Get agent public key POST /api/v1/groups/create - Create encryption group POST /api/v1/groups/:id/members - Add group member ``` ### MCP Sync Tools ``` sync_status - Get sync health and statistics sync_push - Push pending events to sequencer sync_pull - Pull events from sequencer sync_outbox - List local outbox events sync_retry_failed - Reset failed events for retry sync_entity_history - Get entity event history sync_full - Push then pull (full sync) ``` ### Heartbeat API ``` GET /heartbeat/status - Overall health status GET /heartbeat/checks - All checker states POST /heartbeat/checks/:id/run - Trigger immediate check POST /heartbeat/checks/:id/enable - Enable checker POST /heartbeat/checks/:id/disable - Disable checker ``` ### Gateway API ``` POST /gateway/send - Send message to channel GET /gateway/sessions - List active sessions GET /gateway/sessions/:id - Get session details POST /gateway/handoff - Escalate to human agent GET /gateway/metrics - Channel metrics ``` *** *StateSet iCommerce v0.3.1* *January 2026* # StateSet iCommerce Docs Source: https://docs.stateset.com/introduction Start here to explore StateSet products, APIs, and guides. # StateSet iCommerce Documentation Welcome to the StateSet iCommerce docs. This landing page helps you choose a product area and get to the right guides quickly. ```bash theme={null} npm install -g @stateset/cli ``` ```bash theme={null} npx @stateset/cli ``` ```bash theme={null} stateset --version ``` # StateSet iCommerce Skills AI Agents can use the iCommerce skills to run their commerce engine and sync to the sequencer. ```bash theme={null} curl -s https://docs.stateset.com/stateset-icommerce-skill.md > ~/.claude/skills/stateset-icommerce/SKILL.md ``` 1. Run the command above to get started 2. Register & save your API key 3. Start running your commerce engine and sync to the sequencer ## Start with iCommerce StateSet iCommerce Engine is the unified, AI-native embedded engine for agentic commerce. Category definition and why iCommerce matters. Start building with the embedded engine. How the engine is structured end to end. ## Product Areas Secure execution environments for agents. Conversational checkout and delegated payments. Standard discovery + checkout for commerce. Secure execution environments for agents. Verifiable event sequencing for auditability. On-chain anchoring of commitments and proofs. # Returns Source: https://docs.stateset.com/object-reference/returns/object The returns object ### Definition Returns are used to track the return of an item or items to a merchant. Returns can be created for a variety of reasons, including: * Item is damaged * Item is defective * Item is incorrect * Item is missing * Item is no longer needed * Item is not as described * Item is not what was ordered * Item is unwanted * Item was not delivered * Item was not received * Item was not received on time * Item was not what was expected ### Attributes ### Return | Name | Type | Description | | -------------------- | --------- | ------------------------------------------------------------ | | id | Integer | Unique identifier for the entry in the table | | created\_date | Date/Time | Date and time when the entry was created | | amount | Decimal | The monetary amount associated with the entry | | action\_needed | Boolean | Indicates whether any action is required for the entry | | condition | String | Describes the condition of the item or situation | | customerEmail | String | Email address of the customer associated with the entry | | customer\_id | Integer | Unique identifier for the customer associated with the entry | | description | String | Brief description or additional details about the entry | | enteredBy | String | Name or identifier of the person who entered the entry | | flat\_rate\_shipping | Boolean | Indicates whether the shipping rate is a flat rate | | order\_date | Date/Time | Date and time when the order was placed | | order\_id | Integer | Unique identifier for the order associated with the entry | | reason\_category | String | Category or reason associated with the entry | | reported\_condition | String | Condition as reported by the customer or user | | requested\_date | Date/Time | Date and time when a specific request was made for the entry | | rma | String | Return Merchandise Authorization (RMA) number for the entry | | serial\_number | String | Unique serial number associated with the item in the entry | | shipped\_date | Date/Time | Date and time when the item was shipped or dispatched | | status | String | Current status or state of the entry | | tax\_refunded | Decimal | The amount of tax refunded for the entry | | total\_refunded | Decimal | The total amount refunded for the entry | | tracking\_number | String | Tracking number associated with the shipment for the entry | ### Return Line Item | Name | Type | Description | | -------------------- | ------- | -------------------------------------------------------------- | | amount | Decimal | The monetary amount associated with the return line item | | condition | String | Describes the condition of the returned item | | flat\_rate\_shipping | Boolean | Indicates whether the shipping rate is a flat rate | | id | Integer | Unique identifier for the return line item | | name | String | Name or description of the return line item | | price | Decimal | The price of the return line item | | return\_id | Integer | Unique identifier for the return associated with the line item | | serial\_number | String | Unique serial number associated with the returned item | | sku | String | Stock Keeping Unit (SKU) of the returned item | | tax\_refunded | Decimal | The amount of tax refunded for the return line item | # 5-Minute Quickstart Source: https://docs.stateset.com/quickstart Deploy your first AI agent and see StateSet in action # From Zero to Autonomous in 5 Minutes Time to first value: 5 minutes By the end of this guide, you'll have a live AI agent handling real customer conversations. ## What You'll Build Here's what we'll accomplish together in the next 5 minutes: Sign up for StateSet and verify your email Launch your AI customer service agent Test your agent with real conversations Watch autonomous operations in real-time ## Prerequisites Before we begin, ensure you have: | Requirement | Why You Need It | | ---------------- | ------------------------------ | | 🌐 Web browser | Access StateSet dashboard | | ✉️ Email address | Create and verify your account | | ⏱️ 5 minutes | Complete the entire quickstart | *** ## Step 1: Create Your Account **Time investment: 30 seconds** 1. Go to [stateset.com/sign-up](https://stateset.com/sign-up) 2. Enter your email address 3. Click the verification link sent to your inbox 4. You're now in your StateSet dashboard! Prefer code-first setup? You can skip the dashboard and jump straight to the SDK option in Step 2 below. *** ## Step 2: Deploy Your First Agent **Time investment: 2 minutes** ### Option A: One-Click Deploy (Recommended) In your dashboard, click the **"Deploy Agent"** button and choose from our pre-configured options: Pre-trained on 10M+ support conversations. Perfect for handling: - Product inquiries - Order tracking - Returns processing - Technical issues Optimized for driving revenue and conversions. Specializes in: - Lead qualification - Product recommendations - Quote generation - Demo scheduling Handles backend operations seamlessly. Expert in: - Order fulfillment - Inventory management - Logistics coordination - Vendor communications ### Option B: Deploy via Code Install the required packages: ```bash theme={null} npm install stateset-node dotenv winston ``` Create your agent file (`agent.js`): ```javascript title="agent.js" theme={null} import { StateSetClient } from "stateset-node"; import dotenv from "dotenv"; import winston from "winston"; // Load environment variables dotenv.config(); // Configure logger const logger = winston.createLogger({ level: process.env.LOG_LEVEL || "info", format: winston.format.json(), transports: [new winston.transports.Console()], }); // Initialize StateSet client const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, }); // Deploy agent async function deployAgent() { try { const agent = await client.agents.create({ name: "Alex", role: "Customer Success Specialist", personality: { tone: "friendly", style: "solution-oriented", traits: ["empathetic", "knowledgeable"], }, greeting: "Hi! I'm Alex from customer success. How can I help you today?", capabilities: [ "answer_product_questions", "track_orders", "process_returns", "technical_support", "escalate_issues", ], }); logger.info("Agent deployed successfully", { agentId: agent.id, }); logger.info("Chat URL", { url: `https://app.stateset.com/chat/${agent.id}`, }); return agent; } catch (error) { logger.error("Agent deployment failed", { message: error.message, code: error.code, requestId: error.request_id, }); throw error; } } // Execute deployment deployAgent() .then((agent) => console.log(`Agent ${agent.name} is live!`)) .catch((error) => console.error("Deployment failed:", error.message)); ``` Set your API key in `.env`: ```bash title=".env" theme={null} STATESET_API_KEY=your_api_key_here LOG_LEVEL=info ``` Run your application: ```bash theme={null} node agent.js ``` *** ## Step 3: Test Your Agent **Time investment: 1 minute** ### Test via Live Chat Open the chat URL from your deployment and try these test messages: ```text theme={null} "Hi, I need help with my order" "What's your return policy?" "I'm having trouble logging in" "Can you help me track order #12345?" ``` ### Test via API Send a message programmatically: ```bash title="Send message via API" theme={null} curl -X POST https://api.stateset.com/v1/messages \ -H "Authorization: Bearer ${STATESET_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "to": "agent_xxx", "body": "Hello, I need help with my order", "is_public": true }' ``` ```json title="API Response" theme={null} { "id": "msg_123", "to": "agent_xxx", "body": "Hello, I need help with my order", "created_at": "2025-01-01T12:00:00Z", "status": "queued" } ``` ```json title="Error Response" theme={null} { "error": { "code": "invalid_api_key", "message": "Invalid or expired API key" } } ``` *** ## Step 4: Verify & Monitor **Time investment: 1.5 minutes** ### Real-Time Analytics Dashboard Track your agent's performance: 1. Navigate to your [StateSet Dashboard](https://app.stateset.com) 2. Click **"Agent Analytics"** 3. Monitor these key metrics: | Metric | What It Shows | | ------------------ | ------------------------------------- | | 🎯 Conversations | Total messages handled | | ⚡ Response Time | Average time to reply (usually \< 1s) | | 😊 CSAT Score | Customer satisfaction rating | | 📈 Resolution Rate | Issues solved autonomously | ### What Just Happened? Your AI agent is now: * ✨ **Learning** from every interaction to improve * 📈 **Improving** response quality automatically * 🔄 **Scaling** to handle unlimited conversations * ⏰ **Operating** 24/7 without breaks * 🔒 **Secure** with enterprise-grade protection *** ## Explore Your Agent's Capabilities Your agent comes pre-configured with powerful capabilities: * Answer product and feature questions - Track orders and shipment status - Process returns and refund requests - Handle complaints with empathy - Escalate complex issues to humans * Qualify incoming leads automatically - Recommend products based on needs - Apply promotional discount codes - Upsell related products and services - Schedule product demos with sales team * Troubleshoot common technical issues - Guide users through setup processes * Reset passwords and manage accounts - Check system and service status - Create and update support tickets *** ## Next Steps: Level Up Your Agent **Optional enhancements** ### Add Your Knowledge Base **Time: 2 minutes** Make your agent an expert on your products and services: ```javascript title="Add knowledge base" theme={null} const kb = await client.knowledgeBase.create({ name: "Product Documentation", agent_id: agent.id, }); // Upload your documentation await kb.uploadDocument("./product-guide.pdf"); await kb.uploadDocument("./faq.md"); await kb.uploadDocument("./api-reference.md"); // Your agent now knows everything in your docs! logger.info("Knowledge base updated", { documents: 3, agentId: agent.id, }); ``` ### Connect Your Systems **Time: 5 minutes** Enable your agent to take real actions: ```javascript title="Add system integration" theme={null} await agent.addIntegration({ type: "webhook", name: "order_lookup", endpoint: "https://api.yourstore.com/orders", method: "GET", authentication: { type: "api_key", header: "X-API-Key", key: process.env.STORE_API_KEY, }, // Define response mapping mapping: { orderId: "$.order_id", status: "$.status", items: "$.items[*].name", }, }); logger.info("Integration added", { type: "order_lookup", agentId: agent.id, }); ``` ### Deploy to Your Website **Time: 3 minutes** Add a chat widget to your site: ```html title="Add chat widget to your website"> theme={null} ``` *** ## Common Questions Your first 1,000 conversations are completely free. After that: | Plan | Price | What You Get | | ---------- | ------------------- | ---------------------------------------------- | | Starter | \$0.50/conversation | Up to 10K conversations/month | | Growth | Custom pricing | Unlimited conversations + priority support | | Enterprise | Custom | Dedicated infrastructure + custom integrations | You only pay for **successfully resolved** conversations. Absolutely! You can fully customize: * **Personality**: Define tone, style, and Traits * **Knowledge**: Train on your own documentation * **Responses**: Provide templates and examples * **Correction**: Refine responses in real-time * **Integrations**: Connect to any system via API Your agent learns from every correction you make. StateSet takes security seriously: * 🔒 **SOC 2 Type II** certified infrastructure * 🛡️ **End-to-end encryption** at rest and in transit * 📋 **GDPR compliant** data handling * 👥 **Role-based access control** for team management * 📊 **Complete audit logs** of all activities We never train on your data without explicit permission. Yes! Integration options include: * **Pre-built integrations**: 100+ tools supported (Shopify, NetSuite, Zendesk, etc.) * **Custom API**: Flexible REST/GraphQL endpoints * **Webhooks**: Real-time event notifications * **SDK support**: Official libraries for 11+ languages * **Middleware**: Zapier, Make, and custom solutions See our [Integration Guide](/guides/integrations) for details. *** ## Summary In just 5 minutes, you've: ✅ Created your StateSet account\ ✅ Deployed a fully functional AI agent\ ✅ Tested real conversations\ ✅ Monitored performance metrics ### Your Agent Can Now: | Capability | Benefit | | ----------------------------------------------- | --------------------------------- | | 🎯 Handle multiple conversations simultaneously | Scale without headcount | | 📈 Improve response quality over time | Get better with every interaction | | ⏰ Operate continuously without breaks | 24/7 availability | | 🔒 Connect securely to your systems | Safe, autonomous operations | | 📊 Provide detailed analytics | Data-driven insights | *** ## Ready for More? Deep dive into building advanced features with StateSet Make your agents even smarter with custom training Connect to 100+ pre-built integrations Connect with 5,000+ developers and get help *** Next: Monitor Your Agent Visit the **Agent Analytics** tab in your dashboard to track conversation volume, resolution rate, and customer satisfaction scores. Use these metrics to identify areas where your agent's knowledge base can be expanded. Need help? Our AI-powered support team (yes, real AI agents!) is standing by: * 📧 Email: [support@stateset.com](mailto:support@stateset.com) * 💬 Chat: Click the bubble below * 🎙️ Discord: [Join our community](https://discord.gg/stateset) Average response time: \< 2 minutes # StateSet Agentic OS: Autonomous Agents for Next-Gen Commerce Source: https://docs.stateset.com/response-api-reference/agents Explore StateSet's Agentic OS, combining Automation and Analysis Agents to power the future of commerce. # StateSet Agentic OS: Autonomous Agents for Next-Gen Commerce In today's rapidly evolving digital economy, enterprises are increasingly turning to **autonomous agents** to power critical business operations. Two distinct classes of agents are taking center stage: **Automation Agents** and **Analysis Agents**. While Automation Agents excel in task execution through robust tool integration and precise function calling, Analysis Agents shine in synthesizing data, reasoning through complexities, and providing strategic insights powered by advanced chain-of-thought processes. ## Defining the Next-Gen Business Operating System StateSet’s **Agentic OS** is at the forefront of this shift, introducing a new paradigm that combines the strengths of both Automation and Analysis. This next-generation autonomous commerce operating system is engineered to support mission-critical processes across some of the world's fastest-growing businesses. Backed by cutting-edge artificial intelligence, the Agentic OS empowers businesses to run leaner, faster, and more intelligently. It integrates seamlessly into existing workflows, deploying AI agents that handle everything from back-office automation to strategic forecasting. > This system ensures that businesses are not just keeping pace with the future but actively shaping it. ## Two Core Agent Classes, One Unified Platform StateSet’s Agentic OS leverages two core agent classes: ### Automation Agents **Automation Agents** are the workhorses of digital operations. They are equipped to: * Trigger functions * Integrate with enterprise systems * Execute repetitive tasks These agents free up human talent for more value-added activities. By handling order management, subscription renewals, inventory checks, and returns processing, these agents streamline operations and minimize human error. ### Analysis Agents **Analysis Agents** leverage: * Reasoning * Chain-of-thought methodologies * Rich data sets They make sense of complex scenarios and drive intelligent decision-making. They are used for: * Identifying emerging marketing trends * Understanding customer behavior patterns * Optimizing supply chain logistics * Providing actionable insights that guide strategic initiatives and boost long-term growth. ## Building Tomorrow’s Leading Brands, Today Our vision is to build the next generational software company by empowering the world’s fastest-growing brands with an **Agentic Operating System**. Through StateSet’s Agentic OS, organizations can deploy specialized AI agents focused on their unique business outcomes. > This is achieved by supercharging customer support teams and dynamically adjusting inventory levels based on demand signals. ## Meet the AI Agents: Gloria, Robert, and Diana StateSet’s Agentic OS offers a diverse portfolio of AI Agents for Shopify brands, each designed to deliver exceptional results in their area of expertise. ### Gloria: Your Customer Experience Maven * **Expertise:** Email support, orders, subscriptions, and returns * **Achievements:** * Resolves issues 90% faster * Boasts a 98% satisfaction rating * 4.98/5 average communication score * **Key Integrations:** Shopify, Gorgias, StayAI, Klaviyo, Attentive Gloria epitomizes the power of Autonomous Agents, handling critical customer service tasks at scale. She's ready to sort out complex return requests, address subscription concerns, and streamline order resolutions—all while maintaining exceptional communication and customer sentiment. ### Robert: Your Subscription and Order Specialist * **Expertise:** Subscriptions, Order Management, Sales * **Achievements:** * Maintains a 98% satisfaction rating * Excels in language and communication, scoring 4.95/5 and 4.98/5 respectively * **Key Integrations:** Shopify, Gorgias, Recharge, Klaviyo, Attentive Robert ensures that customers never miss a beat with their recurring products and keeps order pipelines flowing smoothly. By quickly adapting to new marketplace dynamics and automating repeat tasks, he brings operational stability and elevated customer trust. ### Diana: Your Pre-Sales Rockstar * **Expertise:** Pre-sales Support, Product Recommendations, Technical Guidance * **Achievements:** * 98% satisfaction rating * 4.9 score in language and communication * 10X ROI in Revenue Generation * **Key Integrations:** Shopify, Gorgias, Skio, Klaviyo, Attentive Diana leverages advanced reasoning and data analytics to understand shopper intent, deliver personalized recommendations, and offer technical guidance that turns browsers into loyal buyers. Her insight-driven strategies exemplify the strengths of AI Agents in revenue generation and brand growth. ## Seamless Integration for Continuous Innovation From seamless integration with your existing tools—like Shopify for commerce, Gorgias for customer support, and Klaviyo for marketing—to adapting to platforms like Recharge and StayAI, StateSet’s Agentic OS is built to evolve alongside your organization. > This ensures that as your brand grows, your operational ecosystem becomes even more autonomous, insightful, and efficient. ## The Future Is Agentic We stand on the cusp of a transformative era in software. With StateSet’s Agentic OS, businesses can transcend traditional limitations and usher in a future defined by precision, speed, and informed decision-making. By harnessing the power of Automation and Analysis Agents, businesses don’t just remain competitive—they become catalysts of innovation within their industries. > It’s time to embrace the Agentic revolution. Welcome to the future of autonomous commerce operations. **To learn more visit:** [stateset.com](https://stateset.com) **To chat with Gloria, Robert, or Diana:** [response.cx](https://response.cx) # Create Agent Source: https://docs.stateset.com/response-api-reference/agents/create POST https://api.stateset.com/v1/agents This endpoint creates a new agent ### Body Human‑readable name for the agent. Agent type/preset (e.g., "Conversational AI Agent"). Defaults to conversational. Short purpose/description shown in the dashboard. High‑level role or persona for the agent. System instructions that guide the agent’s behavior. Primary objective(s) the agent should optimize for. Voice model to use for voice channels (if enabled). Whether the agent is active immediately. Defaults to `true`. Organization/workspace that owns the agent. If omitted, uses your current org. ### Response Unique identifier for the agent. The name of the created agent. The agent type/preset. The description of the created agent. The role/persona of the agent. Whether the agent is active. Organization/workspace that owns the agent. Voice model configured for the agent. When the agent was created. When the agent was last updated. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/agents' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "agent_name": "Support Bot", "agent_type": "Conversational AI Agent", "description": "Handles order status and returns", "role": "Customer Support Specialist", "instructions": "Be concise, friendly, and ask for an order number when needed.", "goal": "Resolve customer issues quickly", "voice_model": "Asteria" }' ``` # Delete Agent Source: https://docs.stateset.com/response-api-reference/agents/delete DELETE https://api.stateset.com/v1/agents/{id} This endpoint deletes an agent. ### Path Parameters The agent ID. ### Response This is the id of the agent. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/agents/agent_123' \ --header 'Authorization: Bearer ' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00" } ``` # Get Agent Source: https://docs.stateset.com/response-api-reference/agents/get GET https://api.stateset.com/v1/agents/{id} This endpoint gets an agent ### Path Parameters The agent ID. ### Response The name of the created agent. The type of the created agent. The description of the created agent. The activation status of the created agent. The date and time the agent was created. The date and time the agent was last updated. The organization ID to which the agent belongs. The voice model associated with the agent. The voice model ID associated with the agent. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/agents/agent_123' \ --header 'Authorization: Bearer ' ``` ```json Response theme={null} { "id": "agent_123", "agent_name": "Support Bot", "agent_type": "Conversational AI Agent", "description": "Handles order status and returns", "activated": true, "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-02T08:30:00Z", "org_id": "org_456", "voice_model": "Asteria" } ``` # List Agents Source: https://docs.stateset.com/response-api-reference/agents/list GET https://api.stateset.com/v1/agents This endpoint gets agents ### Query Parameters (optional) Number of agents to return. Defaults to 20. Offset for pagination. Defaults to 0. ### Response The name of the created agent. The type of the created agent. The description of the created agent. The activation status of the created agent. The date and time the agent was created. The date and time the agent was last updated. The organization ID to which the agent belongs. The voice model associated with the agent. The voice model ID associated with the agent. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/agents?limit=20&offset=0' \ --header 'Authorization: Bearer ' ``` ```json Response theme={null} [ { "id": "agent_123", "agent_name": "Support Bot", "agent_type": "Conversational AI Agent", "description": "Handles order status and returns", "activated": true, "org_id": "org_456" } ] ``` # Update Agent Source: https://docs.stateset.com/response-api-reference/agents/update PUT https://api.stateset.com/v1/agents/{id} This endpoint updates an agent ### Body Updated name for the agent. Updated agent type/preset. Updated description. Updated role/persona. Updated system instructions. Updated goals/objectives. Updated voice model. Activation status. ### Response The name of the agent. The type of the agent. The description of the agent. The activation status of the agent. The date and time the agent was created. The date and time the agent was last updated. The organization ID to which the agent belongs. The voice model associated with the agent. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/agents/agent_123' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "agent_name": "Support Bot v2", "description": "Updated return and warranty support agent", "instructions": "Ask clarifying questions before taking action.", "activated": true }' ``` # Create Attribute Source: https://docs.stateset.com/response-api-reference/attributes/create POST https://api.stateset.com/v1/attritbutes This endpoint creates a new attribute ### Body The name of the attribute to be created. The type of the attribute (e.g., string, number, boolean). The value assigned to the attribute. The maximum value for the attribute, applicable only for numeric types. The minimum value for the attribute, applicable only for numeric types. The category this attribute belongs to. A brief description of the attribute. Indicates whether the attribute is modifiable after creation. Describes the impact or significance of the attribute. ### Response The name of the created attribute. The type of the created attribute. The value assigned to the created attribute. The maximum value for the created attribute, if applicable. The minimum value for the created attribute, if applicable. The category the created attribute belongs to, if any. A brief description of the created attribute. Indicates whether the attribute is modifiable. The impact or significance of the created attribute, if described. A confirmation message stating that the attribute has been successfully created. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/attributes' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "em_1NXWPnCo6bFb1KQto6C8OWvE", "attribute_name": "Example Name", "attribute_type": "string", "value": "Example Value", "max_value": 100, "min_value": 10, "category": "Example Category", "description": "This is a sample attribute for demonstration.", "modifiable": true, "impact": "High" }' ``` # Delete Attribute Source: https://docs.stateset.com/response-api-reference/attributes/delete DELETE https://api.stateset.com/v1/attributes This endpoint deletes a attribute. ### Body This is the id of the attribute.. ### Response This is the id of the attribute. The name of the created attribute. The type of the created attribute. The value assigned to the created attribute. The maximum value for the created attribute, if applicable. The minimum value for the created attribute, if applicable. The category the created attribute belongs to, if any. A brief description of the created attribute. Indicates whether the attribute is modifiable. The impact or significance of the created attribute, if described. A confirmation message stating that the attribute has been successfully created. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/attribute' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00" } ``` # Get Attribute Source: https://docs.stateset.com/response-api-reference/attributes/get GET https://api.stateset.com/v1/attribute This endpoint gets an attribute ### Body This is the id of the attribute. ### Response This is the id of the attribute. The name of the created attribute. The type of the created attribute. The value assigned to the created attribute. The maximum value for the created attribute, if applicable. The minimum value for the created attribute, if applicable. The category the created attribute belongs to, if any. A brief description of the created attribute. Indicates whether the attribute is modifiable. The impact or significance of the created attribute, if described. A confirmation message stating that the attribute has been successfully created. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/attribute' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Attribute", "name": "Confidence", "description": "This is the confidence attribute", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # List Attributes Source: https://docs.stateset.com/response-api-reference/attributes/list GET https://api.stateset.com/v1/attributes This endpoint gets all attributes ### Body ### Response This is the id of the attribute. The name of the created attribute. The type of the created attribute. The value assigned to the created attribute. The maximum value for the created attribute, if applicable. The minimum value for the created attribute, if applicable. The category the created attribute belongs to, if any. A brief description of the created attribute. Indicates whether the attribute is modifiable. The impact or significance of the created attribute, if described. A confirmation message stating that the attribute has been successfully created. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/attributes' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System attribute", "name": "attribute 1", "description": "This is the attribute", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Update Attribute Source: https://docs.stateset.com/response-api-reference/attributes/update PUT https://api.stateset.com/v1/attributes This endpoint updates a attribute ### Body This is the id of the attribute. The name of the attribute to be created. The type of the attribute (e.g., string, number, boolean). The value assigned to the attribute. The maximum value for the attribute, applicable only for numeric types. The minimum value for the attribute, applicable only for numeric types. The category this attribute belongs to. A brief description of the attribute. Indicates whether the attribute is modifiable after creation. Describes the impact or significance of the attribute. ### Response This is the id of the attribute. The name of the created attribute. The type of the created attribute. The value assigned to the created attribute. The maximum value for the created attribute, if applicable. The minimum value for the created attribute, if applicable. The category the created attribute belongs to, if any. A brief description of the created attribute. Indicates whether the attribute is modifiable. The impact or significance of the created attribute, if described. A confirmation message stating that the attribute has been successfully created. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/attributes' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Attribute", "name": "attribute 1", "description": "This is the attribute", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Attribute", "name": "attribute 1", "description": "This is the attribute", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Authentication Source: https://docs.stateset.com/response-api-reference/authentication Authenticate requests to the StateSet ResponseCX APIs # Authentication StateSet ResponseCX provides REST and GraphQL APIs. All requests must be authenticated with an API key. **Quick Start** ```bash theme={null} Authorization: Bearer ${STATESET_API_KEY} ``` ## API keys * **Test keys** (`sk_test_`) for sandbox development * **Live keys** (`sk_live_`) for production Create keys in **Dashboard → Settings → API Keys**. Keys are shown only once—store them securely. Never expose secret keys in client-side code or public repositories. Use environment variables. ## Using your key ```bash cURL theme={null} curl https://api.stateset.com/v1/agents \ -H "Authorization: Bearer ${STATESET_API_KEY}" \ -H "Content-Type: application/json" ``` ```javascript Node.js theme={null} import { StateSetClient } from 'stateset-node'; const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); const agents = await client.agents.list(); ``` ```python Python theme={null} import os from stateset import StateSetClient client = StateSetClient(api_key=os.getenv("STATESET_API_KEY")) agents = client.agents.list() ``` ## Troubleshooting * `401 Unauthorized`: missing/invalid key or wrong environment. * `403 Forbidden`: key lacks required permissions. # Channel Threads Source: https://docs.stateset.com/response-api-reference/channel-threads Overview of channel thread resources. # Channel Threads Use the channel threads endpoints to manage conversation threads. * [List](/response-api-reference/channel-threads/list) * [Get](/response-api-reference/channel-threads/get) * [Create](/response-api-reference/channel-threads/create) * [Update](/response-api-reference/channel-threads/update) * [Delete](/response-api-reference/channel-threads/delete) # Create Channel Thread Source: https://docs.stateset.com/response-api-reference/channel-threads/create POST https://api.stateset.com/v1/channel_thread This endpoint creates a new channel thread ### Body This is the ID of the channel thread to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation addChannelThread( $channel_thread: channel_thread_insert_input! ) { insert_channel_thread(objects: [$channel_thread]) { returning { id name uuid user_id } } } ``` ```javascript Node.js theme={null} const created = await stateset.channel.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_channel_thread": { "returning": [ { "id": "", "name": "", "uuid": "", "user_id": "" } ] } } } ``` # Delete Channel Thread Source: https://docs.stateset.com/response-api-reference/channel-threads/delete DELETE https://api.stateset.com/v1/channel_thread This endpoint deletes an existing thread. ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteChannelThread ($id: String!) { delete_channel_thread(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const channelthead = await stateset.channelthread.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} channelthead = stateset.channelthead.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} channelthead, err := stateset.Cases.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case channelthead = stateset.channelthead.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const channelthead = await stateset.channelthead.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} channelthead = Stateset::Return.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $channelthead = $stateset->channelthead->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/channelthread HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "channel_thread", "deleted": true } ``` *** title: "Delete Channel Thread" api: "DELETE [https://api.stateset.com/v1/channel\_thread](https://api.stateset.com/v1/channel_thread)" description: "This endpoint deletes an existing thread." -------------------------------------------------------- ### Body The ID provided in the data tab may be used to identify the case ### Response The ID provided in the data tab may be used to identify the case The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteChannelThread ($id: String!) { delete_channel_thread(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const channelthead = await stateset.channelthread.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} channelthead = stateset.channelthead.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} channelthead, err := stateset.ChannelThread.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case channelthead = stateset.channelthead.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const channelthead = await stateset.channelthead.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} channelthead = Stateset::ChannelThread.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $channelthead = $stateset->channelthead->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/channelthread HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "channel_thread", "deleted": true } ``` # Get Channel Threads Source: https://docs.stateset.com/response-api-reference/channel-threads/get GET https://api.stateset.com/v1/channel_threads This endpoint gets a channel threads. ### Body This is the id of the channel thread. ### Response This is the id of the channel\_thread This is the name of the channel\_thread This is the uuid of the channel\_thread This is the user\_id of the channel\_thread ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/channelthread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MyChannelThread { channel_thread { id created_at name system_prompt user_id messages { id body channel_id chat_id created_at date deliveredReceipt from fromMe likes messageNumber points sentReceipt timestamp to } } } ``` ```js Node.js theme={null} const channel_threads = await stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} channel_threads = stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} channel_threads, err := stateset.Messages.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} channel_threads = Stateset::Messages.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} ChannelThread channel_threads = Stateset.ChannelThreads.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} ChannelThread channel_threads = Stateset.ChannelThreads.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $channel_threads = Stateset\ChannelThreads::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/channel_threads HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` # List Channel Threads Source: https://docs.stateset.com/response-api-reference/channel-threads/list GET https://api.stateset.com/v1/channel_threads This endpoint gets a channel threads. ### Body ### Response This is the id of the channel\_thread This is the name of the channel\_thread This is the uuid of the channel\_thread This is the user\_id of the channel\_thread ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/channel_threads' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```graphQL GraphQL theme={null} query MyChannelThread { channel_thread { id created_at name system_prompt user_id messages { id body channel_id chat_id created_at date deliveredReceipt from fromMe likes messageNumber points sentReceipt timestamp to } } } ``` ```js Node.js theme={null} const channel_threads = await stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} channel_threads = stateset.channel_threads.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} channel_threads, err := stateset.Messages.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} channel_threads = Stateset::Messages.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} ChannelThread channel_threads = Stateset.ChannelThreads.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} ChannelThread channel_threads = Stateset.ChannelThreads.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $channel_threads = Stateset\ChannelThreads::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/channel_threads HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` # Update Channel Thread Source: https://docs.stateset.com/response-api-reference/channel-threads/update PUT https://api.stateset.com/v1/channel_thread This endpoint creates a new channel thread ### Body This is the ID of the channel thread to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/channel_thread' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```javascript Node.js theme={null} const created = await stateset.channel.update({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_channel_thread": { "returning": [ { "id": "", "name": "", "uuid": "", "user_id": "" } ] } } } ``` # Computer Use AI Agents Source: https://docs.stateset.com/response-api-reference/computer-use # Computer Use AI Agents Imagine telling your AI assistant to handle that tedious onboarding paperwork, automatically fill forms across systems, or select a contact reason to auto-close weekend-built tickets. That's now a reality with Anthropic's new Computer Use capabilities. Our goal is to translate human intent into agentic outcomes – think of these agents as virtual coworkers. At StateSet, we're building the best AI agents for the fastest-growing DTC brands, combining deterministic workflows with generative, personalized responses. ## Computer Use API: A New Frontier Unlike slow, complex RPA/BPM tools, our Computer Use AI works directly through the browser with existing websites and legacy systems. Our mission is to create the **Autonomous Commerce Operating System**, and Computer Use API will be a key part. Envision a virtual coworker handling browser-based repetitive tasks, freeing you for strategic work. ## Tips & Limitations of Computer Use Today * No account creation or social media posting (safety first) * Keyboard shortcuts preferred over mouse movements (reliability) * Built-in verification steps (trust but verify) * Focus on non-time-critical tasks (practical boundaries) These aren't limitations – they're features for reliable, trustworthy real-world applications. We'll focus on repetitive tasks, with proper guardrails. ## Real-World Applications * Automated onboarding processes * Automatically closing tickets * Repetitive data entry tasks * Monitoring Social Media Comments * Form filling across multiple systems * Legacy system integration without API development ## Practical Implementation Tips * Break complex tasks into well-specified steps. * Verify outcomes explicitly. * Prefer keyboard shortcuts over mouse movements. * Include example screenshots for repeatable tasks. ## The Future of Autonomous Commerce Operations The implications are profound. AI isn't just about chat or content generation anymore. We're entering a world where AI can act directly within daily interfaces. We're already using AI Agents daily for coding, search, data updates, and document processing. Now we have autonomous agents that can complete tasks, handle workflows, and interact with browser-based systems. At StateSet, we're moving towards a world where we orchestrate multiple AI agents for our customers, powering their scale across modalities, and now, in the browser as well. Imagine an intelligent RPA macro machine. ## My General Thoughts * Start with well-defined, repeatable tasks. * Build verification into workflows. * Use screenshot examples in prompts. * Focus on non-critical but repetitive processes first. ## Looking Ahead What we saw isn't just another AI update; it's a glimpse into a future where AI understands and executes human intent reliably. The future of human-AI collaboration is here. It’s more practical, reliable, and transformative than expected. # Deploy Source: https://docs.stateset.com/response-api-reference/deploy Deploy ResponseCX agents with the SDK # Deploy an agent with the SDK ### SDK The ResponseCX agent runtime is built on top of StateSet Cloud platform infrastructure, a deterministic workflow engine, an event-driven architecture, and state-of-the-art models. Each agent has its own configuration and set of modules that define its behavior. ### TypeScript One-Click Deploy Deploying an agent with the SDK is as simple as copying and pasting the code below into a file and running it. ```typescript theme={null} import { NextRequest, NextResponse } from "next/server"; import { StateSetClient } from 'stateset-node'; import winston from 'winston'; const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', transports: [new winston.transports.Console()] }); // Ensure runtime is set to edge export const config = { runtime: 'edge', }; // Define interfaces for agent configuration interface AgentAttribute { attribute_name: string; attribute_type: string; value?: number; max_value?: number; min_value?: number; category?: string; description?: string; modifiable?: boolean; impact?: string; org_id?: string; activated?: boolean; user_id?: string; } interface AgentRule { rule_name: string; rule_type: string; activated: boolean; description: string; org_id: string; user_id?: string; } interface AgentWorkflow { name: string; description: string; type: string; triggers: Trigger[]; actions: Action[]; } interface Trigger { type: string; event: string; } interface Action { type: string; config: Record; } interface AgentChannel { name: string; type: string; config: Record; } interface AgentConfiguration { learning_rate: number; memory_retention: number; response_threshold: number; auto_escalation: boolean; monitoring: { performance_tracking: boolean; error_logging: boolean; activity_history: boolean; }; } // Helper function to retrieve API key securely const getApiKey = (): string => { const apiKey = process.env.STATESET_API_KEY; if (!apiKey) { throw new Error('STATESET_API_KEY is not defined in environment variables.'); } return apiKey; }; // Helper function to handle batch creation const createBatch = async (items: any[], createFn: Function, nameField: string): Promise => { const creationPromises = items.map(createFn); const results = await Promise.allSettled(creationPromises); const createdIds: string[] = []; results.forEach((result, index) => { if (result.status === 'fulfilled') { createdIds.push(result.value.id); } else { logger.error('Failed to create item', { nameField, name: items[index][nameField], reason: result.reason }); } }); return createdIds; }; // Main handler function export default async function handler(req: NextRequest) { try { const apiKey = getApiKey(); const client = new StateSetClient({ apiKey }); // Create the base agent const agent = await client.agents.create({ name: 'Order Processing Agent', description: 'AI Agent for handling order processing and management', type: 'order_processing', schema: { type: 'object', properties: { orderId: { type: 'string' }, customerId: { type: 'string' }, orderDetails: { type: 'object', properties: { items: { type: 'array' }, totalAmount: { type: 'number' }, shippingAddress: { type: 'object' } } } }, required: ['orderId'] }, capabilities: [ 'order_processing', 'customer_service', 'inventory_management', 'shipping_coordination' ] }); // Define agent components const personalityAttributes: AgentAttribute[] = [ { attribute_name: 'Efficiency', attribute_type: 'numeric', value: 90, max_value: 100, min_value: 0, category: 'performance', description: 'Speed and accuracy in processing orders', modifiable: true, impact: 'high', org_id: 'org_123', activated: true }, { attribute_name: 'Customer Focus', attribute_type: 'numeric', value: 95, max_value: 100, min_value: 0, category: 'personality', description: 'Level of attention to customer needs', modifiable: true, impact: 'high', org_id: 'org_123', activated: true }, { attribute_name: 'Adaptability', attribute_type: 'numeric', value: 85, max_value: 100, min_value: 0, category: 'personality', description: 'Ability to handle unexpected situations', modifiable: true, impact: 'medium', org_id: 'org_123', activated: true } ]; const operationalRules: AgentRule[] = [ { rule_name: 'Order Validation', rule_type: 'validation', activated: true, description: 'Validate all order details before processing', org_id: 'org_123' }, { rule_name: 'Inventory Check', rule_type: 'process', activated: true, description: 'Verify inventory availability before order confirmation', org_id: 'org_123' }, { rule_name: 'Customer Communication', rule_type: 'communication', activated: true, description: 'Maintain clear communication with customers throughout the process', org_id: 'org_123' }, { rule_name: 'Error Handling', rule_type: 'exception', activated: true, description: 'Handle errors and exceptions gracefully with proper escalation', org_id: 'org_123' } ]; const workflows: AgentWorkflow[] = [ { name: 'Order Processing Workflow', description: 'Standard workflow for processing new orders', type: 'sequential', triggers: [ { type: 'event', event: 'new_order_received' } ], actions: [ { type: 'validate_order', config: { checkInventory: true } }, { type: 'process_payment', config: { retryAttempts: 3 } }, { type: 'generate_shipping_label', config: { carrier: 'preferred' } } ] } ]; const channels: AgentChannel[] = [ { name: 'Customer Chat', type: 'chat', config: { response_time: 30, language: 'en', tone: 'professional' } }, { name: 'Email Notifications', type: 'email', config: { templates: { order_confirmation: true, shipping_update: true, delivery_confirmation: true } } } ]; // Create agent components const attributeIds = await createBatch(personalityAttributes, (attr) => client.attributes.create({ agent_id: agent.id, ...attr }), 'attribute_name'); const ruleIds = await createBatch(operationalRules, (rule) => client.rules.create({ agent_id: agent.id, ...rule }), 'rule_name'); const workflowIds = await createBatch(workflows, (workflow) => client.workflows.create({ agent_id: agent.id, ...workflow }), 'name'); const channelIds = await createBatch(channels, (channel) => client.channels.create({ agent_id: agent.id, ...channel }), 'name'); // Define agent configuration const agentConfig: AgentConfiguration = { learning_rate: 0.1, memory_retention: 0.8, response_threshold: 0.7, auto_escalation: true, monitoring: { performance_tracking: true, error_logging: true, activity_history: true } }; // Update agent with all created components const updatedAgent = await client.agents.update(agent.id, { attributes: attributeIds, rules: ruleIds, workflows: workflowIds, channels: channelIds, status: 'active', configuration: agentConfig }); // Activate the agent await client.agents.setAvailable(agent.id); return NextResponse.json({ status: 'success', message: 'Order processing agent created successfully', data: { agent_id: agent.id, attributes_created: attributeIds.length, rules_created: ruleIds.length, workflows_created: workflowIds.length, channels_created: channelIds.length, status: updatedAgent.status } }); } catch (error) { logger.error('Error creating order processing agent', { message: error instanceof Error ? error.message : String(error) }); return NextResponse.json({ status: 'error', message: error instanceof Error ? error.message : 'An unknown error occurred', timestamp: new Date().toISOString(), details: error instanceof Error ? { name: error.name, stack: process.env.NODE_ENV === 'development' ? error.stack : undefined } : undefined }, { status: 500, headers: { 'Content-Type': 'application/json' } }); } } ``` ### Python One Click Deploy Deploying an agent with the SDK is as simple as copying and pasting the code below into a file and running it. ```python theme={null} import os import asyncio import logging from stateset import StateSetClient from fastapi import FastAPI, Request, HTTPException from pydantic import BaseModel from typing import List, Dict, Optional app = FastAPI() logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Define data models class AgentAttribute(BaseModel): attribute_name: str attribute_type: str value: Optional[int] = None max_value: Optional[int] = None min_value: Optional[int] = None category: Optional[str] = None description: Optional[str] = None modifiable: Optional[bool] = None impact: Optional[str] = None org_id: Optional[str] = None activated: Optional[bool] = None class AgentRule(BaseModel): rule_name: str rule_type: str activated: bool description: str org_id: str class Trigger(BaseModel): type: str event: str class Action(BaseModel): type: str config: Dict[str, any] class AgentWorkflow(BaseModel): name: str description: str type: str triggers: List[Trigger] actions: List[Action] class AgentChannel(BaseModel): name: str type: str config: Dict[str, any] class AgentConfiguration(BaseModel): learning_rate: float memory_retention: float response_threshold: float auto_escalation: bool monitoring: Dict[str, bool] # Helper function to retrieve API key securely def get_api_key() -> str: api_key = os.getenv('STATESET_API_KEY') if not api_key: raise ValueError('STATESET_API_KEY is not defined in environment variables.') return api_key # Helper function to handle batch creation async def create_batch(items: List[BaseModel], create_fn, name_field: str) -> List[str]: tasks = [create_fn(item) for item in items] results = await asyncio.gather(*tasks, return_exceptions=True) created_ids = [] for i, result in enumerate(results): if isinstance(result, Exception): logger.error( "Failed to create %s: %s", name_field, getattr(items[i], name_field), exc_info=result, ) else: created_ids.append(result['id']) return created_ids @app.post("/create_agent") async def create_agent(): try: api_key = get_api_key() client = StateSetClient(api_key=api_key) # Create the base agent agent_data = { "name": "Order Processing Agent", "description": "AI Agent for handling order processing and management", "type": "order_processing", "schema": { "type": "object", "properties": { "orderId": {"type": "string"}, "customerId": {"type": "string"}, "orderDetails": { "type": "object", "properties": { "items": {"type": "array"}, "totalAmount": {"type": "number"}, "shippingAddress": {"type": "object"} } } }, "required": ["orderId"] }, "capabilities": [ "order_processing", "customer_service", "inventory_management", "shipping_coordination" ] } agent = await client.agents.create(agent_data) # Define agent components personality_attributes = [ AgentAttribute( attribute_name="Efficiency", attribute_type="numeric", value=90, max_value=100, min_value=0, category="performance", description="Speed and accuracy in processing orders", modifiable=True, impact="high", org_id="org_123", activated=True ), AgentAttribute( attribute_name="Customer Focus", attribute_type="numeric", value=95, max_value=100, min_value=0, category="personality", description="Level of attention to customer needs", modifiable=True, impact="high", org_id="org_123", activated=True ), AgentAttribute( attribute_name="Adaptability", attribute_type="numeric", value=85, max_value=100, min_value=0, category="personality", description="Ability to handle unexpected situations", modifiable=True, impact="medium", org_id="org_123", activated=True ) ] operational_rules = [ AgentRule( rule_name="Order Validation", rule_type="validation", activated=True, description="Validate all order details before processing", org_id="org_123" ), AgentRule( rule_name="Inventory Check", rule_type="process", activated=True, description="Verify inventory availability before order confirmation", org_id="org_123" ), AgentRule( rule_name="Customer Communication", rule_type="communication", activated=True, description="Maintain clear communication with customers throughout the process", org_id="org_123" ), AgentRule( rule_name="Error Handling", rule_type="exception", activated=True, description="Handle errors and exceptions gracefully with proper escalation", org_id="org_123" ) ] workflows = [ AgentWorkflow( name="Order Processing Workflow", description="Standard workflow for processing new orders", type="sequential", triggers=[ Trigger(type="event", event="new_order_received") ], actions=[ Action(type="validate_order", config={"checkInventory": True}), Action(type="process_payment", config={"retryAttempts": 3}), Action(type="generate_shipping_label", config={"carrier": "preferred"}) ] ) ] channels = [ AgentChannel( name="Customer Chat", type="chat", config={ "response_time": 30, "language": "en", "tone": "professional" } ), AgentChannel( name="Email Notifications", type="email", config={ "templates": { "order_confirmation": True, "shipping_update": True, "delivery_confirmation": True } } ) ] # Create agent components attribute_ids = await create_batch(personality_attributes, lambda attr: client.attributes.create(agent.id, attr.dict()), 'attribute_name') rule_ids = await create_batch(operational_rules, lambda rule: client.rules.create(agent.id, rule.dict()), 'rule_name') workflow_ids = await create_batch(workflows, lambda wf: client.workflows.create(agent.id, wf.dict()), 'name') channel_ids = await create_batch(channels, lambda ch: client.channels.create(agent.id, ch.dict()), 'name') # Define agent configuration agent_config = AgentConfiguration( learning_rate=0.1, memory_retention=0.8, response_threshold=0.7, auto_escalation=True, monitoring={ "performance_tracking": True, "error_logging": True, "activity_history": True } ) # Update agent with all created components updated_agent = await client.agents.update(agent.id, { "attributes": attribute_ids, "rules": rule_ids, "workflows": workflow_ids, "channels": channel_ids, "status": "active", "configuration": agent_config.dict() }) # Activate the agent await client.agents.set_available(agent.id) return { "status": "success", "message": "Order processing agent created successfully", "data": { "agent_id": agent.id, "attributes_created": len(attribute_ids), "rules_created": len(rule_ids), "workflows_created": len(workflow_ids), "channels_created": len(channel_ids), "status": updated_agent['status'] } } except Exception as error: logger.error('Error creating order processing agent', exc_info=error) raise HTTPException(status_code=500, detail=str(error)) ``` # Create Embedding Source: https://docs.stateset.com/response-api-reference/embeddings/create POST https://api.stateset.com/v1/embeddings This endpoint creates a new embedding ### Body This is the ID of the embedding to be created. This is the text of the embedding. This is the metadata of the embedding. This is the user id of the embedding. ### Response This is the ID of the embedding. This is the text of the embedding. This is the metadata of the embedding. This is the user id of the embedding. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/embeddings' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "em_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` # Delete Embedding Source: https://docs.stateset.com/response-api-reference/embeddings/delete DELETE https://api.stateset.com/v1/embeddings This endpoint deletes an embedding ### Body This is the ID of the embedding to be created. ### Response This is the ID of the embedding. This is the text of the embedding. This is the user id of the embedding. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/embeddings' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "em_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` # Get Embeddings Source: https://docs.stateset.com/response-api-reference/embeddings/get GET https://api.stateset.com/v1/embeddings/:id This endpoint gets embeddings by id. ### Body This is the ID of the embedding to be created. ### Response This is the ID of the embedding. This is the text of the embedding. This is the metadata of the embedding. This is the user id of the embedding. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/embeddings/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "em_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` # List Embeddings Source: https://docs.stateset.com/response-api-reference/embeddings/list GET https://api.stateset.com/v1/embeddings This endpoint gets all embeddings. ### Body ### Response This is the ID of the embedding. This is the text of the embedding. This is the metadata of the embedding. This is the user id of the embedding. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/embeddings' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` # Update Embedding Source: https://docs.stateset.com/response-api-reference/embeddings/update PUT https://api.stateset.com/v1/embeddings This endpoint updates an embedding ### Body This is the ID of the embedding to be created. This is the text of the embedding. This is the metadata of the embedding. This is the user id of the embedding. ### Response This is the ID of the embedding. This is the text of the embedding. This is the metadata of the embedding. This is the user id of the embedding. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/embeddings' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "em_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` # Create Example Source: https://docs.stateset.com/response-api-reference/examples/create POST https://api.stateset.com/v1/examples This endpoint creates a new example ### Body The name of the example to be created. The type of the example (e.g., string, number, boolean). A brief description of the example. This is the ticket\_id of the example. This is the created\_at of the example. This is the updated\_at of the example. ### Response The name of the created example. The type of the created example. A brief description of the created example. This is the ticket\_id of the example. This is the created\_at of the example. This is the updated\_at of the example. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/examples' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "em_1NXWPnCo6bFb1KQto6C8OWvE", "example_name": "Example Name", "example_type": "string" }' ``` # Delete Example Source: https://docs.stateset.com/response-api-reference/examples/delete DELETE https://api.stateset.com/v1/examples This endpoint deletes a example. ### Body This is the id of the example. ### Response This is the id of the example. This is the type of the example. This is the name of the example. This is the description of the example. This is the created\_at of the example. This is the updated\_at of the example. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/example' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00" } ``` # Get Example Source: https://docs.stateset.com/response-api-reference/examples/get GET https://api.stateset.com/v1/example This endpoint gets an example ### Body This is the id of the example. ### Response This is the id of the example. This is the type of the example. This is the name of the example. This is the ticket\_id of the example. This is the description of the example. This is the created\_at of the example. This is the updated\_at of the example. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/example' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Example", "name": "Confidence", "description": "This is the cancellation example", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # List Examples Source: https://docs.stateset.com/response-api-reference/examples/list GET https://api.stateset.com/v1/examples This endpoint gets an example ### Body ### Response This is the id of the example. This is the type of the example. This is the name of the example. This is the ticket\_id of the example. This is the description of the example. This is the created\_at of the example. This is the updated\_at of the example. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/examples' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System example", "name": "example 1", "description": "This is the cancellation example", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Update Example Source: https://docs.stateset.com/response-api-reference/examples/update PUT https://api.stateset.com/v1/examples This endpoint updates an example ### Body This is the id of the example. This is the type of the example. This is the name of the example. This is the description of the example. This is the ticket\_id of the example. This is the created\_at of the example. This is the updated\_at of the example. ### Response This is the id of the example. This is the type of the example. This is the name of the example. This is the description of the example. This is the ticket\_id of the example. This is the created\_at of the example. This is the updated\_at of the example. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/examples' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System example", "name": "example 1", "ticket_id_: "1231213", "description": "This is the example", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System example", "name": "example 1", "ticket_id_: "1231213", "description": "This is the example", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Agent Framework and SDK Source: https://docs.stateset.com/response-api-reference/framework Explore the components and capabilities of the StateSet ResponseCX AI Agent Framework and SDK. # StateSet ResponseCX AI Agent Framework and SDK The StateSet ResponseCX AI Agent Framework is a powerful suite of tools and libraries designed to facilitate the development and deployment of sophisticated AI agents. This framework provides a robust foundation for building intelligent, autonomous agents that can handle complex tasks. ## Framework Overview The ResponseCX AI Agent Framework integrates several key components to create a complete system for building intelligent agents. ```mermaid theme={null} flowchart LR subgraph VectorDB["Vector Database"] direction TB VDB((Vector DB)) end subgraph MacrosFAQs["Macros"] direction TB Macros["Macros"] FAQs["FAQs"] Product["Product"] Blogs["Blogs"] Articles["Articles"] end Application[Application] --> |Query| EmbeddingModel[Embedding Model] EmbeddingModel --> MetadataFilter[Metadata Filter] MetadataFilter --> |Vector Embedding| API[API] API <--> VectorDB API --> Context[Context] Context --> LLM[LLM] LLM --> |Stream| Application subgraph LLMModels["LLM Models"] direction TB GPT4o[GPT4o] Claude[Claude] Llama3[Llama3] end subgraph KnowledgeBase["Knowledge"] direction TB Memories[Memories] Rules[Rules] Attributes[Attributes] Examples[Examples] end subgraph Workflows["Workflows"] direction TB subgraph Activities["Activities"] direction TB Action1[Action 1] Action2[Action 2] Action3[Action 3] end end Agent[Agent] Scheduler[Scheduler] LLM -.-> LLMModels LLM -.-> KnowledgeBase LLM --> Agent Agent --> Workflows Workflows --> Scheduler Scheduler --> |Scheduled Messages| Application ``` ### Key Components: * **Application:** The user-facing interface or system interacting with the AI agent. * **Embedding Model:** Transforms text queries into vector embeddings for semantic search. * **Metadata Filter:** Filters vector results based on specified metadata. * **API:** Provides the interface for interacting with the Vector Database. * **Vector Database (VDB):** Stores and retrieves vector embeddings, allowing for fast similarity searches. * **Context:** Provides relevant information to the LLM for generating responses. * **LLM (Large Language Model):** Generates responses based on the context and query. * **LLM Models:** (GPT4o, Claude, Llama3) - The specific large language models that you can choose from. * **Knowledge Base:** (Memories, Rules, Attributes, Examples) - Stores relevant information about the agent's configuration. * **Workflows:** (Actions 1-3) - Define the sequence of operations that an agent can perform. * **Agent:** The core entity that leverages the LLM, Knowledge Base and Workflows. * **Scheduler:** Manages the timing and triggering of scheduled messages. * **Macros/FAQs:** Predefined sets of information and responses. ## SDK Overview The **ResponseCX AI Agent SDK** is built on top of the **StateSet Cloud platform infrastructure**, which includes: * A deterministic workflow engine * An event-driven architecture * A state-of-the-art AI model Each Agent has its own configuration and set of modules that are used to define the behavior of the agent. ## Modules The SDK is organized around the following modules: * **Agents:** Configure agent-specific settings and behaviors. * **Knowledge:** Store and manage the agent's knowledge base. * **Attributes:** Define properties and characteristics of the agent. * **Rules:** Establish logic and conditions for the agent's actions. * **Functions:** Add custom code and capabilities to the agent. * **Memories:** Store and retrieve past interactions to maintain context. * **Examples:** Provide training data for the agent to learn from. * **Schedules:** Set up recurring tasks and notifications for the agent. * **Settings:** Configure general settings and parameters for the agent. Each module has its own set of endpoints that developers can use to build, customize, and deploy agents. ## AI Agents Robert is a customer experience agent built on the ResponseCX Platform. Robert Robert CX Stats ```json theme={null} { "data": { "agents": [ { "id": "d8a35c79...", "activated": true, "agent_name": "Robert", "agent_type": "Subscription and Order Agent", "goal": "Create great customer experiences", "description": "Robert is the Subscriptions and Order Agent", "instructions": "Answer the customer's question to the best of your ability based on the brand attributes, rules and actions.", "role": "Customer Experience Agent", "agent_attributes": [ { "attribute_name": "Confident", "attribute_type": "Brand Tone and Voice", "description": "We assert the superiority of our product based on its unique properties and its research support. This authoritative stance is balanced with an approachable and informative manner.", "value": 15, "activated": null }, { "attribute_name": "Empathetic and Supportive", "attribute_type": "Brand Tone and Voice", "description": "We encourage customer interaction, whether it’s through sharing their experiences or providing feedback, which demonstrates that we value customer involvement and continuous improvement.", "value": 15, "activated": null }, { "attribute_name": "Educational and Scientific", "attribute_type": "Brand Tone and Voice", "description": "Educational and Scientific, very knowledgeable and very educational like a great teacher.", "value": 14, "activated": null } ], "agent_rules": [ { "rule_name": "Order Cancel Rule", "rule_type": "System Rule", "description": "If the customer ask to cancel my order or please cancel my order, call the cancel-order function." }, { "rule_name": "Always Respond Politely", "rule_type": "System Rule", "description": "Always respond very politely to the customer." }, { "rule_name": "Do not Repeat", "rule_type": "System Rule", "description": "Do not repeat the same answer." }, { "rule_name": "After you Respond", "rule_type": "System Rule", "description": "After you respond (if the customer asked a question), please say, \"Please let me know if you have any other questions.”, If they say they have no other questions or if they confirm their question was answered, please say: “Thank you for reaching out and have a great rest of the day!”. If the customer says thank you, please respond with, “You are welcome, have a great rest of the day!”." }, { "rule_name": "Email Rule", "rule_type": "System Rule", "description": "ALWAYS add breaks (\"

\") between sentences to the response where you see fit (make sure it is NOT just one block of text, this is an email like format with spacing (\"
\") between sentences and paragraphs, each paragraph is enclosed within

tags, and line breaks within paragraphs are represented by
tags)." }, { "rule_name": "Giveaways", "rule_type": "System Rule", "description": "Do not agree to participate in any giveaways, programs or collaborations offered by customers." }, { "rule_name": "Do not Mention you're an AI", "rule_type": "System Rule", "description": "Do not mention you're an AI to the customer. You are a member of the customer service team named Robert." }, { "rule_name": "Order Cancel Confirmation", "rule_type": "System Rule", "description": "Only confirm order cancellations and refunds if the cancel-order function has been called." }, { "rule_name": "Do not Write Tool Calls in your Response", "rule_type": "System Rule", "description": "DO NOT Write tool calls in your response eg { \"tool_uses\": [ { \"recipient_name\": \"functions.send-code\", \"parameters\": { \"email\": \"erebne00@leeu.edu\", \"code\": \"acrn\" } } ] }. Do not include these in the message to the customer." }, { "rule_name": "Cancel Subscription Rule", "rule_type": "System Rule", "description": "If the customer asks to cancel their subscription, ALWAYS first ask would you like to pause or skip your next order instead? If they confirm cancel, call the cancel function. If they say pause or skip next order, call the pause or skip-next-order function." }, { "rule_name": "Function Calls", "rule_type": "System Rule", "description": "If the customer asks to perform a change to their account, call the corresponding function but in your response do not mention I will need to use our internal tools to manage your request eg. don't say [Initiating send-code function with email]" }, { "rule_name": "Skip Next Order Rule", "rule_type": "System Rule", "description": "If the customer asks to skip their next order, call the skip-next-order function and send a confirmation message that their next order has been skipped." }, { "rule_name": "Do not agree to discounts", "rule_type": "System Prompt", "description": "Under no circumstance should you agree to apply a discount to an order." }, { "rule_name": "Change Frequency", "rule_type": "System Prompt", "description": "If the customer asks to change their subscription frequency, call the change-frequency function." }, { "rule_name": "You are Robert", "rule_type": "System Rule", "description": "You are Robert on the customer service team." }, { "rule_name": "eMail Signature", "rule_type": "System Prompt", "description": "

\nBest regards, \n
Robert
Customer Service Representative at StateSet" }, { "rule_name": "Wholesale Rule", "rule_type": "System Rule", "description": "Do not answer any wholesale request. Please say an agent will be with you momentarily." }, { "rule_name": "Shipping Labels", "rule_type": "System Rule", "description": "Do not confirm / promise to send shipping labels." }, { "rule_name": "Pause Rule Details", "rule_type": "System Rule", "description": "If the customer asks to pause for more than 3 months, please do not call the pause function. Please let them know that the most a subscription can be paused is 3 months and ask if that is ok with them. If so call the pause function." }, { "rule_name": "Medical Advise", "rule_type": "System Rule", "description": "Do not provide medical advise." } ], "agent_schedules": [ { "schedule_name": "Wait 3 Minutes", "schedule_type": "eMail Schedule", "description": "3 minutes" } ], "agent_settings": [ { "id": 1, "test": true, "agent_take_over_tag": "agent-take-over", "skip_emails": [ "square@help-messaging.squareup.com", "noreply@facebookmail.com" ], "skip_tags": [ "RETURNS", "EXCHANGES", "RETURN/EXCHANGE" ], "model_name": "llama3.1:8b", "model_type": "open", "model_provider": "StateSet Cloud Platform", "temperature": 0.2, "max_tokens": 1034, "skip_subjects": [ "Using Happy Hour in Your Routine", "forget to break the seal", "A Finish For Every Mood", "Automatic reply:" ], "out_of_office_keywords": [ "office", "Out Of office", "Out of office", "Out Of Office", "I am currently Out of Office" ], "skip_channels": [ "sms", "facebook", "facebook-mention", "instagram-comment", "instagram-direct-message", "instagram-ad-comment" ], "skip_instagram_messages": [ "Mentioned you in their story", "Media not yet supported by the Messenger API for Instagram." ], "agent_emails": [ "support@stateset.com", "response@stateset.com" ], "time_threshold": 2000, "assignee_user_id": 321321312, "allowed_intents": [ "subscription/cancel", "subscription/change", "order/cancel" ], "intent_skip_email": "dom@stateset.com", "health_concern_keywords": [ "ill", "sick", "allergic", "gastro", "intolerant", "reaction", "sickness", "bloated", "upset stomach", "side effects", "illness" ], "agent_takeover_phrases": [ "an agent will be with you momentarily", "I'm sorry for any inconvenience you may have experienced, an agent will be with you momentarily.", "I apologize for the inconvenience. We understand that you may have some questions that require a more detailed response. We will have an agent with you momentarily and we will be available to answer any questions you may have." ], "escalation_team_id": 1231, "escalation_tag_name": "agent-take-over", "stateset_response_gorgias_email": "support@stateset.com", "stateset_response_gorgias_user_id": "", "stateset_response_name": "Robert Customer Support", "name_from": "Robert Customer Support", "address_from": "support@stateset.com" } ] } ] } } ``` ## Interaction Overview Here's an overview of how the different components interact: 1. The **Application** sends a **Query** to the **Embedding Model**. 2. The **Embedding Model** generates a vector embedding of the query. 3. The **Metadata Filter** is used to filter the results. 4. The filtered vector embedding is sent to the **API** for retrieval of information from the **Vector Database**. 5. The **API** retrieves relevant vectors and corresponding data. 6. The retrieved data is passed as a **Context** to the **LLM**. 7. The **LLM** uses the **Context** and **Knowledge** to generate a response, which is then streamed back to the **Application**. 8. The **Agent** triggers predefined **Workflows**, which are then controlled by the **Scheduler**. This framework allows for the creation of a wide range of intelligent agents with varying capabilities and levels of autonomy. # Create Function Parameter Source: https://docs.stateset.com/response-api-reference/function-parameters/create POST https://api.stateset.com/v1/function_parameters This endpoint creates a new function parameter ### Body This is the id of the rule. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the function parameter. ### Response This is the id of the function parameter. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the rule. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/function_parameter' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Delete Function Parameter Source: https://docs.stateset.com/response-api-reference/function-parameters/delete DELETE https://api.stateset.com/v1/function_parameters This endpoint deletes a function parameter ### Body This is the id of the function parameter. It is used to identify the function parameter. ### Response This is the id of the function parameter. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the function parameter. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/function_parameter' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Get Function Parameter Source: https://docs.stateset.com/response-api-reference/function-parameters/get GET https://api.stateset.com/v1/function_parameters This endpoint gets a new function parameter ### Body This is the id of the rule. It is used to identify the function parameter. ### Response This is the id of the function parameter. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the function parameter. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/function_parameter' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # List Function Parameters Source: https://docs.stateset.com/response-api-reference/function-parameters/list GET https://api.stateset.com/v1/function_parameters This endpoint gets function parameters ### Body ### Response This is the id of the function parameter. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the function parameter. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/function_parameters' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Update Function Parameter Source: https://docs.stateset.com/response-api-reference/function-parameters/update PUT https://api.stateset.com/v1/function_parameters This endpoint updates a new function parameter ### Body This is the id of the function parameter. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the function parameter. ### Response This is the id of the function parameter. It is used to identify the function parameter. This is the id of the function. It is used to identify the function. This is the name of the function parameter. It is used to identify the function parameter. This is the description of the function parameter. It is used to identify the function parameter. This is the activated check of the function parameter. It is used to identify the function parameter activation state. This is the created\_at of the function parameter. It is used to identify the function parameter. This is the updated\_at of the function parameter. It is used to identify the function parameter. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/function_parameter' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_id": "2438cf38-4004-41d3-8c90-131735ff7d00", "function_parameter_name": "Function 1", "function_parameter_description": "This is the function", "activated": true, "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Create Function Source: https://docs.stateset.com/response-api-reference/functions/create POST https://api.stateset.com/v1/functions This endpoint creates a new function ### Body This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ### Response This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/functions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Function", "name": "Function 1", "description": "This is the function", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Function", "name": "Function 1", "description": "This is the function", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Delete Function Source: https://docs.stateset.com/response-api-reference/functions/delete DELETE https://api.stateset.com/v1/functions This endpoint deletes a function ### Body This is the id of the function. ### Response This is the id of the function. This is the type of the function. This is the name of the function. This is the description of the function. This is the created\_at of the function. This is the updated\_at of the function. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/functions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00" } ``` # Get Function Source: https://docs.stateset.com/response-api-reference/functions/get GET https://api.stateset.com/v1/functions This endpoint gets a function ### Body This is the id of the function. ### Response This is the id of the function. This is the type of the function. This is the name of the function. This is the description of the function. This is the created\_at of the function. This is the updated\_at of the function. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/functions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Function", "name": "Function 1", "description": "This is the function", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # List Functions Source: https://docs.stateset.com/response-api-reference/functions/list GET https://api.stateset.com/v1/functions This endpoint gets a function ### Body ### Response This is the id of the function. This is the type of the function. This is the name of the function. This is the description of the function. This is the created\_at of the function. This is the updated\_at of the function. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/functions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Function", "name": "Function 1", "description": "This is the function", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Update Function Source: https://docs.stateset.com/response-api-reference/functions/update PUT https://api.stateset.com/v1/functions This endpoint updates a function ### Body This is the id of the function. This is the type of the function. This is the name of the function. This is the description of the function. This is the created\_at of the function. This is the updated\_at of the function. ### Response This is the id of the function. This is the type of the function. This is the name of the function. This is the description of the function. This is the created\_at of the function. This is the updated\_at of the function. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/functions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Function", "name": "Function 1", "description": "This is the function", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Function", "name": "Function 1", "description": "This is the function", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Create Memory Source: https://docs.stateset.com/response-api-reference/memories/create POST https://api.stateset.com/v1/memory This endpoint creates a new memory ### Body This is the unique identifier for the memory. This is the content of the memory. This is the type of memory (e.g., short-term, long-term). This is the unique identifier for the user associated with the memory. This is the unique identifier for the agent that created the memory. This is the timestamp when the memory was created. ### Response The unique identifier for the memory. The content of the memory that was stored. The type of memory (e.g., short-term, long-term). The unique identifier for the user associated with the memory. The unique identifier for the agent that created the memory. The timestamp when the memory was created. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/memory' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" }' ``` ```graphQL GraphQL theme={null} mutation InsertNewMemory( $memory: memories_insert_input! ) { insert_memories ( objects: [$memory] ) { returning { id memory memory_type user_id agent_id created_at } } }`; ``` ```js Node.js theme={null} const memory = await stateset.memory.create({ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" }) ``` ```json Response theme={null} { "memory": { "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" } } ``` # Delete Memory Source: https://docs.stateset.com/response-api-reference/memories/delete DELETE https://api.stateset.com/v1/memory This endpoint deletes a memory ### Body This is the unique identifier for the memory. ### Response The unique identifier for the memory. The content of the memory that was stored. The type of memory (e.g., short-term, long-term). The unique identifier for the user associated with the memory. The unique identifier for the agent that created the memory. The timestamp when the memory was created. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/memory' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst" }' ``` ```graphQL GraphQL theme={null} mutation DeleteMemory( $id: String! ) { delete_memories ( objects: [$id] ) { returning { id memory memory_type user_id agent_id created_at } } }`; ``` ```js Node.js theme={null} const memory = await stateset.memory.create({ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" }) ``` ```json Response theme={null} { "memory": { "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" } } ``` # Get Memory Source: https://docs.stateset.com/response-api-reference/memories/get GET https://api.stateset.com/v1/memory This endpoint gets a memory ### Body This is the unique identifier for the memory. ### Response The unique identifier for the memory. The content of the memory that was stored. The type of memory (e.g., short-term, long-term). The unique identifier for the user associated with the memory. The unique identifier for the agent that created the memory. The timestamp when the memory was created. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/memory' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst" }' ``` ```graphQL GraphQL theme={null} mutation InsertNewMemory( $memory: memories_insert_input! ) { insert_memories ( objects: [$memory] ) { returning { id memory memory_type user_id agent_id created_at } } }`; ``` ```js Node.js theme={null} const memory = await stateset.memory.get({ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" }) ``` ```json Response theme={null} { "memory": { "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" } } ``` # List Memories Source: https://docs.stateset.com/response-api-reference/memories/list GET https://api.stateset.com/v1/memory This endpoint lists all memories ### Body This is the unique identifier for the user associated with the memory. This is the unique identifier for the agent that created the memory. ### Response The unique identifier for the memory. The content of the memory that was stored. The type of memory (e.g., short-term, long-term). The unique identifier for the user associated with the memory. The unique identifier for the agent that created the memory. The timestamp when the memory was created. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/memory' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_id": "user_1234abcd", "agent_id": "agent_5678efgh" }' ``` ```graphQL GraphQL theme={null} query ListMemories( $user_id: String! $agent_id: String! ) { memories( where: { user_id: {_eq: $user_id} agent_id: {_eq: $agent_id} } ) { returning { id memory memory_type user_id agent_id created_at } } }`; ``` ```js Node.js theme={null} const memory = await stateset.memory.list({ "user_id": "user_1234abcd", "agent_id": "agent_5678efgh" }) ``` ```json Response theme={null} { "memory": { "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" } } ``` # Update Memory Source: https://docs.stateset.com/response-api-reference/memories/update PUT https://api.stateset.com/v1/memory This endpoint updates a memory ### Body This is the unique identifier for the memory. This is the content of the memory. This is the type of memory (e.g., short-term, long-term). This is the unique identifier for the user associated with the memory. This is the unique identifier for the agent that created the memory. This is the timestamp when the memory was created. ### Response The unique identifier for the memory. The content of the memory that was stored. The type of memory (e.g., short-term, long-term). The unique identifier for the user associated with the memory. The unique identifier for the agent that created the memory. The timestamp when the memory was created. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/memory' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh" }' ``` ```graphQL GraphQL theme={null} mutation UpdateMemory( $memory: memories_update_input! ) { update_memories ( objects: [$memory] ) { returning { id memory memory_type user_id agent_id created_at } } }`; ``` ```js Node.js theme={null} const memory = await stateset.memory.update({ "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh" }) ``` ```json Response theme={null} { "memory": { "id": "1234abcd-5678-efgh-9101-ijklmnopqrst", "memory": "User prefers to receive notifications via email.", "memory_type": "long-term", "user_id": "user_1234abcd", "agent_id": "agent_5678efgh", "created_at": "2024-08-25T10:00:00Z" } } ``` # Messages Source: https://docs.stateset.com/response-api-reference/messages Overview of message resources. # Messages Use the messages endpoints to manage conversation messages. * [List](/response-api-reference/messages/list) * [Get](/response-api-reference/messages/get) * [Create](/response-api-reference/messages/create) * [Update](/response-api-reference/messages/update) * [Delete](/response-api-reference/messages/delete) # Create Message Source: https://docs.stateset.com/response-api-reference/messages/create POST https://api.stateset.com/v1/messages This endpoint creates a new message ### Body This is the ID of the message to be created. This is the time of the message to be created. This is the body of the message to be created. This is the username of the message to be created. This is the channel\_id of the message to be created. This is the user\_id of the message to be created. This is the is\_public of the message to be created. This is the from of the message to be created. This is the to of the message to be created. This is the from\_me of the message to be created. This is the sent\_receipt of the message to be created. This is the delivered\_receipt of the message to be created. This is the message\_number of the message to be created. This is the date of the message to be created. This is the timestamp of the message to be created. This is the created\_at of the message to be created. This is the updated\_at of the message to be created. ### Response This is the id of the message. This is the body of the message. This is the date and time when the message was created. This is the date when the message was sent. This indicates if the message has been delivered. This is the sender of the message. This indicates if the message was sent by the user. This indicates if the message is public or private. This is the unique number assigned to the message. This indicates if the message has been sent. This is the time when the message was sent. This is the timestamp of the message. This is the recipient of the message. This is the unique identifier for the user associated with the message. This is the username of the user associated with the message. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/message' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation insert_message ($message: message_insert_input! ){ insert_message ( objects: [$message] ) { returning { id time body username } } } ``` ```javascript Node.js theme={null} const created = await stateset.message.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_message": { "returning": [ { "id": "", } ] } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # Delete Message Source: https://docs.stateset.com/response-api-reference/messages/delete DELETE https://api.stateset.com/v1/messages/:id This endpoint deletes an existing message. ### Body The ID provided in the data tab may be used to identify the message ### Response The ID provided in the data tab may be used to identify the message The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/messages/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "msg_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteMessage ($id: String!) { delete_message(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const message = await stateset.channelthread.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} message = stateset.message.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} message, err := stateset.Cases.Del( "msg_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case message = stateset.message.del( "msg_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const message = await stateset.message.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} message = Stateset::Return.del({ 'msg_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $message = $stateset->message->del( 'msg_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/channelthread HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "channel_thread", "deleted": true } ``` # Get Messages Source: https://docs.stateset.com/response-api-reference/messages/get GET https://api.stateset.com/v1/messages/:id This endpoint gets a message. ### Body This is the id of the message. ### Response This is the id of the message. This is the body of the message. This is the date and time when the message was created. This is the date when the message was sent. This indicates if the message has been delivered. This is the sender of the message. This indicates if the message was sent by the user. This indicates if the message is public or private. This is the unique number assigned to the message. This indicates if the message has been sent. This is the time when the message was sent. This is the timestamp of the message. This is the recipient of the message. This is the unique identifier for the user associated with the message. This is the username of the user associated with the message. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/messages/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MyMessages { message { id body created_at date deliveredReceipt from fromMe is_public messageNumber sentReceipt time timestamp to user_id username } } ``` ```js Node.js theme={null} const messages = await stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} messages = stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} messages, err := stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} messages = Stateset::Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Message messages = Stateset.Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Message messages = Stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $messages = Stateset\Messages::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/messages HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # List Messages Source: https://docs.stateset.com/response-api-reference/messages/list GET https://api.stateset.com/v1/messages This endpoint lists messages. ### Body This is the limit of the messages. This is the offset of the messages This is the order direction of the messages. ### Response This is the id of the message. This is the body of the message. This is the date and time when the message was created. This is the date when the message was sent. This indicates if the message has been delivered. This is the sender of the message. This indicates if the message was sent by the user. This indicates if the message is public or private. This is the unique number assigned to the message. This indicates if the message has been sent. This is the time when the message was sent. This is the timestamp of the message. This is the recipient of the message. This is the unique identifier for the user associated with the message. This is the username of the user associated with the message. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/messages' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MyMessages { message { id body created_at date deliveredReceipt from fromMe is_public messageNumber sentReceipt time timestamp to user_id username } } ``` ```js Node.js theme={null} const messages = await stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} messages = stateset.messages.retrieve({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} messages, err := stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} messages = Stateset::Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Message messages = Stateset.Messages.retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Message messages = Stateset.Messages.Retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $messages = Stateset\Messages::retrieve( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/messages HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "body": "Hello World", "created_at": "2021-01-01T00:00:00.000000Z", "date": "2021-01-01", "deliveredReceipt": true, "from": "user1", "fromMe": true, "is_public": true, "messageNumber": 1, "sentReceipt": true, "time": "00:00:00", "timestamp": "2021-01-01T00:00:00.000000Z", "to": "user2", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "username": "user1" } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # Update Message Source: https://docs.stateset.com/response-api-reference/messages/update POST https://api.stateset.com/v1/messages/:id This endpoint updates a message ### Body This is the ID of the message to be created. This is the time of the message to be created. This is the body of the message to be created. This is the username of the message to be created. This is the channel\_id of the message to be created. This is the user\_id of the message to be created. This is the is\_public of the message to be created. This is the from of the message to be created. This is the to of the message to be created. This is the from\_me of the message to be created. This is the sent\_receipt of the message to be created. This is the delivered\_receipt of the message to be created. This is the message\_number of the message to be created. This is the date of the message to be created. This is the timestamp of the message to be created. This is the created\_at of the message to be created. This is the updated\_at of the message to be created. ### Response ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/messages/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation insert_message ($message: message_insert_input! ){ insert_message ( objects: [$message] ) { returning { id time body username } } } ``` ```javascript Node.js theme={null} const created = await stateset.message.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_message": { "returning": [ { "id": "", } ] } } } ``` ### Messages | Field | Type | Description | | ---------------- | -------- | ---------------------------------------------------------- | | id | String | Unique identifier for the message | | body | String | The content or text of the message | | created\_at | DateTime | The date and time when the message was created | | date | Date | The date when the message was sent | | deliveredReceipt | Boolean | Indicates if the message has been delivered | | from | String | Sender of the message | | fromMe | Boolean | Indicates if the message was sent by the user | | is\_public | Boolean | Indicates if the message is public or private | | messageNumber | Integer | Unique number assigned to the message | | sentReceipt | Boolean | Indicates if the message has been sent | | time | Time | The time when the message was sent | | timestamp | DateTime | The timestamp of the message | | to | String | Recipient of the message | | user\_id | String | Unique identifier for the user associated with the message | | username | String | Username of the user associated with the message | # Models Source: https://docs.stateset.com/response-api-reference/models Models supported by the StateSet ResponseCX API StateSet ResponseCX supports the following AI models: ### o1-preview o1-preview is a variant of OpenAI's o1 model, optimized for performance on a wide range of reasoning, physics and math tasks. ### GPT4o GPT4o is a variant of OpenAI's GPT-4 model, optimized for performance on a wide range of tasks. ### Claude 3.5 Sonnet Claude 3.5 Sonnet is an advanced language model developed by Anthropic, known for its strong performance across a wide range of tasks. ### Llama 3.1 Llama 3.1 is available in three variants: ### Llama 3.1 405B (Preview) * Model ID: llama-3.1-405b-reasoning * Developer: Meta * Context Window: 131,072 tokens * Max Input Tokens: 16,000 (during preview) ### Llama 3.1 70B (Preview) * Model ID: llama-3.1-70b-versatile * Developer: Meta * Context Window: 131,072 tokens * Max Input Tokens: 8,000 (during preview) ### Llama 3.1 8B (Preview) * Model ID: llama-3.1-8b-instant * Developer: Meta * Context Window: 131,072 tokens * Max Input Tokens: 8,000 (during preview) Note: During the preview launch, all Llama 3.1 models are limited to a maximum of 8,000 output tokens. ### Llama 3 Groq 70B Tool Use (Preview) * Model ID: llama3-groq-70b-8192-tool-use-preview * Developer: Groq * Context Window: 8,192 tokens ### Llama 3 Groq 8B Tool Use (Preview) * Model ID: llama3-groq-8b-8192-tool-use-preview * Developer: Groq * Context Window: 8,192 tokens ### Meta Llama 3 70B * Model ID: llama3-70b-8192 * Developer: Meta * Context Window: 8,192 tokens ### Meta Llama 3 8B * Model ID: llama3-8b-8192 * Developer: Meta * Context Window: 8,192 tokens ### Mixtral 8x7B * Model ID: mixtral-8x7b-32768 * Developer: Mistral * Context Window: 32,768 tokens ### Gemini 1.5 Flash * Model ID: gemini-1.5-flash * Developer: Google * Context Window: 8,192 tokens ### Gemini 1.5 Pro * Model ID: gemini-1.5-pro * Developer: Google * Context Window: 8,192 tokens ### Gemma 7B * Model ID: gemma-7b-it * Developer: Google * Context Window: 8,192 tokens ### Gemma 2 9B * Model ID: gemma2-9b-it * Developer: Google * Context Window: 8,192 tokens ### Whisper * Model ID: whisper-large-v3 * Developer: OpenAI * File Size: 25 MB # ResponseCX Source: https://docs.stateset.com/response-api-reference/overview An overview of StateSet ResponseCX and its AI-driven approach to business software. # StateSet ResponseCX: Pioneering Autonomous Commerce with AI Agents ## The Dawn of Autonomous Business Software We are witnessing a fundamental shift in business software. The era of seat licenses and manual database management is fading, replaced by an age of **outcomes-as-a-service** powered by **application-specific AI agents**. At StateSet, we are not just anticipating this change; we are actively building it. Our AI agents, working autonomously alongside human teams, provide transparent reasoning for their actions. By blending **generative** and **deterministic** agentic operations, we are delivering truly intelligent automation at scale. ## Beyond Chatbots: The Power of Autonomous Agents These are not just chatbots. While traditional chatbots struggle with intent recognition and personalized responses, our autonomous agents are driving growth for the most innovative **Direct-to-Consumer (DTC) brands**. Companies like **ARMRA, Truvani, and Bartesian** are already using our platform to reclaim hundreds of hours weekly and offer unparalleled customer experiences. These brands are adopting our technology, redefining customer service, and streamlining operations. > **Imagine:** AI agents that proactively handle customer inquiries, manage returns, and optimize inventory, all with detailed reasoning and transparency. ## The StateSet Advantage: A Robust AI Platform StateSet's competitive edge extends far beyond a simple LLM wrapper. Our technology is fortified by: 1. **Proprietary Agent Orchestration Framework:** Manages the complex interactions between multiple AI agents. 2. **Blazing-Fast Query Engine:** Enables rapid data retrieval and analysis. 3. **Best-in-Class Deterministic Workflow Engine:** Ensures consistent and reliable execution of business processes. 4. **Enterprise-Grade Commerce Data Platform:** Provides a centralized source of truth for all commerce-related data. While we leverage the latest advancements in **Large Language Models (LLMs)** and **Vector Embeddings**, these constitute only 20-30% of our total solution. Scaling AI agents to handle thousands of monthly tickets requires a robust, purpose-built infrastructure. StateSet delivers this, including: * **Multi-Modal Capabilities:** Handles text, images, and other data formats. * **Advanced Intent Detection:** Accurately interprets user requests. * **Response Filtering:** Ensures relevant and appropriate responses. * **Memory-Based Personalization:** Provides tailored responses based on past interactions. * **Response Scheduling:** Delivers messages at the optimal time. * **Example Ticket Handling:** Uses past successful interactions as templates. * **Hundreds of Integrations Across the DTC Stack:** Enables seamless data exchange with existing systems. * **Comprehensive Response Tracing:** Provides visibility into every decision and action taken by the AI agents. > **We are not just implementing AI; we are perfecting it through continuous refinement and collaboration with our customers.** ## The StateSet Master Plan: Building the Autonomous Commerce OS Our vision is to create the **autonomous commerce operating system**, powered by application-specific AI agents. Since 2019, we have been developing: * **Infrastructure Automation:** Streamlines the deployment and management of our AI systems. * **Event-Driven Architecture:** Ensures that all components react in real-time to changes in the system. * **AI Platform Organization:** Provides a structured and efficient framework for AI agent development. This approach enables us to rapidly integrate the latest model advancements, future-proofing the StateSet platform. ```mermaid theme={null} graph LR A[Client Interaction] --> B(StateSet AI Agents); B --> C{StateSet Platform}; C --> D[External Services]; ``` > This diagram shows how an interaction with a client triggers our AI agents. The agents then use the Stateset Platform to interact with the external services. ## Product Roadmap: Shaping the Future of Commerce Our product roadmap is designed to deliver a comprehensive platform for autonomous commerce: 1. **Advanced Infrastructure on StateSet Cloud**: Core infrastructure automation for fast AI deployment, including fine-tuning, versioning, CI/CD, and API access. 2. **Next-Gen Web Services**: Command Query Based Rust web services that our AI agents use to drive commerce operations. 3. **Agent Orchestration Framework**: Enables multiple AI agents to collaborate on complex problems across sales, marketing, operations, and finance. 4. **Generative User Interfaces**: Conversational UIs monitored by AI agents and humans, leveraging our Query Engine for enhanced customer experiences. ## What Makes StateSet Different? We are not building another Business Process Management (BPM) tool, nor are we creating another user interface for CRUD operations. Instead, we are constructing the infrastructure that allows autonomous AI agents to operate at scale and with precision. This is not software 1.0 or software-as-a-service 2.0; this is the next generation of **business outcomes as a service**. ## The Future is Here: AI-Powered Autonomy Say goodbye to software seat licenses and manual database updates. Welcome to the era of AI-powered outcomes and true autonomy in business operations. > **Soon, you may even need to pay commissions to your AI counterparts.** At StateSet, we're leading the AI agent revolution. Join us as we reshape the landscape of commerce and redefine the potential of business software. # ReasonCX Source: https://docs.stateset.com/response-api-reference/reason Discover how ReasonCX combines advanced AI reasoning and source-grounded platforms to transform commerce analytics. # ReasonCX: The Next Generation of AI-Powered Commerce Analytics The AI landscape is undergoing a revolution, with the emergence of breakthrough **AI Agents** that are fundamentally changing how businesses operate. These agents don't just respond faster; they understand context, automate complex workflows, and deliver personalized responses with precision. The ROI we're witnessing across our customers is truly remarkable. ## The Rise of AI Agents with Advanced Reasoning We are now seeing the next generation of AI Agents emerge: those with **advanced reasoning capabilities** powered by models like **OpenAI’s o1**. These models don't just generate responses—they think deeply, uncovering insights that would have taken teams weeks to discover manually. This leap in reasoning allows us to surface critical "unknown unknowns" hidden within your data—often the key differentiator between good and exceptional business performance. ## Source-Grounded AI Platforms: Redefining User Interaction Simultaneously, **source-grounded AI platforms**, such as **NotebookLM**, are transforming how users interact with AI. These applications offer unprecedented flexibility, enabling you to: * Manipulate source inputs * Experiment with outputs * Seamlessly switch between different modalities ## ReasonCX: Transforming Commerce Analytics The convergence of these **advanced reasoning models** with **multimodal, source-grounded applications** marks a massive leap forward. That’s why we're excited to introduce **ReasonCX**: an AI agent that harnesses these cutting-edge capabilities to transform commerce analytics. **ReasonCX** integrates seamlessly with your storefront and helpdesk, creating a new system of intelligence that turns your commerce data into real-time strategic insights. Think of it as an AI-powered commerce analyst that never sleeps, continuously analyzing your data to surface opportunities and prevent problems before they occur. ## Exceptional Insights Delivered by ReasonCX We've already seen ReasonCX deliver exceptional insights across multiple data streams, providing: * ✅ **Real-time detection** of customer friction points before they impact revenue * ✅ **Deep analysis** of product performance and promotion effectiveness * ✅ **Sophisticated anomaly detection** with automated action recommendations * ✅ **Comprehensive analysis** of cancellation patterns and retention opportunities * ✅ **Predictive modeling** for inventory and support team resource allocation > We are witnessing something even more powerful: AI that not only processes data but also reasons through it. ## ReasonCX: Your Edge During High-Stakes Periods What makes **ReasonCX** particularly valuable during high-stakes periods like **BFCM** is its ability to process massive amounts of commerce data in real time. Plus, with our integration of **E2B's interactive visualization capabilities**, you can generate stunning graphs and shareable PDF reports with a single click. ## Ready to Elevate Your Performance? Ready to elevate your holiday season performance? DM me for early access and see how ReasonCX can transform your commerce intelligence. # ResponseCX Quickstart Source: https://docs.stateset.com/response-api-reference/response-quickstart Deploy your first ResponseCX agent and send a response in minutes. # ResponseCX Quickstart Get from zero to a working ResponseCX agent using the SDK. ## Prerequisites * StateSet account with ResponseCX enabled * API key from your dashboard * Node.js 16+ Set your key in the environment: ```bash theme={null} export STATESET_API_KEY=sk_test_your_actual_key_here ``` ## 1. Install the SDK ```bash theme={null} npm install stateset-node dotenv winston ``` ## 2. Initialize a client ```javascript theme={null} import { StateSetClient } from 'stateset-node'; import dotenv from 'dotenv'; import winston from 'winston'; dotenv.config(); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', transports: [new winston.transports.Console()] }); const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY }); ``` ## 3. Create an agent ```javascript theme={null} async function createAgent() { try { const agent = await client.agents.create({ name: 'My Agent', description: 'My first ResponseCX agent' }); logger.info('Agent created', { agentId: agent.id }); return agent; } catch (error) { logger.error('Agent creation failed', { message: error.message, requestId: error.request_id }); throw error; } } ``` ## 4. Add a rule (optional) ```javascript theme={null} async function createRule(agentId) { try { const rule = await client.rules.create({ name: 'Always Respond Politely', description: 'Be friendly and concise', agent_id: agentId }); logger.info('Rule created', { ruleId: rule.id }); return rule; } catch (error) { logger.error('Rule creation failed', { message: error.message }); throw error; } } ``` ## 5. Add an attribute (optional) ```javascript theme={null} async function createAttribute(agentId) { return client.attributes.create({ name: 'Confident', description: 'Authoritative but approachable', value: 15, agent_id: agentId }); } ``` ## 6. Create your first response ```javascript theme={null} async function createResponse() { const response = await client.response.create({ ticket_url: 'https://yourapp.com/tickets/123', channel: 'Email', customer_message: 'Explain the importance of fast language models', agent_response: 'Fast models reduce latency, enable real-time UX, and lower costs.' }); logger.info('Response created', { responseId: response.id }); return response; } ``` ## Next steps * Manage agents: [Agents Quickstart](/guides/agents-quickstart) * Add rules: [Rules Quickstart](/guides/rules-quickstart) * Add attributes and examples: [Attributes Quickstart](/guides/attributes-quickstart), [Examples Quickstart](/guides/examples-quickstart) # Create Response Source: https://docs.stateset.com/response-api-reference/responses/create POST https://api.stateset.com/v1/response This endpoint creates a new response from the agent ### Body This is the unique identifier for the response This is the unique identifier for the ticket url. This is the unique identifier for the channel This is the customer message. This is the agent response. This is the reported condition of the return. This is whethere the message added the agent\_take\_over tag. This is whether the request was served by an agent. This is the org\_id of the response. This is the created date of the response. This is the ticket id of the response. This is the function call of the response. This is the workflow id of the response. ### Response The ID provided in the data tab may be used to identify the return The ticket url provided in the data tab may be used to identify the return The channel provided in the data tab may be used to identify the return The customer message provided in the data tab may be used to identify the return The agent response provided in the data tab may be used to identify the return The rating provided in the data tab may be used to identify the return The agent take over provided in the data tab may be used to identify the return The served by agent provided in the data tab may be used to identify the return The org id provided in the data tab may be used to identify the return The created date provided in the data tab may be used to identify the return The ticket id provided in the data tab may be used to identify the return The function call provided in the data tab may be used to identify the return The workflow id provided in the data tab may be used to identify the return ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/response' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ticket_url': 'https://api.stateset.com/v1/ticket', 'channel': 'Email', 'customer_message': 'I would like to cancel my order', 'agent_response': 'Your order has been cancelled. Thank you!', 'rating': '5', 'agent_take_over': false, 'served_by_agent': true, 'org_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'created_date': '2023-06-28T19:34:59.189838+00:00', 'ticket_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'function_call': 'cancel-order', 'workflow_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }' ``` ```graphQL GraphQL theme={null} mutation InsertNewResponse( $response: responses_insert_input! ) { insert_responses ( objects: [$response] ) { returning { id ticket_url channel customer_message agent_response rating agent_take_over served_by_agent org_id created_date ticket_id function_call workflow_id } } }`; ``` ```js Node.js theme={null} const response = await stateset.response.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ticket_url': 'https://api.stateset.com/v1/ticket', 'channel': 'Email', 'customer_message': 'I would like to cancel my order', 'agent_response': 'Your order has been cancelled. Thank you!', 'rating': '5', 'agent_take_over': false, 'served_by_agent': true, 'org_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'created_date': '2023-06-28T19:34:59.189838+00:00', 'ticket_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'function_call': 'cancel-order', 'workflow_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```python Python theme={null} ``` ```python Python theme={null} response = stateset.response.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ticket_url': 'https://api.stateset.com/v1/ticket', 'channel': 'Email', 'customer_message': 'I would like to cancel my order', 'agent_response': 'Your order has been cancelled. Thank you!', 'rating': '5', 'agent_take_over': false, 'served_by_agent': true, 'org_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'created_date': '2023-06-28T19:34:59.189838+00:00', 'ticket_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'function_call': 'cancel-order', 'workflow_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```ruby Ruby theme={null} ``` ```ruby Ruby theme={null} response = stateset.response.create({ 'id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'ticket_url': 'https://api.stateset.com/v1/ticket', 'channel': 'Email', 'customer_message': 'I would like to cancel my order', 'agent_response': 'Your order has been cancelled. Thank you!', 'rating': '5', 'agent_take_over': false, 'served_by_agent': true, 'org_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'created_date': '2023-06-28T19:34:59.189838+00:00', 'ticket_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30', 'function_call': 'cancel-order', 'workflow_id': '0901f083-aa1c-43c5-af5c-0a9d2fc64e30' }) ``` ```json Response theme={null} { "response": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "ticket_url": "https://api.stateset.com/v1/ticket", "channel": "Email", "customer_message": "I would like to cancel my order", "agent_response": "Your order has been cancelled. Thank you!", "rating": "5", "agent_take_over": false, "served_by_agent": true, "org_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "ticket_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "function_call": "cancel-order", "workflow_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, ] } ``` # Retrieve Response Source: https://docs.stateset.com/response-api-reference/responses/get GET https://api.stateset.com/v1/response/:id This endpoint retrieves a response from the agent. ### Body This is the id of the response. ### Response The ID provided in the data tab may be used to identify the return The ticket url provided in the data tab may be used to identify the return The channel provided in the data tab may be used to identify the return The customer message provided in the data tab may be used to identify the return The agent response provided in the data tab may be used to identify the return The rating provided in the data tab may be used to identify the return The agent take over provided in the data tab may be used to identify the return The served by agent provided in the data tab may be used to identify the return The org id provided in the data tab may be used to identify the return The created date provided in the data tab may be used to identify the return The ticket id provided in the data tab may be used to identify the return The function call provided in the data tab may be used to identify the return The workflow id provided in the data tab may be used to identify the return ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/response/retrieve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "res_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```json Response theme={null} { "response": [ { "id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "ticket_url": "https://api.stateset.com/v1/ticket", "channel": "Email", "customer_message": "I would like to cancel my order", "agent_response": "Your order has been cancelled. Thank you!", "rating": "5", "agent_take_over": false, "served_by_agent": true, "org_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "created_date": "2023-06-28T19:34:59.189838+00:00", "ticket_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30", "function_call": "cancel-order", "workflow_id": "0901f083-aa1c-43c5-af5c-0a9d2fc64e30" }, ] } ``` # Rules Source: https://docs.stateset.com/response-api-reference/rules Overview of rules resources. # Rules Use the rules endpoints to manage rules. * [List](/response-api-reference/rules/list) * [Get](/response-api-reference/rules/get) * [Create](/response-api-reference/rules/create) * [Update](/response-api-reference/rules/update) * [Delete](/response-api-reference/rules/delete) # Create Rule Source: https://docs.stateset.com/response-api-reference/rules/create POST https://api.stateset.com/v1/rules This endpoint creates a new rule ### Body This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ### Response This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/rules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Rule", "name": "Rule 1", "description": "This is the rule", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Rule", "name": "Rule 1", "description": "This is the rule", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Delete Rule Source: https://docs.stateset.com/response-api-reference/rules/delete DELETE https://api.stateset.com/v1/rules This endpoint deletes a rule ### Body This is the id of the rule. ### Response This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/rules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00" } ``` # Get Rule Source: https://docs.stateset.com/response-api-reference/rules/get GET https://api.stateset.com/v1/rules This endpoint gets a rule ### Body This is the id of the rule. ### Response This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/rules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Rule", "name": "Rule 1", "description": "This is the rule", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # List Rules Source: https://docs.stateset.com/response-api-reference/rules/list GET https://api.stateset.com/v1/rules This endpoint gets a rule ### Body ### Response This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/rules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Rule", "name": "Rule 1", "description": "This is the rule", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Update Rule Source: https://docs.stateset.com/response-api-reference/rules/update PUT https://api.stateset.com/v1/rules This endpoint updates a rule ### Body This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ### Response This is the id of the rule. This is the type of the rule. This is the name of the rule. This is the description of the rule. This is the created\_at of the rule. This is the updated\_at of the rule. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/rules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Rule", "name": "Rule 1", "description": "This is the rule", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "type": "System Rule", "name": "Rule 1", "description": "This is the rule", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Create Schedule Source: https://docs.stateset.com/response-api-reference/schedules/create POST https://api.stateset.com/v1/schedules This endpoint creates a new schedule ### Body This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ### Response This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/schedules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "schedule_type": "System Schedule", "schedule_name": "eMail Schedule", "description": "Always respond to eMails after waiting 5 minutes", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "schedule_type": "System Schedule", "schedule_name": "eMail Schedule", "description": "Always respond to eMails after waiting 5 minutes", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Delete Schedule Source: https://docs.stateset.com/response-api-reference/schedules/delete DELETE https://api.stateset.com/v1/schedules This endpoint deletes a schedule ### Body This is the id of the schedule. ### Response This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/schedules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00" } ``` # Get Schedule Source: https://docs.stateset.com/response-api-reference/schedules/get GET https://api.stateset.com/v1/schedules This endpoint gets a schedule ### Body This is the id of the schedule. ### Response This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/schedules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "schedule_type": "System Schedule", "schedule_name": "eMail Schedule", "description": "Always respond to eMails after waiting 5 minutes", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # List Schedules Source: https://docs.stateset.com/response-api-reference/schedules/list GET https://api.stateset.com/v1/schedules This endpoint gets a schedule ### Body ### Response This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/schedules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "schedule_type": "System Schedule", "schedule_name": "eMail Schedule", "description": "Always respond to eMails after waiting 5 minutes", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Update Schedule Source: https://docs.stateset.com/response-api-reference/schedules/update PUT https://api.stateset.com/v1/schedules This endpoint updates a schedule. ### Body This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ### Response This is the id of the schedule. This is the type of the schedule. This is the name of the schedule. This is the description of the schedule. This is the created\_at of the schedule. This is the updated\_at of the schedule. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/schedules' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "schedule_type": "System Schedule", "schedule_name": "eMail Schedule", "description": "Always respond to eMails after waiting 5 minutes", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" }' ``` ```json Response theme={null} { "id": "2438cf38-4004-41d3-8c90-131735ff7d00", "schedule_type": "System Schedule", "schedule_name": "eMail Schedule", "description": "Always respond to eMails after waiting 5 minutes", "created_at": "2023-11-28T00:00:00.000000Z", "updated_at": "2023-11-28T00:00:00.000000Z" } ``` # Create Session Source: https://docs.stateset.com/response-api-reference/sessions/create POST https://api.stateset.com/v1/session This endpoint creates a new session ### Body This is the ID of the session to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/session' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```graphQL GraphQL theme={null} mutation addSession( $session: session_insert_input! ) { insert_session(objects: [$session]) { returning { id name uuid user_id } } } ``` ```javascript Node.js theme={null} const created = await stateset.session.create({ id: "", }); ``` ```json Response theme={null} { "data": { "insert_session": { "returning": [ { "id": "", "name": "", "uuid": "", "user_id": "" } ] } } } ``` # Delete Session Source: https://docs.stateset.com/response-api-reference/sessions/delete DELETE https://api.stateset.com/v1/session This endpoint deletes an existing session. ### Body The ID provided in the data tab may be used to identify the session ### Response The ID provided in the data tab may be used to identify the session The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/session' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteSession ($id: String!) { delete_session(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const session = await stateset.session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} session = stateset.session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} session, err := stateset.Session.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case session = stateset.session.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const session = await stateset.session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} session = Stateset::Return.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $session = $stateset->session->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/session HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "session", "deleted": true } ``` *** title: "Delete Session" api: "DELETE [https://api.stateset.com/v1/session](https://api.stateset.com/v1/session)" description: "This endpoint deletes an existing session." --------------------------------------------------------- ### Body The ID provided in the data tab may be used to identify the session ### Response The ID provided in the data tab may be used to identify the session The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/session' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE" }' ``` ```graphQL GraphQL theme={null} mutation deleteSession ($id: String!) { delete_session(where: {id: {_eq: $id}}) { affected_rows } } ``` ```js Node.js theme={null} const session = await stateset.session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} session = stateset.session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Go theme={null} session, err := stateset.Session.Del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ) ``` ```java Java theme={null} Case session = stateset.session.del( "rt_1NXWPnCo6bFb1KQto6C8OWvE" ); ``` ```js Javascript theme={null} const session = await stateset.session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```ruby Ruby theme={null} session = Stateset::Session.del({ 'rt_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```php PHP theme={null} $session = $stateset->session->del( 'rt_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} DELETE /v1/session HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "id": "ct_1NXWPnCo6bFb1KQto6C8OWvE", "object": "session", "deleted": true } ``` # Get Session Source: https://docs.stateset.com/response-api-reference/sessions/get GET https://api.stateset.com/v1/session This endpoint gets a session. ### Body This is the id of the session. ### Response This is the id of the session This is the name of the session This is the uuid of the session This is the user\_id of the session ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/session' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", }' ``` ```graphQL GraphQL theme={null} query MySession { session { id created_at name system_prompt } } ``` ```js Node.js theme={null} const session = await stateset.session.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} session = stateset.session.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} session, err := stateset.Session.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} session = Stateset::Session.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Session session = Stateset.Session.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Session session = Stateset.Session.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $session = Stateset\Session::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/session HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "created_at": "2021-01-01T00:00:00.000000Z", "name": "My Session", "system_prompt": "You are a helpful assistant.", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", } } } ``` # List Sessions Source: https://docs.stateset.com/response-api-reference/sessions/list GET https://api.stateset.com/v1/sessions This endpoint gets a sessions. ### Body ### Response This is the id of the session This is the name of the session This is the uuid of the session This is the user\_id of the session ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/sessions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ ``` ```graphQL GraphQL theme={null} query MySession { session { id created_at name system_prompt user_id } } ``` ```js Node.js theme={null} const sessions = await stateset.sessions.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }); ``` ```py Python theme={null} sessions = stateset.sessions.retrieve({ 'ct_1NXWPnCo6bFb1KQto6C8OWvE' }) ``` ```go Golang theme={null} sessions, err := stateset.Sessions.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```ruby Ruby theme={null} sessions = Stateset::Sessions.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ) ``` ```java Java theme={null} Session session = Stateset.Sessions.retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```csharp C# theme={null} Session session = Stateset.Sessions.Retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```php PHP theme={null} $sessions = Stateset\Sessions::retrieve( 'ct_1NXWPnCo6bFb1KQto6C8OWvE' ); ``` ```http HTTP theme={null} GET /v1/sessions HTTP/1.1 Host: api.stateset.com Content-Type: application/json ``` ```json Response theme={null} { "data": { "message": { "id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", "created_at": "2021-01-01T00:00:00.000000Z", "name": "My Session", "system_prompt": "You are a helpful assistant.", "user_id": "rt_1NXWPnCo6bFb1KQto6C8OWvE", } } } ``` # Update Session Source: https://docs.stateset.com/response-api-reference/sessions/update PUT https://api.stateset.com/v1/session This endpoint updates a session ### Body This is the ID of the session to be updated. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/session' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` ```javascript Node.js theme={null} const updated = await stateset.session.update({ id: "", }); ``` ```json Response theme={null} { "data": { "update_session": { "returning": [ { "id": "", "name": "", "uuid": "", "user_id": "" } ] } } } ``` # Settings Source: https://docs.stateset.com/response-api-reference/settings Overview of settings resources. # Settings Use the settings endpoints to manage settings. * [List](/response-api-reference/settings/list) * [Get](/response-api-reference/settings/get) * [Create](/response-api-reference/settings/create) * [Update](/response-api-reference/settings/update) * [Delete](/response-api-reference/settings/delete) # Create Settings Source: https://docs.stateset.com/response-api-reference/settings/create POST https://api.stateset.com/v1/settings This endpoint creates a new settings ### Body The unique identifier for the agent whose settings are being updated. The object containing all the settings that you want to update for the agent. ### Response The unique identifier of the agent whose settings were updated. A test field to verify the update operation. Indicates whether the agent take over tag is enabled. Indicates whether the agent should skip certain emails. An array of tags that the agent should skip. The name of the model used by the agent. The type of model used by the agent. The provider of the model used by the agent. The temperature setting for the model. The maximum number of tokens allowed in the agent's responses. An array of subjects that the agent should skip. Keywords indicating out-of-office status that the agent should recognize. An array of channels that the agent should skip. Indicates whether the agent should skip Instagram messages. An array of emails associated with the agent. The time threshold for the agent's operations, in minutes. The user ID of the person assigned to the agent. An array of intents that the agent is allowed to process. Keywords related to health concerns that the agent should recognize. Phrases that trigger the agent to take over a conversation. The team ID for escalations. The name of the tag used for escalations. The email used by the StateSet response system integrated with Gorgias. The user ID in the StateSet response system integrated with Gorgias. The name of the response used by StateSet. The name that appears in the "From" field of the agent's communications. The address that appears in the "From" field of the agent's communications. The analytics platform used by the agent. The agent's average response time, in seconds. The frequency of backups for the agent's data. The retention period for the agent's backups. Indicates whether the agent is compliant with CCPA regulations. The timestamp when the agent was created. The CRM system used by the agent. The agent's customer satisfaction score. The target customer satisfaction score for the agent. The level of encryption used by the agent. The data retention period for the agent's data. The ID of the fallback agent in case of issues. Indicates whether the agent is GDPR compliant. The rate at which the agent resolves issues on first contact. The average handle time for the agent's tasks, in seconds. Indicates whether the agent should skip emails based on intent. A list of IP addresses that are whitelisted for the agent. The language preferences set for the agent. The maximum duration of a conversation handled by the agent, in minutes. The organization ID associated with the agent. Indicates whether the agent is PCI DSS compliant. Indicates whether the agent has a profanity filter enabled. The resolution rate for the agent's tasks. The target resolution rate for the agent's tasks. The threshold for the agent's response time, in seconds. The threshold for the agent's sentiment analysis. The ticketing system used by the agent. The data sources used for training the agent. The frequency of the agent's training sessions. The last date the agent's training was updated. Indicates whether two-factor authentication is required for the agent. The timestamp when the agent's settings were last updated. ### Request Example ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/graphql' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "query": "mutation UpdateAgentSettings($id: Int!, $agent_settings: agent_settings_set_input!) { update_agent_settings(where: { id: { _eq: $id } }, _set: $agent_settings) { returning { id test agent_take_over_tag skip_emails skip_tags model_name model_type model_provider temperature max_tokens skip_subjects out_of_office_keywords skip_channels skip_instagram_messages agent_emails time_threshold assignee_user_id allowed_intents health_concern_keywords agent_takeover_phrases escalation_team_id escalation_tag_name stateset_response_gorgias_email stateset_response_g ``` # Delete Settings Source: https://docs.stateset.com/response-api-reference/settings/delete DELETE https://api.stateset.com/v1/settings/:id This endpoint deletes a settings ### Body The unique identifier for the agent whose settings are being updated. The object containing all the settings that you want to update for the agent. ### Response The unique identifier of the agent whose settings were updated. A test field to verify the update operation. Indicates whether the agent take over tag is enabled. Indicates whether the agent should skip certain emails. An array of tags that the agent should skip. The name of the model used by the agent. The type of model used by the agent. The provider of the model used by the agent. The temperature setting for the model. The maximum number of tokens allowed in the agent's responses. An array of subjects that the agent should skip. Keywords indicating out-of-office status that the agent should recognize. An array of channels that the agent should skip. Indicates whether the agent should skip Instagram messages. An array of emails associated with the agent. The time threshold for the agent's operations, in minutes. The user ID of the person assigned to the agent. An array of intents that the agent is allowed to process. Keywords related to health concerns that the agent should recognize. Phrases that trigger the agent to take over a conversation. The team ID for escalations. The name of the tag used for escalations. The email used by the StateSet response system integrated with Gorgias. The user ID in the StateSet response system integrated with Gorgias. The name of the response used by StateSet. The name that appears in the "From" field of the agent's communications. The address that appears in the "From" field of the agent's communications. The analytics platform used by the agent. The agent's average response time, in seconds. The frequency of backups for the agent's data. The retention period for the agent's backups. Indicates whether the agent is compliant with CCPA regulations. The timestamp when the agent was created. The CRM system used by the agent. The agent's customer satisfaction score. The target customer satisfaction score for the agent. The level of encryption used by the agent. The data retention period for the agent's data. The ID of the fallback agent in case of issues. Indicates whether the agent is GDPR compliant. The rate at which the agent resolves issues on first contact. The average handle time for the agent's tasks, in seconds. Indicates whether the agent should skip emails based on intent. A list of IP addresses that are whitelisted for the agent. The language preferences set for the agent. The maximum duration of a conversation handled by the agent, in minutes. The organization ID associated with the agent. Indicates whether the agent is PCI DSS compliant. Indicates whether the agent has a profanity filter enabled. The resolution rate for the agent's tasks. The target resolution rate for the agent's tasks. The threshold for the agent's response time, in seconds. The threshold for the agent's sentiment analysis. The ticketing system used by the agent. The data sources used for training the agent. The frequency of the agent's training sessions. The last date the agent's training was updated. Indicates whether two-factor authentication is required for the agent. The timestamp when the agent's settings were last updated. ### Request Example ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/graphql' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "query": "mutation UpdateAgentSettings($id: Int!, $agent_settings: agent_settings_set_input!) { update_agent_settings(where: { id: { _eq: $id } }, _set: $agent_settings) { returning { id test agent_take_over_tag skip_emails skip_tags model_name model_type model_provider temperature max_tokens skip_subjects out_of_office_keywords skip_channels skip_instagram_messages agent_emails time_threshold assignee_user_id allowed_intents health_concern_keywords agent_takeover_phrases escalation_team_id escalation_tag_name stateset_response_gorgias_email stateset_response_g ``` # Get Settings Source: https://docs.stateset.com/response-api-reference/settings/get GET https://api.stateset.com/v1/settings/:id This endpoint retrieves the settings for a specific agent by their unique identifier. ### Parameters The unique identifier of the agent whose settings are being retrieved. ### Response Fields The unique identifier of the agent. A test field for the agent's settings. Indicates whether the agent take over tag is enabled. Indicates whether the agent should skip certain emails. An array of tags that the agent should skip. The name of the model used by the agent. The type of model used by the agent. The provider of the model used by the agent. The temperature setting for the model. The maximum number of tokens allowed in the agent's responses. An array of subjects that the agent should skip. Keywords indicating out-of-office status that the agent should recognize. An array of channels that the agent should skip. Indicates whether the agent should skip Instagram messages. An array of emails associated with the agent. The time threshold for the agent's operations, in minutes. The user ID of the person assigned to the agent. An array of intents that the agent is allowed to process. Keywords related to health concerns that the agent should recognize. Phrases that trigger the agent to take over a conversation. The team ID for escalations. The name of the tag used for escalations. The email used by the StateSet response system integrated with Gorgias. The user ID in the StateSet response system integrated with Gorgias. The name of the response used by StateSet. The name that appears in the "From" field of the agent's communications. The address that appears in the "From" field of the agent's communications. The analytics platform used by the agent. The agent's average response time, in seconds. The frequency of backups for the agent's data. The retention period for the agent's backups. Indicates whether the agent is compliant with CCPA regulations. The timestamp when the agent was created. The CRM system used by the agent. The agent's customer satisfaction score. The target customer satisfaction score for the agent. The level of encryption used by the agent. The data retention period for the agent's data. The ID of the fallback agent in case of issues. Indicates whether the agent is GDPR compliant. The rate at which the agent resolves issues on first contact. The average handle time for the agent's tasks, in seconds. Indicates whether the agent should skip emails based on intent. A list of IP addresses that are whitelisted for the agent. The language preferences set for the agent. The maximum duration of a conversation handled by the agent, in minutes. The organization ID associated with the agent. Indicates whether the agent is PCI DSS compliant. Indicates whether the agent has a profanity filter enabled. The resolution rate for the agent's tasks. The target resolution rate for the agent's tasks. The threshold for the agent's response time, in seconds. The threshold for the agent's sentiment analysis. The ticketing system used by the agent. The data sources used for training the agent. The frequency of the agent's training sessions. The last date the agent's training was updated. Indicates whether two-factor authentication is required for the agent. The timestamp when the agent's settings were last updated. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/agent_settings/123' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' ``` ```json theme={null} { "id": 123, "test": "Test field value", "agent_take_over_tag": true, "skip_emails": false, "skip_tags": ["spam", "promotions"], "model_name": "StateSet AI Model", "model_type": "NLP", "model_provider": "StateSet AI", "temperature": 0.7, "max_tokens": 2048, "skip_subjects": ["marketing", "ads"], "out_of_office_keywords": ["out of office", "vacation"], "skip_channels": ["Facebook", "Twitter"], "skip_instagram_messages": true, "agent_emails": ["agent@example.com"], "time_threshold": 30, "assignee_user_id": 456, "allowed_intents": ["order_status", "cancellation"], "health_concern_keywords": ["allergy", "side effect"], "agent_takeover_phrases": ["Let me take over", "I got this"], "escalation_team_id": 789, "escalation_tag_name": "urgent", "stateset_response_gorgias_email": "gorgias@example.com", "stateset_response_gorgias_user_id": "gorgias_user_123", } ``` # List Settings Source: https://docs.stateset.com/response-api-reference/settings/list GET https://api.stateset.com/v1/settings This endpoint retrieves the settings for a specific agent by their unique identifier. ### Parameters The unique identifier of the agent whose settings are being retrieved. ### Response Fields The unique identifier of the agent. A test field for the agent's settings. Indicates whether the agent take over tag is enabled. Indicates whether the agent should skip certain emails. An array of tags that the agent should skip. The name of the model used by the agent. The type of model used by the agent. The provider of the model used by the agent. The temperature setting for the model. The maximum number of tokens allowed in the agent's responses. An array of subjects that the agent should skip. Keywords indicating out-of-office status that the agent should recognize. An array of channels that the agent should skip. Indicates whether the agent should skip Instagram messages. An array of emails associated with the agent. The time threshold for the agent's operations, in minutes. The user ID of the person assigned to the agent. An array of intents that the agent is allowed to process. Keywords related to health concerns that the agent should recognize. Phrases that trigger the agent to take over a conversation. The team ID for escalations. The name of the tag used for escalations. The email used by the StateSet response system integrated with Gorgias. The user ID in the StateSet response system integrated with Gorgias. The name of the response used by StateSet. The name that appears in the "From" field of the agent's communications. The address that appears in the "From" field of the agent's communications. The analytics platform used by the agent. The agent's average response time, in seconds. The frequency of backups for the agent's data. The retention period for the agent's backups. Indicates whether the agent is compliant with CCPA regulations. The timestamp when the agent was created. The CRM system used by the agent. The agent's customer satisfaction score. The target customer satisfaction score for the agent. The level of encryption used by the agent. The data retention period for the agent's data. The ID of the fallback agent in case of issues. Indicates whether the agent is GDPR compliant. The rate at which the agent resolves issues on first contact. The average handle time for the agent's tasks, in seconds. Indicates whether the agent should skip emails based on intent. A list of IP addresses that are whitelisted for the agent. The language preferences set for the agent. The maximum duration of a conversation handled by the agent, in minutes. The organization ID associated with the agent. Indicates whether the agent is PCI DSS compliant. Indicates whether the agent has a profanity filter enabled. The resolution rate for the agent's tasks. The target resolution rate for the agent's tasks. The threshold for the agent's response time, in seconds. The threshold for the agent's sentiment analysis. The ticketing system used by the agent. The data sources used for training the agent. The frequency of the agent's training sessions. The last date the agent's training was updated. Indicates whether two-factor authentication is required for the agent. The timestamp when the agent's settings were last updated. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/agent_settings/123' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' ``` ```json theme={null} { "id": 123, "test": "Test field value", "agent_take_over_tag": true, "skip_emails": false, "skip_tags": ["spam", "promotions"], "model_name": "StateSet AI Model", "model_type": "NLP", "model_provider": "StateSet AI", "temperature": 0.7, "max_tokens": 2048, "skip_subjects": ["marketing", "ads"], "out_of_office_keywords": ["out of office", "vacation"], "skip_channels": ["Facebook", "Twitter"], "skip_instagram_messages": true, "agent_emails": ["agent@example.com"], "time_threshold": 30, "assignee_user_id": 456, "allowed_intents": ["order_status", "cancellation"], "health_concern_keywords": ["allergy", "side effect"], "agent_takeover_phrases": ["Let me take over", "I got this"], "escalation_team_id": 789, "escalation_tag_name": "urgent", "stateset_response_gorgias_email": "gorgias@example.com", "stateset_response_gorgias_user_id": "gorgias_user_123", } ``` # Update Settings Source: https://docs.stateset.com/response-api-reference/settings/update PUT https://api.stateset.com/v1/settings/:id This endpoint updates a settings ### Body The unique identifier for the agent whose settings are being updated. The object containing all the settings that you want to update for the agent. ### Response The unique identifier of the agent whose settings were updated. A test field to verify the update operation. Indicates whether the agent take over tag is enabled. Indicates whether the agent should skip certain emails. An array of tags that the agent should skip. The name of the model used by the agent. The type of model used by the agent. The provider of the model used by the agent. The temperature setting for the model. The maximum number of tokens allowed in the agent's responses. An array of subjects that the agent should skip. Keywords indicating out-of-office status that the agent should recognize. An array of channels that the agent should skip. Indicates whether the agent should skip Instagram messages. An array of emails associated with the agent. The time threshold for the agent's operations, in minutes. The user ID of the person assigned to the agent. An array of intents that the agent is allowed to process. Keywords related to health concerns that the agent should recognize. Phrases that trigger the agent to take over a conversation. The team ID for escalations. The name of the tag used for escalations. The email used by the StateSet response system integrated with Gorgias. The user ID in the StateSet response system integrated with Gorgias. The name of the response used by StateSet. The name that appears in the "From" field of the agent's communications. The address that appears in the "From" field of the agent's communications. The analytics platform used by the agent. The agent's average response time, in seconds. The frequency of backups for the agent's data. The retention period for the agent's backups. Indicates whether the agent is compliant with CCPA regulations. The timestamp when the agent was created. The CRM system used by the agent. The agent's customer satisfaction score. The target customer satisfaction score for the agent. The level of encryption used by the agent. The data retention period for the agent's data. The ID of the fallback agent in case of issues. Indicates whether the agent is GDPR compliant. The rate at which the agent resolves issues on first contact. The average handle time for the agent's tasks, in seconds. Indicates whether the agent should skip emails based on intent. A list of IP addresses that are whitelisted for the agent. The language preferences set for the agent. The maximum duration of a conversation handled by the agent, in minutes. The organization ID associated with the agent. Indicates whether the agent is PCI DSS compliant. Indicates whether the agent has a profanity filter enabled. The resolution rate for the agent's tasks. The target resolution rate for the agent's tasks. The threshold for the agent's response time, in seconds. The threshold for the agent's sentiment analysis. The ticketing system used by the agent. The data sources used for training the agent. The frequency of the agent's training sessions. The last date the agent's training was updated. Indicates whether two-factor authentication is required for the agent. The timestamp when the agent's settings were last updated. ### Request Example ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/graphql' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "query": "mutation UpdateAgentSettings($id: Int!, $agent_settings: agent_settings_set_input!) { update_agent_settings(where: { id: { _eq: $id } }, _set: $agent_settings) { returning { id test agent_take_over_tag skip_emails skip_tags model_name model_type model_provider temperature max_tokens skip_subjects out_of_office_keywords skip_channels skip_instagram_messages agent_emails time_threshold assignee_user_id allowed_intents health_concern_keywords agent_takeover_phrases escalation_team_id escalation_tag_name stateset_response_gorgias_email stateset_response_g ``` # Users Source: https://docs.stateset.com/response-api-reference/users Overview of user resources. # Users Use the users endpoints to manage users. * [List](/response-api-reference/users/list) * [Get](/response-api-reference/users/get) * [Create](/response-api-reference/users/create) * [Update](/response-api-reference/users/update) * [Delete](/response-api-reference/users/delete) # Create User Source: https://docs.stateset.com/response-api-reference/users/create POST https://api.stateset.com/v1/users This endpoint creates a new user ### Body This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ### Response This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.com/v1/users' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "8" }' ``` ```json Response theme={null} { "id": "8" } ``` # Delete User Source: https://docs.stateset.com/response-api-reference/users/delete DELETE https://api.stateset.com/v1/users/:id This endpoint deletes an existing user. ### Body The ID of the user to delete. ### Response The ID provided in the data tab may be used to identify the return The object type Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request DELETE 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id: "1234", }' ``` ````graphQL GraphQL theme={null} mutation { deleteUser( input: { id: "1234" } ) { success } } ```javascript Node.js var deleted = await stateset.users.del({ id: "1234" }); ```` ```python Python theme={null} deleted = stateset.users.del({ "id": "1234" }) ``` ```ruby Ruby theme={null} deleted = Stateset::Users.del({ "id": "1234" }) ``` ```php PHP theme={null} $deleted = $stateset->users->del([ "id" => "1234" ]); ``` ```go Go theme={null} deleted, err := stateset.Users.Del( "1234" ) ``` ```java Java theme={null} Stateset.Users.del( "1234" ); ``` ```json Response theme={null} { "id": "1234", "object": "user", "deleted": true } ``` # Get User Source: https://docs.stateset.com/response-api-reference/users/get GET https://api.stateset.com/v1/users/:id This endpoint gets or creates a new user. ### Body This is the id of the user. ### Response This is the id of the user. This is the active of the user. This is the avatar of the user. This is the bio of the user. This is the birthday of the user. This is the country of the user. This is the email of the user. This is the firstName of the user. This is the lastName of the user. This is the last\_seen of the user. This is the last\_typed of the user. This is the location of the user. This is the organization of the user. This is the phone of the user. This is the regions of the user. This is the title of the user. This is the twitter of the user. This is the username of the user. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": 1 }' ``` ```graphQL GraphQL theme={null} query { user { id active avatar bio birthday country email firstName lastName last_seen last_typed location organization phone regions title twitter username } } ``` ```javascript Node.js theme={null} var user = await stateset.users.get({ "id" }) ``` ```python Python theme={null} user = stateset.users.get( "id" ) ``` ```ruby Ruby theme={null} user = Stateset::Users.get( "id" ) ``` ```php PHP theme={null} $user = Stateset\Users::get([ "id" => "1" ]); ``` ```go Go theme={null} user, err := stateset.Users.get( "id" ) ``` ```` ```java Java User user = stateset.users.get( "id" ); ```` ```json Response theme={null} { "id": 1, "active": true, "avatar": "", "bio": "This is the bio of the user.", "birthday": "2020-01-01", "country": "US", "email": "someone@there.com", } ``` # List Users Source: https://docs.stateset.com/response-api-reference/users/list GET https://api.stateset.com/v1/users/:id This endpoint gets or creates a new user. ### Body This is the limit of the users. This is the offset of the users. This is the order direction of the users. ### Response This is the id of the user. This is the active of the user. This is the avatar of the user. This is the bio of the user. This is the birthday of the user. This is the country of the user. This is the email of the user. This is the firstName of the user. This is the lastName of the user. This is the last\_seen of the user. This is the last\_typed of the user. This is the location of the user. This is the organization of the user. This is the phone of the user. This is the regions of the user. This is the title of the user. This is the twitter of the user. This is the username of the user. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "limit": 10, "offset": 0, "order_direction": "asc" }' ``` ```graphQL GraphQL theme={null} query { user { id active avatar bio birthday country email firstName lastName last_seen last_typed location organization phone regions title twitter username } } ``` ```javascript Node.js theme={null} var user = await stateset.users.list({ limit: 10, offset: 0, order_direction: "asc" }) ``` ```python Python theme={null} user = stateset.users.list( limit=10, offset=0, order_direction="asc" ) ``` ```ruby Ruby theme={null} user = Stateset::Users.list( limit: 10, offset: 0, order_direction: "asc" ) ``` ```php PHP theme={null} $user = Stateset\Users::list([ "limit" => 10, "offset" => 0, "order_direction" => "asc" ]); ``` ```go Go theme={null} user, err := stateset.Users.List( 10, 0, "asc" ) ``` ```java Java theme={null} User user = stateset.users.list( 10, 0, "asc" ); ``` ```json Response theme={null} { "id": 1, "active": true, "avatar": "", "bio": "This is the bio of the user.", "birthday": "2020-01-01", "country": "US", "email": "someone@there.com", } ``` ## Users | Name | Type | Description | | ------------ | -------------------------- | ------------------------------------------------ | | id | Text (Primary Key, Unique) | Unique identifier for the user | | active | Boolean | Indicates if the user is currently active | | avatar | Text | URL or path to the user's avatar image | | bio | Text | Biography or description of the user | | birthday | Date | Date of birth of the user | | country | Text | Country of residence of the user | | email | Text | Email address of the user | | firstName | Text | First name of the user | | lastName | Text | Last name of the user | | last\_seen | Date/Time | Date and time when the user was last seen | | last\_typed | Date/Time | Date and time when the user last typed a message | | location | Text | Location or address of the user | | organization | Text | Organization or company the user belongs to | | phone | Text | Phone number of the user | | regions | Text | Regions or areas associated with the user | | title | Text | Title or job position of the user | | twitter | Text | Twitter handle or username of the user | | username | Text | Unique username of the user | # Update User Source: https://docs.stateset.com/response-api-reference/users/update PUT https://api.stateset.com/v1/users/:id This endpoint updates an existing user. ### Body This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ### Response This is the id of the user. It is used to identify the user. Indicates if the user is currently active URL or path to the user's avatar image Biography or description of the user Date of birth of the user Country of residence of the user Email address of the user First name of the user Last name of the user Date and time when the user was last seen Date and time when the user last typed a message Location or address of the user Organization or company the user belongs to Phone number of the user Regions or areas associated with the user Title or job position of the user Twitter handle or username of the user Unique username of the user ```bash cURL theme={null} curl --location --request PUT 'https://api.stateset.com/v1/users/:id' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "user_group_id": "example_1", "name": "Example 1", "mapping": {"40": "213", "134": "386"}, "properties": {"filterValue": "value"} }' ``` ```json Response theme={null} { "success": 1, "user_group": { "team_id": 113, "token": "", "name": "ok", "provided_id": "6" } } ``` # Realtime Voice Source: https://docs.stateset.com/response-api-reference/voice Explore how StateSet's Autonomous AI Agents and Realtime Voice API are revolutionizing the e-commerce customer experience. # StateSet Voice: Transforming E-commerce with Realtime AI StateSet's cutting-edge **Autonomous AI Agents** are revolutionizing e-commerce, providing seamless, efficient, and personalized customer experiences. Leveraging advanced AI, Natural Language Processing (NLP), and the new **Realtime Voice API**, we are moving beyond traditional ticket-based customer service to enable instant, context-aware customer interactions. ## The Power of the Realtime API OpenAI's Realtime APIs are fundamentally changing how we interact with software, especially in e-commerce operations and customer experience: * **Instant Data Exchange:** Enables immediate data transfer between customers and brands, ensuring up-to-the-second information and actions. * **Seamless Integration:** Facilitates smooth communication between different platforms and services, creating a unified operations stack. * **Enhanced User Experience:** Users receive immediate responses and instant results, significantly improving satisfaction. * **Dynamic Decision Making:** Businesses can make informed decisions based on real-time data, improving agility and responsiveness. ## Key Features of StateSet's Voice AI ### 1. Seamless User Verification * **Email Entry:** Users begin by entering their email address. * **OTP Verification:** A one-time password (OTP) is sent for secure authentication. * **Persistent Authentication:** User information is saved securely for future interactions. ### 2. Context-Aware Interactions * **Personalized Experience:** The system retrieves user context, including order history, preferences, and more. * **Intelligent Recommendations:** Realtime AI provides personalized product suggestions and upsells based on past interactions. * **Effortless Modifications:** Users can easily modify orders or subscriptions using voice commands. ### 3. AI-Powered Natural Language Understanding * **LLM Integration:** Leverages large language models for nuanced comprehension of customer queries, detecting intent, sentiment, and more. * **Finite Perfect Memory:** AI agents maintain context throughout the conversation, ensuring coherent and relevant responses. ### 4. Real-time Action Execution * **Function Calling:** AI can perform actions like order cancellations, subscription modifications, and more in real-time. * **24/7 Availability:** Instant query resolution at any time, enhancing customer satisfaction, especially outside of business hours. ### 5. Enhanced Customer Experience * **Reduced Response Times:** Provides immediate answers to customer queries. * **Increased Satisfaction:** Personalized, efficient service leads to happier customers. * **Lower Operational Costs:** Realtime automation reduces the need for large human customer service teams. ## StateSet's ResponseCX: AI-Powered Customer Service Automation **ResponseCX**, our flagship AI-powered solution, brings all these features together: * **Rapid Resolution:** Dramatically reduced response and resolution times. * **Personalization at Scale:** Tailored customer interaction at every touchpoint. * **Operational Efficiency:** Significant reduction in customer service operational costs. * **Continuous Improvement:** AI models learn and improve with every interaction. ## Implementation and Integration Our voice AI is designed for easy integration: 1. **Seamless Website Integration:** One-touch resolution directly from your e-commerce website. 2. **Secure Authentication Flow:** Email entry → OTP verification → Persistent session. 3. **Comprehensive Action Suite:** From product recommendations to order modifications, all through voice commands. 4. **Omnichannel Support:** Consistent experience across web, mobile, and phone interactions. ## Voice AI Integration with the ResponseCX AI Agent Framework The **Realtime Voice API** seamlessly integrates with our existing AI Agent framework, enhancing the capabilities of our autonomous AI agents: * **Flexible Integration:** Voice AI can be added to existing AI Agents, leveraging the same knowledge base, rules, and action capabilities. * **Unified Experience:** Customers can switch between text and voice interactions without losing context or functionality. * **Enhanced Accessibility:** Voice integration makes our AI Agents more accessible to a wider range of users. ```mermaid theme={null} graph LR A[Customer Interaction] --> B(Realtime Voice API); B --> C(StateSet AI Agents); C --> D[E-commerce Systems]; ``` > This diagram shows how a customer interacts with the Realtime Voice API and then the StateSet AI Agents to interact with your e-commerce systems. ## AI Agents for E-commerce Success Here are key AI Agent use cases that drive e-commerce success, particularly during peak periods: ### 1. Exchanges & Returns Agent: * Automates order lookups, return requests, and label generation. * Provides automated exchange recommendations. * Streamlines the return process for customers and operations teams. ### 2. Order Management Agent: * Handles order cancellation requests and order tagging. * Interfaces with 3PL systems for bespoke order cancellations. * Improves resolution speed and order accuracy. ### 3. Subscriptions Agent: * Automates subscription-related tasks like cancellations, frequency changes, and pausing. * Enables the customer service team to focus on retention strategies. * Builds trust and encourages repeat customers. ### 4. Reasoning AI Agents for Analysis: * Provides insights on frequently asked product questions. * Analyzes subscription cancellation reasons and return/exchange patterns. * Helps in understanding and responding to customer trends during high-volume periods. ## The Future of Customer Experience StateSet's Autonomous AI Agents, powered by the Realtime API, represent the next frontier in conversational AI for e-commerce. By eliminating traditional ticketing systems and enabling instant, context-aware interactions, we're not just improving customer service—we're reimagining it. With a reported **4X-6X ROI** on a monthly basis from revenue generated by our Autonomous AI Agents, the future of commerce is clearly conversational, personalized, and autonomous. Experience the future of e-commerce customer experience with StateSet's **Realtime Voice AI**. Transform your customer interactions, boost satisfaction, and drive operational efficiency like never before. To learn more about **ResponseCX**, [book some time with our team at response.cx](https://response.cx). # Security & Compliance Source: https://docs.stateset.com/security Comprehensive security measures, compliance standards, and best practices for StateSet platform # Our Commitment to Security At StateSet, security isn't just a feature—it's the foundation of everything we build. We understand that our customers trust us with their most valuable business data, and we take that responsibility seriously. Our comprehensive security program ensures your data is protected at every level. ## Industry-Standard Certifications **Independently verified** compliance demonstrating our commitment to: * Security controls and monitoring * System availability and uptime * Processing integrity and accuracy * Data confidentiality and privacy protection **Information Security Management** following international standards: * Risk assessment and management * Security incident response * Business continuity planning * Continuous improvement processes ## Platform Security Architecture ### Data Protection **Data in Transit** * TLS 1.3 for all API communications * Perfect Forward Secrecy (PFS) * HSTS (HTTP Strict Transport Security) * Certificate pinning for mobile apps **Data at Rest** * AES-256 encryption for all stored data * Encrypted database volumes * Secure key management with AWS KMS * Automatic key rotation every 90 days **Identity & Access Management** * Multi-factor authentication (MFA) required * Role-based access control (RBAC) * Principle of least privilege * Regular access reviews and audits **API Security** * Rate limiting and throttling * IP allowlisting capabilities * API key rotation and management * Request signing and verification **Cloud Security** * AWS enterprise-grade infrastructure * VPC isolation and network segmentation * Web Application Firewall (WAF) * DDoS protection and mitigation **Monitoring & Detection** * 24/7 security operations center (SOC) * Real-time threat detection * Automated incident response * Comprehensive audit logging ## API Security Best Practices ### Authentication & Authorization ```javascript theme={null} // ✅ Secure API key usage const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, // Use environment variables baseURL: 'https://api.stateset.com/v1', timeout: 30000, retries: 3 }); // ✅ Implement proper error handling try { const customer = await client.customers.create({ email: 'customer@example.com', name: 'John Doe' }); } catch (error) { if (error.code === 'UNAUTHORIZED') { // Handle authentication errors logger.error('Invalid API key or expired token'); // Don't log sensitive information } else if (error.code === 'RATE_LIMIT_EXCEEDED') { // Handle rate limiting const retryAfter = error.headers['retry-after']; logger.warn(`Rate limited. Retry after ${retryAfter} seconds`); } throw error; } ``` ### Secure Webhook Implementation ```javascript theme={null} // ✅ Verify webhook signatures const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(payload, 'utf8') .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature, 'hex'), Buffer.from(expectedSignature, 'hex') ); } // ✅ Secure webhook endpoint app.post('/webhooks/stateset', express.raw({type: 'application/json'}), (req, res) => { const signature = req.headers['x-stateset-signature']; const isValid = verifyWebhookSignature( req.body, signature, process.env.STATESET_WEBHOOK_SECRET ); if (!isValid) { return res.status(401).send('Unauthorized'); } // Process webhook safely const event = JSON.parse(req.body); // Handle event... res.status(200).send('OK'); }); ``` ## Data Privacy & Compliance ### GDPR Compliance **Customer Rights Management** * Right to access personal data * Right to rectification and deletion * Data portability and export * Automated consent management **Built-in Privacy Features** * Data minimization principles * Purpose limitation controls * Automated data retention policies * Privacy impact assessments ### Data Residency & Sovereignty ```json theme={null} { "data_regions": { "us_east": { "location": "United States (Virginia)", "compliance": ["SOC2", "FedRAMP"], "encryption": "AES-256-GCM" }, "eu_west": { "location": "European Union (Ireland)", "compliance": ["GDPR", "ISO27001"], "encryption": "AES-256-GCM" }, "ap_southeast": { "location": "Asia Pacific (Singapore)", "compliance": ["PDPA", "ISO27001"], "encryption": "AES-256-GCM" } } } ``` ## Security Operations ### Incident Response **Automated Monitoring** * Real-time security event correlation * Anomaly detection and alerting * Threat intelligence integration * 24/7 security operations center **Rapid Response Protocol** * \< 15 minutes: Initial assessment * \< 1 hour: Containment measures * \< 4 hours: Customer notification (if applicable) * \< 24 hours: Resolution and remediation **Business Continuity** * Automated failover systems * Data backup and restoration * Service availability maintenance * Post-incident review and improvements ### Vulnerability Management * **Regular Security Assessments**: Quarterly penetration testing by certified third parties * **Automated Scanning**: Daily vulnerability scans across all systems * **Patch Management**: Critical security patches applied within 24 hours * **Bug Bounty Program**: Responsible disclosure with security researchers ## Compliance & Auditing ### Regular Audits **Annual Compliance Audit** * Independent security controls testing * Operational effectiveness verification * Customer report availability **Quarterly Security Testing** * External penetration testing * Application security assessment * Network infrastructure testing **Continuous Monitoring** * Monthly access reviews * Quarterly risk assessments * Annual policy updates ### Audit Logging All API requests and administrative actions are logged with: ```json theme={null} { "timestamp": "2024-01-15T10:30:00Z", "event_type": "api_request", "user_id": "usr_12345", "api_key_id": "key_67890", "endpoint": "/v1/customers", "method": "POST", "ip_address": "203.0.113.0", "user_agent": "StateSet-SDK/1.0.0", "response_code": 201, "response_time_ms": 150, "request_id": "req_abcd1234" } ``` ## Security Best Practices for Developers ### Environment Security **Never commit secrets to version control** Use environment variables or secure secret management systems: ```bash theme={null} # ✅ Environment variables export STATESET_API_KEY="your_secure_api_key" export STATESET_WEBHOOK_SECRET="your_webhook_secret" # ✅ Using a .env file (add to .gitignore) STATESET_API_KEY=your_secure_api_key STATESET_WEBHOOK_SECRET=your_webhook_secret ``` ### API Key Management **Secure Key Management** * Rotate API keys every 90 days * Use different keys for different environments * Implement key-level monitoring and alerting * Revoke unused or compromised keys immediately **Access Patterns** * Use read-only keys when possible * Implement IP allowlisting for production keys * Monitor for unusual usage patterns * Set up automated key rotation ```javascript theme={null} // ✅ Secure configuration const config = { apiKey: process.env.STATESET_API_KEY, environment: process.env.NODE_ENV, allowedIPs: process.env.ALLOWED_IPS?.split(','), timeout: 30000, retries: 3, retryDelay: 1000 }; // ✅ Key validation if (!config.apiKey || !config.apiKey.startsWith('sk_')) { throw new Error('Invalid StateSet API key format'); } // ✅ Environment checks if (config.environment === 'production' && !config.allowedIPs) { console.warn('Production environment without IP allowlisting'); } ``` ## Contact & Support ### Security Team For security-related inquiries: * **Security Issues**: [security@stateset.com](mailto:security@stateset.com) * **Compliance Questions**: [compliance@stateset.com](mailto:compliance@stateset.com) * **Trust Portal**: [trust.stateset.com](https://trust.stateset.com) * **Status Page**: [status.stateset.com](https://status.stateset.com) ### Emergency Response For security emergencies requiring immediate attention: **Critical Security Issues** * Phone: +1 (555) SECURITY * Email: [emergency@stateset.com](mailto:emergency@stateset.com) * Response Time: \< 15 minutes *** **Continuous Improvement** Our security program is continuously evolving. We regularly review and update our practices based on emerging threats, industry best practices, and customer feedback. For the latest security updates and advisories, visit our [trust portal](https://trust.stateset.com). # Service-as-a-Software (SaaS 3.0) Source: https://docs.stateset.com/service-as-a-software The revolutionary paradigm shift from software tools to autonomous business outcomes # Service-as-a-Software: The Autonomous Business Revolution **We're not building better software. We're eliminating the need for it.** Traditional software gives you tools. StateSet gives you outcomes. ## The \$4.3 Trillion Problem Every year, businesses waste \$4.3 trillion on inefficient operations: * **60%** of employee time spent on repetitive tasks * **130+** different software tools per enterprise * **73%** of data never analyzed or used * **8 hours** average time to resolve customer issues The problem isn't that we need better software. **The problem is that we're still using software at all.** ## The Evolution: From Tools to Outcomes ### The Stone Age of Business Software (1980s-2000s) ```mermaid theme={null} graph LR A[Human] -->|Manual Input| B[Software] B -->|Output| C[Human] C -->|Decision| D[Action] ``` **Characteristics:** * Install on every computer * Massive IT departments * Updates via CD-ROM * Humans do 90% of the work **Example:** Installing QuickBooks on 50 computers and manually entering every transaction. ### The Bronze Age of Business Software (2000s-2020s) ```mermaid theme={null} graph LR A[Human] -->|Browser| B[Cloud Software] B -->|Dashboard| C[Human] C -->|Interprets| D[Decision] D -->|Manual| E[Action] ``` **Characteristics:** * Access from anywhere * Subscription pricing * Automatic updates * Humans still do 70% of the work **Example:** Logging into Salesforce to manually update 100 customer records. ### The Future is Now (2024+) ```mermaid theme={null} graph LR A[Business Goal] -->|Achieved by| B[AI Agents] B -->|Autonomous Actions| C[Outcomes] C -->|Measured Results| D[Value Delivered] ``` **Characteristics:** * AI agents work autonomously * Pay for outcomes, not seats * Continuous improvement * Humans do 10% of the work (strategic decisions only) **Example:** Tell StateSet "increase customer satisfaction by 20%" and watch it happen. ## What Makes Service-as-a-Software Different? ### Traditional SaaS vs. Service-as-a-Software * **You get:** Software tools * **You do:** All the work * **Pricing:** Per user/month * **Value:** Potential productivity * **Example:** CRM that stores data * **You get:** Business outcomes * **AI does:** The actual work * **Pricing:** Per outcome achieved * **Value:** Guaranteed results * **Example:** AI that manages all customer relationships ## The Six Pillars of SaaS 3.0 ### 1. 🎯 Outcome-Driven Architecture Traditional software asks: "What features do you need?" StateSet asks: **"What do you want to achieve?"** ```typescript theme={null} // Traditional Approach const software = new CRM(); human.enterData(software); // Manual data entry human.analyzeReports(software); // Manual analysis human.makeDecisions(software); // Manual decisions // StateSet Approach const outcome = await StateSet.achieve({ goal: "Increase customer retention by 25%", constraints: { budget: "$10,000/month", timeline: "90 days" } }); // That's it. StateSet handles everything else. ``` ### 2. 🤖 Autonomous Agent Networks Your business doesn't run on software. It runs on decisions and actions. StateSet's agents make both. * Responds to inquiries in less than 1 second * Resolves 94% without human help * Learns from every interaction * Proactively prevents churn * Manages entire order lifecycle * Optimizes inventory in real-time * Coordinates with suppliers * Predicts and prevents issues * Identifies expansion opportunities * Executes marketing campaigns * Optimizes pricing dynamically * Drives revenue growth 24/7 ### 3. 💰 Performance-Based Pricing **Stop paying for potential. Start paying for performance.** Traditional SaaS charges you whether it works or not. StateSet only succeeds when you do. ### 4. 🧠 Collective Intelligence Every StateSet agent learns from every interaction across our entire network. Your agents get smarter every second—even while you sleep. ```mermaid theme={null} graph TB A[Your Agent] -->|Learns| B[Global Knowledge Graph] C[10,000 Other Agents] -->|Contribute| B B -->|Improves| A B -->|Patterns| D[Predictive Insights] D -->|Prevents Issues| A ``` ### 5. 🔄 Self-Improving Systems Traditional software degrades over time. StateSet improves autonomously. **Week 1:** Resolves customer issues in 5 minutes **Week 4:** Resolves similar issues in 2 minutes **Week 12:** Prevents those issues from occurring **Week 24:** Optimizes entire customer experience ### 6. 🎭 Adaptive Interfaces The interface adapts to you, not the other way around. * **CEOs** see strategic insights and outcome metrics * **Managers** see team performance and optimization opportunities * **Operators** see task queues and exception handling * **Customers** see natural conversations and instant resolutions ## Real-World Impact: SaaS 3.0 in Action ### Case Study: TechStyle Fashion Group "We went from 15 people managing customer service to 1 person overseeing AI agents. Response time dropped 94%, satisfaction increased 40%, and we're saving \$2.3M annually. This isn't an upgrade—it's a completely different universe." **Marcus Chen, COO** **Traditional Approach:** * 15 customer service reps * 8-hour response time * 68% satisfaction rate * \$3M annual cost **StateSet Service-as-a-Software:** * 1 human supervisor + AI agents * 30-second response time * 95% satisfaction rate * \$700K annual cost ### The Numbers Don't Lie ## The StateSet Service-as-a-Software Platform ### 1. The Autonomous Operating System StateSet One Architecture StateSet One isn't software you use—it's an AI nervous system that runs your business: * **Self-Organizing Agents**: Automatically form teams to tackle complex problems * **Predictive Operations**: Fix problems before they happen * **Adaptive Workflows**: Continuously optimize based on outcomes * **Human-in-the-Loop**: You make strategic decisions, AI handles everything else ### 2. The Agent Marketplace ### 3. Guaranteed Outcomes We don't just promise results—we guarantee them: ## The Mathematics of Transformation Let's talk ROI. Here's what happens when you switch to Service-as-a-Software: ```python theme={null} # Traditional SaaS Approach employees = 50 avg_salary = 70000 software_licenses = 130 * 200 # 130 tools @ $200/month annual_cost = (employees * avg_salary) + (software_licenses * 12) # Total: $3,812,000 efficiency = 0.4 # 40% time on value-add work effective_output = employees * efficiency # Effective employees: 20 # StateSet Service-as-a-Software human_supervisors = 5 supervisor_salary = 90000 stateset_outcomes = 250000 # Pay for performance annual_cost_saas3 = (human_supervisors * supervisor_salary) + stateset_outcomes # Total: $700,000 efficiency_saas3 = 0.9 # 90% time on strategic work ai_agent_multiplier = 50 # Each agent = 50 human tasks/day effective_output_saas3 = human_supervisors * efficiency_saas3 * ai_agent_multiplier # Effective output: 225 (11x more than traditional) roi = (annual_cost - annual_cost_saas3) / annual_cost_saas3 # ROI: 444% in Year 1 ``` ## Implementation: From Zero to Autonomous in 7 Days ### Day 1-2: Discovery & Design Our AI analyzes your entire operation: * Maps all workflows and decision points * Identifies automation opportunities * Designs optimal agent configuration ### Day 3-4: Agent Deployment Deploy pre-trained agents customized for your business: * Customer service agents go live * Operations agents start learning * Integration with existing systems ### Day 5-6: Learning & Optimization Agents rapidly improve through accelerated learning: * Process historical data * Learn from your best employees * Optimize for your specific KPIs ### Day 7: Full Autonomy Your business runs itself: * 90%+ tasks handled automatically * Humans focus on strategy * Continuous improvement begins ## The Future of Business is Autonomous ### 2025: The Tipping Point * 50% of customer interactions handled by AI agents * Early adopters see 10x productivity gains * Traditional software companies scramble to adapt ### 2026: The New Normal * Autonomous operations become table stakes * Businesses run with 90% fewer employees * Focus shifts from operations to innovation ### 2027: The Autonomous Economy * AI agents negotiate with other AI agents * Entire supply chains self-organize * Human creativity unleashed at scale ## Join the Revolution *** "StateSet isn't just changing how we work—it's changing what work means. We've gone from managing software to managing outcomes. From hiring people to deploying agents. From hoping for results to guaranteeing them. This is the future, and it's already here." **Sarah Mitchell, CEO of FutureCommerce** **Welcome to Service-as-a-Software. Welcome to StateSet.** *The future doesn't wait. Neither should you.* ## Frequently Asked Questions ### What is Service-as-a-Software? Service-as-a-Software (SaaS 3.0) is a paradigm where AI agents autonomously deliver business outcomes, unlike traditional SaaS which provides tools requiring human operation. ### How does StateSet differ from traditional SaaS? Traditional SaaS offers tools; StateSet delivers guaranteed outcomes through autonomous AI agents, with performance-based pricing. ### What kind of outcomes can I expect? Outcomes vary by agent, such as increased revenue, reduced costs, improved customer satisfaction, and automated operations. See our Agent Marketplace for specifics. ### Is there a free trial? Yes, we offer a 7-day implementation period where our AI analyzes your operations and deploys agents, leading to full autonomy. ### How secure is StateSet? StateSet is built with enterprise-grade security, ensuring data protection and compliance with industry standards. # Set L2 Source: https://docs.stateset.com/set/set Overview of the Set L2 chain, anchoring, and verification flow. # Set ```bash theme={null} git clone https://github.com/stateset/set.git cd set ``` Set is an Ethereum Layer-2 (L2) network built on the **OP Stack**, designed for **commerce**. It offers faster, cheaper, and cryptographically verifiable transactions by leveraging optimistic rollups with Merkle root anchoring. ## Table of Contents * [Architecture](#architecture) * [Key Features](#key-features) * [Chain Configuration](#chain-configuration) * [Directory Structure](#directory-structure) * [Technology Stack](#technology-stack) * [Quick Start](#quick-start) * [Local Development (Anvil)](#local-development-anvil) * [Full Devnet](#full-devnet) * [Smart Contracts](#smart-contracts) * [SetRegistry](#setregistry) * [SetPaymaster](#setpaymaster) * [Anchor Service](#anchor-service) * [Integration with stateset-sequencer](#integration-with-stateset-sequencer) * [Docker Deployment](#docker-deployment) * [Testing](#testing) * [Deployment Checklist](#deployment-checklist) * [Monitoring](#monitoring) * [Security](#security) * [Decentralization and Fault Proofs](#decentralization-and-fault-proofs) * [Scorecard](#scorecard) * [Troubleshooting](#troubleshooting) * [Resources](#resources) ## Architecture ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ SET L2 (84532001) │ │ (Commerce-Optimized OP Stack) │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ op-geth │ │ op-node │ │ op-batcher │ │ op-proposer │ │ │ │ (execution) │ │ (consensus) │ │ (batches) │ │ (state) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └─────────────┘ │ │ │ │ │ │ │ │ └────────────────┼──────────────────┴────────────────┘ │ │ │ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ Smart Contracts │ │ │ │ ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ │ │ │ SetRegistry │ │ SetPaymaster │ │ │ │ │ │ (Merkle root anchoring │ │ (Gas abstraction for │ │ │ │ │ │ from sequencer) │ │ merchant transactions) │ │ │ │ │ └─────────────────────────┘ └────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ │ │ └──────────────────────────┼──────────────────────────────────────────────┘ │ ┌──────────────────┼──────────────────┐ │ │ │ ▼ │ ▼ ┌───────────────────┐ │ ┌─────────────────────────┐ │ Anchor Service │ │ │ stateset-sequencer │ │ (Rust) │◄─────┴─────►│ (Off-chain commerce │ │ - Health metrics │ │ event processing) │ │ - Batch anchoring│ └─────────────────────────┘ └───────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ ETHEREUM SEPOLIA (L1) - 11155111 │ │ OptimismPortal │ L2OutputOracle │ SystemConfig │ └─────────────────────────────────────────────────────────────────────────┘ ``` ## Key Features | Feature | Description | | -------------------------------- | ------------------------------------------------------------------ | | **2-second block times** | Fast confirmations optimized for commerce operations | | **Low gas fees** | EIP-1559 parameters tuned for merchant transactions | | **Merkle root anchoring** | Verifiable event commitments from stateset-sequencer | | **Multi-tenant isolation** | Per-tenant/store state tracking via `keccak256(tenantId, storeId)` | | **Inclusion proof verification** | On-chain verification of off-chain events | | **Gas sponsorship** | Merchants can sponsor user transactions via SetPaymaster | | **Strict mode verification** | State chain continuity checking to prevent gaps/forks | ## Chain Configuration | Parameter | Value | | -------------------- | --------------------------- | | Chain ID | `84532001` | | Block Time | 2 seconds | | Gas Limit | 30M gas/block | | L1 Settlement | Ethereum Sepolia (11155111) | | Native Token | ETH | | EVM Version | Cancun | | OP Contracts Version | v1.8.0 | ## Directory Structure ``` set/ ├── anchor/ # Rust anchor service │ ├── src/ │ │ ├── main.rs # Entry point │ │ ├── config.rs # Configuration from env vars │ │ ├── client.rs # Sequencer API client │ │ ├── service.rs # Main anchor logic │ │ ├── health.rs # Health/metrics HTTP server │ │ └── types.rs # Data structures │ └── tests/ │ └── integration.rs # Integration tests ├── contracts/ # Solidity smart contracts │ ├── src/ │ │ ├── SetRegistry.sol # Merkle root anchoring (433 lines) │ │ └── commerce/ │ │ └── SetPaymaster.sol # Gas abstraction (558 lines) │ ├── test/ │ │ ├── SetRegistry.t.sol # Registry tests │ │ └── SetPaymaster.t.sol # Paymaster tests │ └── lib/ # Dependencies (git submodules) │ ├── forge-std/ # Foundry testing framework │ └── openzeppelin-contracts/ ├── op-stack/ # OP Stack configuration │ ├── deployer/ # op-deployer intent files │ ├── batcher/ # Batch submission config │ ├── proposer/ # State root submission config │ ├── challenger/ # Dispute resolution config │ └── sequencer/ # op-geth/op-node config ├── docker/ # Docker Compose files │ ├── docker-compose.yml # Main local devnet │ ├── docker-compose.sepolia.yml │ ├── docker-compose.local.yml │ └── config/ # JWT and node configs ├── scripts/ # Deployment and management │ ├── dev.sh # Local Anvil development helper │ ├── anchor-devnet.sh # Anchor service local helper │ ├── deploy-set-contracts.sh │ ├── deploy-l1.sh │ ├── generate-genesis.sh │ ├── reset-devnet.sh │ ├── start-devnet.sh │ ├── stop-devnet.sh │ ├── quick-start-local.sh │ └── install-op-stack.sh ├── config/ # Chain configuration │ ├── chain-config.toml # L2 chain parameters │ ├── local.env.example # Local devnet env template │ └── sepolia.env.example # Sepolia env template └── docs/ # Documentation ├── README.md # Architecture overview └── local_testing_guide.md # Anvil testing guide ``` ## Technology Stack ### Languages & Frameworks | Component | Technology | Version | | ------------------ | --------------- | ------------- | | Smart Contracts | Solidity | 0.8.20 | | Contract Framework | Foundry (Forge) | Latest | | Anchor Service | Rust | 2021 Edition | | Async Runtime | Tokio | Full features | | Ethereum Client | Alloy | 0.9 | | HTTP Server | Axum | 0.8 | | Scripting | Bash | - | ### OP Stack Components | Component | Purpose | | ------------- | --------------------------------- | | op-geth | L2 execution client (EVM) | | op-node | L2 consensus client | | op-batcher | Submits transaction batches to L1 | | op-proposer | Submits state roots to L1 | | op-challenger | Dispute resolution | ### Dependencies **Solidity:** * OpenZeppelin Contracts (Upgradeable patterns) * Forge-std (Testing) **Rust:** * `tokio` - Async runtime * `alloy` - Ethereum interactions * `axum` - HTTP server for health endpoints * `tracing` - Structured logging * `serde` - Serialization * `reqwest` - HTTP client ## Quick Start ### Local Development (Anvil) The fastest way to get started for development and testing: ```bash theme={null} # 1. Start local Anvil node (Chain ID: 84532001, 2s blocks) ./scripts/dev.sh start # 2. Deploy contracts to local Anvil ./scripts/dev.sh deploy # 3. Run contract tests ./scripts/dev.sh test # 4. Check node status ./scripts/dev.sh status # 5. Fund a test account ./scripts/dev.sh fund 0xYourAddress # Other commands ./scripts/dev.sh accounts # List pre-funded accounts ./scripts/dev.sh console # Open Foundry console ``` **Pre-funded Test Accounts:** | Account | Address | Private Key | | --------- | --------------------------------------------------- | -------------------------------------------------------------------- | | Account 0 | `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` | `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` | | Account 1 | `0x70997970C51812dc3A010C7d01b50e0d17dc79C8` | `0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d` | | ... | See `./scripts/dev.sh accounts` for all 10 accounts | | ### Full Devnet For a complete L2 environment with all OP Stack components: **Prerequisites:** * Go 1.21+ * Rust 1.70+ * Docker & Docker Compose * 2+ ETH on Sepolia (for deployment) ```bash theme={null} # 1. Install OP Stack binaries ./scripts/install-op-stack.sh # 2. Configure environment cp config/sepolia.env.example config/sepolia.env # Edit sepolia.env with your addresses and private keys # 3. Deploy L1 contracts to Sepolia ./scripts/deploy-l1.sh # 4. Generate L2 genesis ./scripts/generate-genesis.sh # 5. Start the devnet ./scripts/start-devnet.sh # Or use quick-start for minimal setup ./scripts/quick-start-local.sh ``` **Verify Chain is Running:** ```bash theme={null} # Check L2 block number cast block-number --rpc-url http://localhost:8547 # Get chain ID (should return 84532001) cast chain-id --rpc-url http://localhost:8547 # Check sync status curl -s http://localhost:8547 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' ``` ## Smart Contracts ### SetRegistry The SetRegistry contract stores batch commitments from the stateset-sequencer, enabling on-chain verification of off-chain commerce events. **Key Features:** * Multi-sequencer authorization * State chain continuity verification * Merkle inclusion proof verification * Per-tenant/store isolation **Core Functions:** | Function | Description | | ----------------------------- | ------------------------------------------------ | | `commitBatch()` | Submit a batch commitment with Merkle roots | | `verifyInclusion()` | Verify an event is included in a committed batch | | `getLatestStateRoot()` | Get current state root for a tenant/store | | `setSequencerAuthorization()` | Admin: authorize/revoke sequencers | | `setStrictMode()` | Enable/disable state chain verification | **Example Usage:** ```solidity theme={null} // Verify an order event was included in a batch bool valid = registry.verifyInclusion( batchId, orderEventHash, merkleProof, leafIndex ); // Get latest state root for a tenant/store bytes32 stateRoot = registry.getLatestStateRoot(tenantId, storeId); ``` **Interact via CLI:** ```bash theme={null} # Check if a sequencer is authorized cast call $REGISTRY_ADDRESS "authorizedSequencers(address)" $SEQUENCER_ADDRESS # Get batch commitment cast call $REGISTRY_ADDRESS "batchCommitments(bytes32)" $BATCH_ID ``` ### SetPaymaster Gas abstraction for sponsored commerce transactions, allowing merchants to pay for user gas fees. **Sponsorship Tiers:** | Tier | Monthly Limit | Per-Tx Limit | | ---------- | ------------- | ------------ | | Starter | 0.1 ETH | 0.001 ETH | | Growth | 1 ETH | 0.01 ETH | | Enterprise | 10 ETH | 0.1 ETH | **Supported Operation Types:** | Operation | Description | | ------------------- | --------------------- | | `ORDER_CREATE` | Creating new orders | | `ORDER_UPDATE` | Updating order status | | `PAYMENT_PROCESS` | Processing payments | | `INVENTORY_UPDATE` | Updating inventory | | `RETURN_PROCESS` | Processing returns | | `COMMITMENT_ANCHOR` | Anchoring commitments | | `OTHER` | Other operations | **Features:** * Per-transaction and daily/monthly spend limits * Automatic refund of unused gas * Category-based sponsorship * Merchant dashboards ## Anchor Service The anchor service (`set-anchor`) is a Rust service that bridges the stateset-sequencer to the SetRegistry contract on-chain. ### Building ```bash theme={null} cd anchor cargo build --release ``` ### Running ```bash theme={null} # Set required environment variables export SET_REGISTRY_ADDRESS=0x... export SEQUENCER_PRIVATE_KEY=0x... export SEQUENCER_API_URL=http://localhost:3000 export L2_RPC_URL=http://localhost:8547 export ANCHOR_INTERVAL_SECS=60 # seconds export MIN_EVENTS_FOR_ANCHOR=100 # Run the service ./target/release/set-anchor ``` **Local devnet:** ```bash theme={null} ./scripts/dev.sh anchor-start ./scripts/dev.sh anchor-smoke ``` Smoke overrides (optional): ```bash theme={null} EVENT_LEAF_0=0x... EVENT_LEAF_1=0x... TENANT_ID=0x... STORE_ID=0x... \ NEW_STATE_ROOT=0x... ./scripts/dev.sh smoke ``` ### Health Endpoints The anchor service exposes health and metrics endpoints: | Endpoint | Description | | -------------- | -------------------------------------------------------- | | `GET /health` | Liveness probe (service is running) | | `GET /ready` | Readiness probe (connected to chain and sequencer) | | `GET /metrics` | Prometheus-format metrics | | `GET /stats` | JSON statistics (anchored count, last anchor time, etc.) | **Example:** ```bash theme={null} # Check if service is ready curl http://localhost:9090/ready # Get metrics curl http://localhost:9090/metrics ``` ## Integration with stateset-sequencer Set integrates with the stateset-sequencer through a two-phase process: ``` stateset-sequencer Anchor Service SetRegistry │ │ │ │ 1. Create BatchCommitment │ │ │ with Merkle roots │ │ │ │ │ │ 2. GET /v1/commitments/pending │ │ │◄───────────────────────────────────│ │ │ Return unanchored batches │ │ │ │ │ │ │ 3. commitBatch(...) │ │ │───────────────────────────────►│ │ │ Returns tx hash │ │ │◄───────────────────────────────│ │ │ │ │ 4. POST /v1/commitments/{id}/anchored │ │◄───────────────────────────────────│ │ │ with chain_tx_hash │ │ │ │ │ ``` **API Endpoints:** | Endpoint | Method | Description | | ------------------------------- | ------ | ------------------------------ | | `/v1/commitments/pending` | GET | List unanchored commitments | | `/v1/commitments/{id}/anchored` | POST | Notify of successful anchoring | ## Docker Deployment ### Local Devnet ```bash theme={null} cd docker # Start full local devnet (includes L1) docker-compose up -d # Check logs docker-compose logs -f op-geth # Stop docker-compose down ``` ### Sepolia Testnet ```bash theme={null} cd docker # Connects to real Ethereum Sepolia docker-compose -f docker-compose.sepolia.yml up -d ``` ### With Optional Services ```bash theme={null} # With block explorer docker-compose --profile explorer up -d # With anchor service docker-compose --profile anchor up -d ``` ### Alternative L1 Clients ```bash theme={null} # Using Nethermind as L1 docker-compose -f docker-compose.nethermind.yml up -d # Using Reth as L1 docker-compose -f docker-compose.reth.yml up -d ``` ## Testing ### Contract Tests ```bash theme={null} cd contracts # Run all tests forge test # Run with verbosity forge test -vvv # Run specific test forge test --match-test testCommitBatch # Run with gas reporting forge test --gas-report # Generate coverage forge coverage ``` ### Anchor Service Tests ```bash theme={null} cd anchor # Run unit tests cargo test # Run integration tests (requires Anvil running) cargo test --test integration # Run with logs RUST_LOG=debug cargo test ``` ## Deployment Checklist ### Accounts Setup 1. [ ] Generate 5 Ethereum accounts: * Admin (owns contracts) * Batcher (submits batches to L1) * Proposer (submits state roots) * Challenger (dispute resolution) * Sequencer (L2 block production) 2. [ ] Fund each account with 0.5+ Sepolia ETH ### Infrastructure 3. [ ] Configure Sepolia RPC endpoint (Infura/Alchemy) 4. [ ] Set up JWT secret for engine API authentication 5. [ ] Prepare data directories for persistent storage ### Deployment 6. [ ] Run `deploy-l1.sh` - Deploy OP Stack contracts to Sepolia 7. [ ] Run `generate-genesis.sh` - Create L2 genesis block 8. [ ] Start L2 nodes (op-geth, op-node) 9. [ ] Start op-batcher and op-proposer 10. [ ] Deploy SetRegistry to L2 11. [ ] Deploy SetPaymaster to L2 12. [ ] Start anchor service ### Verification 13. [ ] Verify L2 is producing blocks (2s intervals) 14. [ ] Verify batches are being submitted to L1 15. [ ] Test anchor service connectivity 16. [ ] Verify contract deployments with `cast` ## Monitoring See `docs/monitoring.md` for SLOs, alert suggestions, and metric definitions. ### Key Metrics | Metric | Expected | Alert Threshold | | ---------------- | ----------------- | --------------- | | Block production | Every 2 seconds | > 10s gap | | Batch submission | Every few minutes | > 30 min gap | | Anchor lag | \< 5 minutes | > 15 minutes | | L2 safe head lag | \< 10 blocks | > 100 blocks | ### Viewing Logs ```bash theme={null} # op-geth logs tail -f logs/op-geth.log # op-node logs tail -f logs/op-node.log # Anchor service logs docker-compose logs -f set-anchor # All OP Stack logs ./scripts/start-devnet.sh logs ``` ### Anchor Service Metrics ```bash theme={null} # Prometheus metrics (HEALTH_PORT, default 9090) curl http://localhost:9090/metrics # JSON stats curl http://localhost:9090/stats | jq ``` ## Security ### Best Practices * **Multi-sig admin**: Use a multisig wallet for admin/owner roles in production * **Key management**: Never commit private keys; use environment variables or secret managers * **Sequencer authorization**: Only authorize trusted sequencer addresses * **Strict mode**: Enable strict mode in production to prevent state gaps * **Threat model**: Review and maintain `docs/threat-model.md` * **Operations runbook**: Keep `docs/runbook.md` current with incident response steps * **Governance policy**: Maintain `docs/security.md` for upgrade and key management ### Pre-Production Checklist * [ ] Smart contract audit completed * [ ] Penetration testing of anchor service * [ ] Key rotation procedures documented * [ ] Incident response plan prepared * [ ] Monitoring and alerting configured ## Decentralization and Fault Proofs See `docs/decentralization.md` and `docs/fault-proofs.md` for the phased decentralization plan and fault-proof operations. Validate production config with: ```bash theme={null} ./scripts/validate-ops-config.sh --mode testnet --require-fault-proofs --require-admin-policy ``` Verify L1 settlement contracts: ```bash theme={null} ./scripts/check-l1-settlement.sh --env-file config/sepolia.env --mode testnet --require-addresses ``` ## Scorecard See `docs/scorecard.md` for the 10/10 rubric and progress tracking. Supporting docs include `docs/threat-model.md`, `docs/security.md`, `docs/runbook.md`, and `docs/architecture.md`. ## Troubleshooting ### Common Issues **L2 not producing blocks:** ```bash theme={null} # Check op-node sync status curl -s http://localhost:9545 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' | jq # Verify L1 connection curl -s http://localhost:8545 -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' ``` **Anchor service not connecting:** ```bash theme={null} # Check health endpoint curl http://localhost:9090/ready # Verify environment variables echo $SET_REGISTRY_ADDRESS echo $L2_RPC_URL # Check sequencer API curl http://localhost:3000/v1/commitments/pending ``` **Contract deployment failing:** ```bash theme={null} # Ensure you have ETH cast balance $DEPLOYER_ADDRESS --rpc-url http://localhost:8547 # Check gas prices cast gas-price --rpc-url http://localhost:8547 # Verify RPC is responding cast chain-id --rpc-url http://localhost:8547 ``` **Tests failing:** ```bash theme={null} # Update dependencies cd contracts && forge update # Clean and rebuild forge clean && forge build # Run with more verbosity forge test -vvvv ``` ## Resources ### Documentation * [OP Stack Documentation](https://docs.optimism.io/operators/chain-operators) * [Optimism Monorepo](https://github.com/ethereum-optimism/optimism) * [Foundry Book](https://book.getfoundry.sh/) * [Alloy Documentation](https://alloy.rs/) ### Project Documentation * [Local Testing Guide](docs/local_testing_guide.md) * [Architecture Overview](docs/architecture.md) * [Scorecard](docs/scorecard.md) * [Toolchain Versions](docs/toolchain.md) * [Monitoring and SLOs](docs/monitoring.md) * [Security and Governance](docs/security.md) * [Node Operator Guide](docs/node-operators.md) * [Integration Example](docs/integration-example.md) * [Block Explorer and Indexing](docs/explorer.md) * [Bridge and Onramp Support](docs/bridge.md) * [Operations History](docs/operations-history.md) * [SDK](sdk/README.md) * [Audit Report](docs/audit-report.md) * [Governance Evidence](docs/governance-evidence.md) * [Fault Proof Exercise Log](docs/fault-proof-exercise.md) * [Decentralization Roadmap](docs/decentralization.md) * [Fault Proof Operations](docs/fault-proofs.md) * [Threat Model](docs/threat-model.md) * [Operations Runbook](docs/runbook.md) ### Related Projects * [StateSet Sequencer](../stateset-sequencer/) - Off-chain commerce event processing * [StateSet Network](../) - Parent project documentation ## License MIT # StateSet Set L2 Source: https://docs.stateset.com/set/stateset-set-l2 Overview of the Set L2 chain, anchoring, and verification flow. # StateSet Set L2 Set L2 is the anchoring layer for verifiable commerce events. It stores batch commitments and proof metadata so any party can verify event inclusion, policy compliance, and state transitions. ## What Set L2 Provides * On-chain batch commitments for sequenced events * Proof anchoring for compliance and policy verification * Public verification for inclusion and state transitions ## Components * **SetRegistry**: Stores batch commitments and proof metadata * **Anchor service**: Submits commitments and proofs on-chain * **Verifier clients**: Validate inclusion and compliance ## Data Flow 1. Sequencer batches events into a Merkle tree. 2. Proofs are generated for policy compliance. 3. Commitments and proof hashes are anchored on Set L2. 4. Verifiers confirm inclusion and policy compliance. ## When to Use Set L2 * Auditing event trails across systems * Verifying compliance against policy limits * Ensuring ordering and integrity of commerce events ## Core Contracts Set L2 exposes a registry contract that accepts commitments from the sequencer and proof system. The registry stores metadata that can be used to verify event inclusion and policy compliance without trusting the sequencer or the proving service. ### SetRegistry Responsibilities * Store batch commitments for event sequences * Store proof metadata for policy compliance * Provide inclusion verification for external verifiers ## How It Fits Together 1. Events are sequenced by the StateSet Sequencer. 2. The sequencer commits batch roots to Set L2. 3. Proofs are generated and anchored for policy compliance. 4. External verifiers can confirm inclusion and compliance on-chain. ## Getting Started If you are evaluating the full VES stack, start with the sequencer overview and demo to understand how events are captured and committed. ## Related Documentation * [StateSet Sequencer](/stateset-sequencer) * [Set L2 Verification](/stateset-set-l2-verification) # About Set L2 architecture Source: https://docs.stateset.com/set/stateset-set-l2-architecture Understand how Set L2 stores commitments and enables verification. # About Set L2 architecture This explanation covers how Set L2 stores commitments and enables verification across systems. Set L2 anchors batch commitments and proof metadata on-chain so clients can verify inclusion and compliance without trusting the sequencer. ## How Set L2 works * The sequencer orders events and computes Merkle roots. * The prover generates compliance proofs. * SetRegistry stores the batch commitment and proof hashes. * Verifiers recompute and compare proofs locally. ## Why this design On-chain anchoring makes the chain the source of truth and allows independent verification. ## When to use this approach * **Audit trails**: When you need tamper-evident event history * **Compliance**: When policies must be provable to third parties * **Trust minimization**: When parties do not trust the sequencer ## Relationship to other features Set L2 is part of the VES flow with the sequencer and verifier clients. ## Further reading * [Set L2 Overview](/stateset-set-l2) * [Set L2 Verification](/stateset-set-l2-verification) * [Sequencer Architecture](/stateset-sequencer-architecture) # Set L2 Compliance Proofs Source: https://docs.stateset.com/set/stateset-set-l2-compliance-proof How policy proofs are anchored and verified. # Set L2 Compliance Proofs Set L2 anchors proof metadata so clients can verify that a policy was satisfied for a batch of events. ## Proof Metadata Each batch commitment can include proof metadata: * `proofHash`: Hash of the proof artifact * `policyHash`: Hash of the policy definition * `allCompliant`: Boolean compliance flag ## Verification Flow 1. Fetch proof metadata from Set L2. 2. Retrieve the proof artifact from your prover storage. 3. Verify the proof locally against the policy inputs. 4. Compare computed hash with the on-chain `proofHash`. ## When to Use Compliance Proofs * Regulatory or policy compliance (AML, order caps) * Third-party verification requirements * Trust minimization across vendors ## Related Documentation * [Set L2 Overview](/stateset-set-l2) * [Set L2 Verification](/stateset-set-l2-verification) # Set L2 Verification Source: https://docs.stateset.com/set/stateset-set-l2-verification How to verify inclusion and compliance using Set L2 commitments. # Set L2 Verification Set L2 enables third parties to verify event inclusion and policy compliance using on-chain commitments and proof metadata. ## Verify Event Inclusion To verify an event inclusion: 1. Retrieve the batch commitment from Set L2. 2. Obtain the Merkle proof from the sequencer. 3. Recompute the root and compare with the on-chain commitment. ## Verify Policy Compliance Compliance proofs are anchored alongside batch commitments: 1. Retrieve proof metadata from Set L2. 2. Validate proof hash and policy hash. 3. Verify the proof using the STARK verifier. ## When to Use Verification * External auditors validating an event trail * Partners confirming a policy boundary (e.g., AML thresholds) * Agents coordinating across systems without shared trust ## Related Documentation * [Set L2 Overview](/stateset-set-l2) * [Sequencer Overview](/stateset-sequencer) # Set L2 Verification Example Source: https://docs.stateset.com/set/stateset-set-l2-verification-example Step-by-step inclusion verification using batch commitments. # Set L2 Verification Example This example shows how a verifier confirms that an event is included in a committed batch. ## Inputs * **Batch commitment**: On-chain root for the batch * **Event hash**: Hash of the event payload * **Merkle proof**: Proof path from the sequencer ## 1) Retrieve the Batch Commitment Fetch the batch commitment from Set L2 using the batch ID. ## 2) Get the Merkle Proof Request the Merkle proof for the event from the sequencer. ## 3) Recompute the Root Use the event hash and proof path to recompute the Merkle root locally. ## 4) Compare On-Chain Root If the recomputed root matches the on-chain root, the event is included in the batch. ## Next Steps After inclusion, verify policy compliance using the proof metadata anchored on Set L2. ## Related Documentation * [Set L2 Verification](/stateset-set-l2-verification) * [Set L2 Overview](/stateset-set-l2) # Smart Agents: Transacting with USDC on StateSet Source: https://docs.stateset.com/smart-agents-usdc-guide Complete guide for autonomous agents to execute USDC transactions on StateSet Commerce Network # Smart Agents: USDC Transactions on StateSet Commerce Network ## Overview Smart agents represent the next evolution of commerce automation. On StateSet Commerce Network, autonomous agents can execute USDC transactions programmatically, enabling automated purchasing, payment processing, and financial operations without human intervention. This guide covers everything you need to build and deploy smart agents that can transact in USDC on StateSet, from wallet setup to advanced multi-agent coordination. ## Why Smart Agents on StateSet? ### Native USDC Integration * **No Bridge Risk**: Native USDC eliminates cross-chain vulnerabilities * **Low Latency**: Sub-second transaction finality for agent operations * **Minimal Fees**: \~\$0.01 per transaction enables high-frequency agent activities * **No Gas Token**: Agents pay fees directly in USDC, simplifying treasury management ### Agent-Optimized Infrastructure * **Programmable Commerce**: Smart contracts designed for autonomous operations * **Event-Driven Architecture**: Real-time webhooks for agent responses * **API-First Design**: RESTful and gRPC endpoints for agent integration * **Permissionless Access**: Agents can operate 24/7 without human oversight ## Agent Architecture ### Core Components ```mermaid theme={null} graph TD A[Smart Agent] --> B[StateSet SDK] B --> C[Wallet Manager] B --> D[Transaction Engine] B --> E[Event Listener] C --> F[USDC Balance] D --> G[StateSet Network] E --> H[Webhooks/Events] ``` ### Agent Types 1. **Trading Agents**: Execute buy/sell orders based on market conditions 2. **Payment Agents**: Process automated payments and settlements 3. **Supply Chain Agents**: Manage inventory and procurement 4. **Finance Agents**: Handle invoicing, loans, and treasury operations 5. **Multi-Agent Systems**: Coordinate complex workflows across agents ## Setting Up Your Smart Agent ### 1. Agent Identity and Authentication ```typescript theme={null} import { StateSetAgent } from '@stateset/agent-sdk'; import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing'; // Generate agent wallet const mnemonic = await generateMnemonic(); const wallet = await DirectSecp256k1Wallet.fromMnemonic(mnemonic, { prefix: 'stateset', }); // Initialize agent with identity const agent = new StateSetAgent({ wallet, endpoint: 'https://rpc.stateset.network', agentConfig: { id: 'agent_001', name: 'Procurement Bot', type: 'trading', permissions: ['order.create', 'payment.execute'] } }); ``` ### 2. Wallet and Key Management ```typescript theme={null} // Secure key storage for production agents class AgentKeyManager { private kms: KeyManagementService; async initializeWallet() { // Use HSM or secure enclave for production const privateKey = await this.kms.generateKey({ algorithm: 'secp256k1', usage: ['sign', 'verify'] }); // Derive public key and address const publicKey = await this.kms.getPublicKey(privateKey); const address = deriveAddress(publicKey, 'stateset'); return { address, sign: async (message: Uint8Array) => { return this.kms.sign(privateKey, message); } }; } } ``` ### 3. USDC Balance Management ```typescript theme={null} // Monitor and manage USDC balance class USDCTreasury { constructor(private agent: StateSetAgent) {} async getBalance(): Promise { return await this.agent.bank.balance({ address: this.agent.address, denom: 'usdc' }); } async ensureSufficientBalance(amount: string) { const balance = await this.getBalance(); if (balance.amount < amount) { // Trigger refill from treasury or alert await this.requestRefill(amount - balance.amount); } } async requestRefill(deficit: string) { // Implement treasury management logic await this.agent.events.emit({ type: 'treasury.refill_required', data: { deficit, agent_id: this.agent.id } }); } } ``` ## Core Agent Operations ### 1. Executing USDC Payments ```typescript theme={null} // Autonomous payment execution class PaymentAgent { async executePayment(params: PaymentParams) { try { // Pre-flight checks await this.validatePayment(params); await this.ensureBalance(params.amount); // Execute payment const result = await this.agent.orders.pay({ order_id: params.orderId, payment_method: { type: 'usdc', amount: { value: params.amount, denom: 'usdc' } }, memo: `Agent payment: ${this.agent.id}` }); // Post-payment actions await this.logTransaction(result); await this.updateInventory(params.orderId); return result; } catch (error) { await this.handlePaymentError(error); } } } ``` ### 2. Automated Order Creation and Payment ```typescript theme={null} // End-to-end order automation class ProcurementAgent { async createAndPayOrder(supplier: Supplier, items: Item[]) { // Create order const order = await this.agent.orders.create({ supplier_id: supplier.id, items: items.map(item => ({ product_id: item.id, quantity: item.quantity, unit_price: item.price })), payment_terms: 'immediate', delivery_address: this.config.warehouse_address }); // Calculate total with tax and fees const total = await this.calculateTotal(order); // Execute payment atomically const payment = await this.agent.transactions.execute({ messages: [{ type: 'order/pay', order_id: order.id, amount: total }], fee: { amount: '0.01', denom: 'usdc' }, memo: `Auto-payment for order ${order.id}` }); return { order, payment }; } } ``` ### 3. Multi-Signature Agent Operations ```typescript theme={null} // Multi-agent approval workflows class MultiSigAgent { private signers: AgentSigner[]; private threshold: number; async executeMultiSigPayment(params: PaymentParams) { // Create multi-sig transaction const tx = await this.createTransaction(params); // Collect signatures from agent network const signatures = await Promise.all( this.signers.map(async (signer) => { const decision = await signer.evaluateTransaction(tx); if (decision.approve) { return signer.sign(tx); } return null; }) ); // Check threshold const validSigs = signatures.filter(sig => sig !== null); if (validSigs.length >= this.threshold) { // Broadcast transaction return await this.agent.broadcast(tx, validSigs); } throw new Error('Insufficient signatures'); } } ``` ## Event-Driven Agent Behavior ### 1. Webhook Integration ```typescript theme={null} // React to on-chain events class EventDrivenAgent { constructor(private agent: StateSetAgent) { this.setupEventListeners(); } private setupEventListeners() { // Subscribe to order events this.agent.events.subscribe({ type: 'order.created', filter: { supplier_id: this.config.supplier_id }, handler: async (event) => { await this.handleNewOrder(event); } }); // Subscribe to payment requests this.agent.events.subscribe({ type: 'invoice.created', filter: { recipient: this.agent.address }, handler: async (event) => { await this.processInvoice(event); } }); } async handleNewOrder(event: OrderEvent) { // Analyze order const analysis = await this.analyzeOrder(event.order); if (analysis.shouldAccept) { // Auto-accept and process await this.agent.orders.accept({ order_id: event.order.id, estimated_delivery: analysis.deliveryDate }); } } } ``` ### 2. Real-time Market Response ```typescript theme={null} // Market-making agent class MarketMakerAgent { private priceFeeds: PriceFeed[]; async monitorAndTrade() { // Subscribe to price updates this.priceFeeds.forEach(feed => { feed.subscribe(async (price) => { const opportunity = await this.findArbitrage(price); if (opportunity) { await this.executeTrade(opportunity); } }); }); } async executeTrade(opportunity: ArbitrageOpp) { // Create atomic swap const swap = await this.agent.dex.swap({ offer: { amount: opportunity.inputAmount, denom: 'usdc' }, ask: { amount: opportunity.expectedOutput, denom: opportunity.outputDenom }, slippage: 0.005, // 0.5% deadline: Date.now() + 60000 // 1 minute }); return swap; } } ``` ## Advanced Agent Patterns ### 1. Agent Coordination Networks ```typescript theme={null} // Coordinate multiple agents for complex workflows class AgentOrchestrator { private agents: Map; async executeWorkflow(workflow: Workflow) { const dag = this.buildDAG(workflow); // Execute tasks in topological order for (const stage of dag.stages) { await Promise.all( stage.tasks.map(async (task) => { const agent = this.agents.get(task.agentId); return agent.execute(task); }) ); } } async negotiateTerms(buyers: Agent[], sellers: Agent[]) { // Implement automated negotiation protocol const bids = await Promise.all( buyers.map(b => b.submitBid()) ); const asks = await Promise.all( sellers.map(s => s.submitAsk()) ); // Match orders using smart routing return this.matchOrders(bids, asks); } } ``` ### 2. Self-Funding Agents ```typescript theme={null} // Agent that manages its own revenue class AutonomousServiceAgent { private revenue: string = '0'; private expenses: string = '0'; async provideService(request: ServiceRequest) { // Quote price based on resource usage const quote = await this.calculateQuote(request); // Request payment const invoice = await this.agent.invoices.create({ amount: quote.total, denom: 'usdc', due_date: Date.now() + 3600000, // 1 hour services: quote.breakdown }); // Wait for payment const payment = await this.waitForPayment(invoice.id); // Execute service const result = await this.executeService(request); // Update financials this.revenue = addAmount(this.revenue, payment.amount); return result; } async manageOperatingExpenses() { // Pay for compute resources if (this.needsMoreCompute()) { await this.purchaseCompute(); } // Distribute profits if (this.revenue > this.targetReserve) { await this.distributeProfit(); } } } ``` ### 3. Risk Management ```typescript theme={null} // Implement risk controls for agent operations class RiskManagedAgent { private riskLimits: RiskLimits; private exposureTracker: ExposureTracker; async executeWithRiskControl(operation: Operation) { // Check exposure limits const currentExposure = await this.exposureTracker.calculate(); const projectedExposure = currentExposure + operation.amount; if (projectedExposure > this.riskLimits.maxExposure) { throw new Error('Exposure limit exceeded'); } // Check velocity limits const recentVolume = await this.getRecentVolume(); if (recentVolume + operation.amount > this.riskLimits.dailyLimit) { throw new Error('Daily limit exceeded'); } // Execute with circuit breaker return await this.circuitBreaker.execute(async () => { const result = await operation.execute(); await this.exposureTracker.update(operation); return result; }); } } ``` ## Security Best Practices ### 1. Key Security ```typescript theme={null} // Secure key management for agents class SecureAgentWallet { // Never store private keys in code or environment variables static async initialize() { // Use hardware security modules const hsm = await HSM.connect({ endpoint: process.env.HSM_ENDPOINT, credentials: await getHSMCredentials() }); // Generate key in HSM const keyId = await hsm.generateKey({ algorithm: 'secp256k1', extractable: false }); return new SecureAgentWallet(hsm, keyId); } async sign(message: Uint8Array): Promise { // Sign within HSM, key never leaves secure enclave return await this.hsm.sign(this.keyId, message); } } ``` ### 2. Transaction Validation ```typescript theme={null} // Validate all transactions before execution class TransactionValidator { async validate(tx: Transaction): Promise { const checks = await Promise.all([ this.checkWhitelist(tx.recipient), this.checkAmount(tx.amount), this.checkFrequency(tx.sender), this.scanForAnomalies(tx) ]); return { valid: checks.every(c => c.passed), issues: checks.filter(c => !c.passed) }; } private async checkWhitelist(address: string) { // Only transact with verified addresses return this.whitelist.includes(address); } private async scanForAnomalies(tx: Transaction) { // ML-based anomaly detection const score = await this.anomalyDetector.score(tx); return score < this.threshold; } } ``` ### 3. Monitoring and Alerting ```typescript theme={null} // Real-time monitoring for agent health class AgentMonitor { async setupMonitoring() { // Track key metrics this.metrics.gauge('usdc_balance', async () => { return await this.agent.getBalance(); }); this.metrics.counter('transactions_total'); this.metrics.histogram('transaction_amount'); // Set up alerts this.alerts.rule({ name: 'low_balance', condition: 'usdc_balance < 100', action: async () => { await this.notifyOps('Agent balance critically low'); await this.pauseAgent(); } }); // Audit logging this.agent.on('transaction', async (tx) => { await this.auditLog.record({ timestamp: Date.now(), agent_id: this.agent.id, action: 'transaction', details: tx, signature: await this.sign(tx) }); }); } } ``` ## Testing Your Agent ### 1. Unit Testing ```typescript theme={null} // Test agent behavior in isolation describe('PaymentAgent', () => { let agent: PaymentAgent; let mockNetwork: MockStateSetNetwork; beforeEach(() => { mockNetwork = new MockStateSetNetwork(); agent = new PaymentAgent({ network: mockNetwork, wallet: MockWallet.generate() }); }); test('should execute payment within limits', async () => { // Arrange const order = mockNetwork.createOrder({ amount: '50.00', status: 'pending' }); // Act const result = await agent.payOrder(order.id); // Assert expect(result.success).toBe(true); expect(mockNetwork.getOrder(order.id).status).toBe('paid'); }); test('should reject payment above limit', async () => { // Arrange const order = mockNetwork.createOrder({ amount: '10000.00', status: 'pending' }); // Act & Assert await expect(agent.payOrder(order.id)) .rejects.toThrow('Payment exceeds agent limit'); }); }); ``` ### 2. Integration Testing ```typescript theme={null} // Test against StateSet testnet describe('Agent Integration', () => { let agent: StateSetAgent; beforeAll(async () => { agent = await StateSetAgent.connect({ endpoint: 'https://testnet-rpc.stateset.network', wallet: await TestWallet.fromFaucet() }); }); test('end-to-end order flow', async () => { // Create test order const order = await agent.orders.create({ items: [{ product_id: 'test_001', quantity: 1 }], payment_method: 'usdc' }); // Execute payment const payment = await agent.orders.pay({ order_id: order.id, amount: order.total }); // Verify on-chain const onChainOrder = await agent.orders.get(order.id); expect(onChainOrder.payment_status).toBe('paid'); expect(onChainOrder.payment_tx).toBe(payment.tx_hash); }); }); ``` ### 3. Simulation Testing ```typescript theme={null} // Simulate agent behavior under various conditions class AgentSimulator { async runSimulation(config: SimulationConfig) { const agents = await this.spawnAgents(config.agentCount); const market = new SimulatedMarket(config.marketConditions); // Run simulation const results = await this.simulate({ agents, market, duration: config.duration, scenarios: config.scenarios }); // Analyze results return { totalVolume: results.reduce((sum, r) => sum + r.volume, 0), successRate: results.filter(r => r.success).length / results.length, averageLatency: this.calculateAvgLatency(results), profitability: this.calculateProfitability(results) }; } } ``` ## API Reference ### Agent-Specific Endpoints ```typescript theme={null} // Initialize agent session POST /v1/agents/session { "agent_id": "agent_001", "signature": "0x...", "permissions": ["order.create", "payment.execute"] } // Execute batch operations POST /v1/agents/batch { "agent_id": "agent_001", "operations": [ { "type": "order.create", "params": { ... } }, { "type": "payment.execute", "params": { ... } } ], "atomic": true } // Query agent transactions GET /v1/agents/{agent_id}/transactions ?start_time=2024-01-01T00:00:00Z &end_time=2024-01-31T23:59:59Z &status=success // Subscribe to events WebSocket /v1/agents/{agent_id}/events { "subscribe": [ "order.matched", "payment.received", "balance.low" ] } ``` ## Common Patterns and Examples ### 1. Supply Chain Automation ```typescript theme={null} // Automated inventory replenishment class InventoryAgent { async monitorAndReplenish() { const inventory = await this.getInventoryLevels(); for (const item of inventory) { if (item.quantity <= item.reorderPoint) { // Find best supplier const suppliers = await this.findSuppliers(item.sku); const bestOffer = await this.negotiatePrice(suppliers, item); // Create and pay order const order = await this.createOrder(bestOffer); await this.payWithUSDC(order); // Update tracking await this.updateInventoryForecast(item, order); } } } } ``` ### 2. DeFi Integration ```typescript theme={null} // Yield optimization agent class YieldAgent { async optimizeYield(balance: string) { // Find best lending rates const opportunities = await this.scanLendingMarkets(); // Calculate optimal allocation const allocation = this.optimizer.allocate(balance, opportunities); // Execute lending positions for (const position of allocation) { await this.lendUSDC({ protocol: position.protocol, amount: position.amount, duration: position.duration }); } // Monitor and rebalance this.scheduleRebalancing(allocation); } } ``` ### 3. Cross-Border Payments ```typescript theme={null} // International payment agent class CrossBorderAgent { async executePayment(payment: InternationalPayment) { // Compliance checks await this.runComplianceChecks(payment); // Convert to USDC const usdcAmount = await this.convertToUSDC( payment.amount, payment.sourceCurrency ); // Execute transfer const transfer = await this.agent.ibc.transfer({ channel: payment.destinationChain, recipient: payment.recipient, amount: usdcAmount, memo: payment.reference }); // Notify recipient await this.notifyRecipient(transfer); return transfer; } } ``` ## Troubleshooting ### Common Issues 1. **Insufficient Balance** ```typescript theme={null} // Implement automatic refill if (error.code === 'insufficient_funds') { await this.treasury.requestRefill(requiredAmount); // Retry after refill } ``` 2. **Rate Limiting** ```typescript theme={null} // Implement exponential backoff async executeWithRetry(operation: () => Promise) { for (let i = 0; i < MAX_RETRIES; i++) { try { return await operation(); } catch (error) { if (error.code === 'rate_limited') { await sleep(Math.pow(2, i) * 1000); continue; } throw error; } } } ``` 3. **Network Failures** ```typescript theme={null} // Implement circuit breaker class CircuitBreaker { async execute(operation: () => Promise) { if (this.isOpen()) { throw new Error('Circuit breaker is open'); } try { const result = await operation(); this.recordSuccess(); return result; } catch (error) { this.recordFailure(); if (this.shouldOpen()) { this.open(); } throw error; } } } ``` ## Resources and Support ### Documentation * [StateSet API Reference](/api-reference) * [USDC Integration Guide](/usdc) * [Smart Contract Documentation](https://docs.stateset.network) ### SDKs and Tools * [TypeScript SDK](https://github.com/stateset/stateset-js) * [Python SDK](https://github.com/stateset/stateset-py) * [Go SDK](https://github.com/stateset/stateset-go) * [Agent Framework](https://github.com/stateset/agent-framework) ### Community * [Discord](https://discord.gg/stateset) - Real-time support * [GitHub Discussions](https://github.com/stateset/stateset/discussions) * [Agent Builders Forum](https://forum.stateset.network/c/agents) ### Support * Technical Support: [support@stateset.network](mailto:support@stateset.network) * Agent Development: [agents@stateset.network](mailto:agents@stateset.network) * Enterprise Solutions: [enterprise@stateset.network](mailto:enterprise@stateset.network) ## Conclusion Smart agents on StateSet Commerce Network represent a paradigm shift in how commerce operates. With native USDC integration, low fees, and powerful infrastructure, agents can execute complex financial operations autonomously and securely. Whether you're building simple payment bots or sophisticated multi-agent systems, StateSet provides the foundation for the autonomous commerce economy. Start building your agent today and join the future of programmable commerce. Ready to get started? [Create your first agent →](https://app.stateset.network/agents) # Agentic Commerce Protocol Source: https://docs.stateset.com/stateset-acp/stateset-acp Enable AI agents to complete checkout and delegated payments inside conversational interfaces. # Agentic Commerce Protocol (ACP) ACP enables AI agents to complete checkout and delegated payments inside conversational interfaces while keeping your commerce stack in control. It provides a structured protocol for agents to collect order intent, authorize payments, and create orders through deterministic, auditable workflows. ## How ACP Works ``` User (chat/voice) → AI Agent → ACP Handler → Order Created │ │ ├── Collects intent ├── Validates order ├── Confirms items ├── Authorizes payment └── Gets authorization └── Syncs to commerce platform ``` 1. **Agent collects intent** — The AI agent gathers order details and payment authorization through natural conversation. 2. **ACP handler validates** — The handler validates the order against your catalog, pricing rules, and inventory. 3. **Payment authorized** — Scoped payment authorization ensures the agent can only charge approved amounts. 4. **Order created** — The order is created in your commerce platform via the Sync Server. ## Key Concepts | Concept | Description | | ----------------- | --------------------------------------------------------------------- | | **Intent** | A structured representation of what the customer wants to buy | | **Authorization** | Scoped permission for the agent to charge a specific amount | | **Handler** | Server-side component that validates and executes commerce operations | | **Binding** | Connection between the ACP handler and your commerce platform | ## Why This Design * **Deterministic checkout** — Orders are validated server-side, never by the LLM. * **Scoped payments** — Agents can only charge amounts the customer explicitly authorizes. * **Auditable** — Every step is logged with full traceability. * **Platform-agnostic** — Works with any commerce backend through bindings. ## When to Use ACP * **Conversational checkout** — Let customers buy through chat or voice interfaces. * **Delegated payments** — Authorize agents to make purchases on behalf of users with spending limits. * **Unified agent workflows** — Single protocol for multiple AI assistants (ChatGPT, custom agents, voice bots). * **B2B ordering** — Streamline wholesale and recurring orders through conversational interfaces. ## Quickstart ```typescript theme={null} import { ACPHandler } from '@stateset/acp'; const handler = new ACPHandler({ apiKey: process.env.STATESET_API_KEY, catalogBinding: 'shopify', paymentBinding: 'stripe', }); // Process an agent's checkout request const order = await handler.processCheckout({ items: [ { sku: 'WIDGET-001', quantity: 2 }, { sku: 'GADGET-005', quantity: 1 }, ], payment: { method: 'authorized_token', token: 'pay_auth_abc123', }, shipping: { address: '123 Main St, New York, NY 10001', method: 'standard', }, }); ``` ## Further Reading * [ACP Overview](/stateset-acp-overview) * [ACP Quickstart](/stateset-acp-quickstart) * [ACP Endpoints](/stateset-acp-endpoints) * [ACP Async Processing](/stateset-acp-async-processing) * [ACP Routing](/stateset-acp-routing) * [ACP Schemas](/stateset-acp-schemas) * [Agentic Commerce Checkout Guide](/agentic-commerce/agentic-commerce-checkout-guide) # ACP Async Processing Source: https://docs.stateset.com/stateset-acp/stateset-acp-async-processing Queue, monitor, and retrieve ACP order results. # ACP Async Processing Use async processing for high volume or time-sensitive workflows. ACP returns a job ID you can poll for completion. ## Submit an Async Order ```bash theme={null} curl -X POST https://your-server.com/v1/tenants/{tenant_id}/acp/orders/async \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ ... order data ... }' ``` ## Response ```json theme={null} { "data": { "jobId": "550e8400-e29b-41d4-a716-446655440000", "status": "queued", "message": "Order ORD-1001 accepted for processing" } } ``` ## Check Status ```bash theme={null} curl https://your-server.com/v1/tenants/{tenant_id}/jobs/{jobId} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Job Status Response ```json theme={null} { "data": { "jobId": "550e8400-e29b-41d4-a716-446655440000", "jobType": "acp_order_process", "state": "succeeded", "createdAt": "2024-01-15T10:30:00Z", "startedAt": "2024-01-15T10:30:01Z", "finishedAt": "2024-01-15T10:30:03Z", "result": { "orderId": "agent-order-001", "orderNumber": "ORD-1001", "statesetOrderId": "550e8400-e29b-41d4-a716-446655440000", "fulfillment": { "provider": "dcl", "success": true }, "erp": { "provider": "netsuite", "success": true, "netsuiteId": "12345" } } } } ``` # ACP API Endpoints Source: https://docs.stateset.com/stateset-acp/stateset-acp-endpoints Order submission endpoints and request patterns. # ACP API Endpoints ACP exposes endpoints for synchronous, async, and batch order submission. ## Endpoints | Method | Endpoint | Description | | ------ | ------------------------------------------ | --------------------------- | | POST | `/v1/tenants/{tenant_id}/acp/orders` | Process order synchronously | | POST | `/v1/tenants/{tenant_id}/acp/orders/async` | Process order in background | | POST | `/v1/tenants/{tenant_id}/acp/orders/batch` | Process multiple orders | ## Authentication Use either header for API key authentication: ``` Authorization: Bearer your-api-key-here ``` ``` X-API-Key: your-api-key-here ``` ## Example: Basic Order Submission ```bash theme={null} curl -X POST https://your-server.com/v1/tenants/{tenant_id}/acp/orders \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "orderId": "agent-order-001", "orderNumber": "ORD-1001", "customer": { "email": "customer@example.com", "firstName": "John", "lastName": "Doe" }, "shippingAddress": { "name": "John Doe", "address1": "123 Main Street", "city": "San Francisco", "state": "CA", "postalCode": "94102", "countryCode": "US" }, "lineItems": [ { "sku": "WIDGET-001", "title": "Blue Widget", "quantity": 2, "price": 29.99 } ] }' ``` # ACP Overview Source: https://docs.stateset.com/stateset-acp/stateset-acp-overview Agentic Commerce Protocol concepts, flow, and integration points. # ACP Overview The Agentic Commerce Protocol (ACP) lets AI agents place orders into your commerce stack with a single, deterministic API call. ## What ACP Enables * Conversational commerce across ChatGPT, Claude, and custom agents * Automated purchasing and reorders * Unified API across channels and assistants ## High-Level Flow 1. Agent collects customer intent and order details 2. Agent submits an ACP order request 3. The Sync Server validates and routes the order 4. Downstream systems (fulfillment/ERP) receive the order ## Core Components * **ACP API**: Order submission endpoints * **Sync Server**: Validation, routing, and orchestration * **Fulfillment/ERP**: Execution and tracking ## Related Documentation * [ACP Guide](/stateset-sync-server/ACP_GUIDE) * [ACP Quickstart](/stateset-acp-quickstart) * [Agentic Commerce Checkout Guide](/agentic-commerce/agentic-commerce-checkout-guide) # StateSet ACP Quickstart Source: https://docs.stateset.com/stateset-acp/stateset-acp-quickstart Run the ACP handler and validate a basic checkout flow. # StateSet ACP Quickstart This quickstart gets the ACP handler running and points to the core checkout flow. ## 1) Build and run ```bash theme={null} cd stateset-acp-handler cargo build --release cargo run --release ``` ## 2) Review the ACP flow ACP supports agentic checkout and delegated payments. The full flow and endpoint details live in the ACP guide: * [ACP Guide](/stateset-sync-server/ACP_GUIDE) ## 3) Validate with the handler The handler README includes request/response examples for each endpoint: * [ACP Handler README](/stateset-acp-handler/README) # ACP Routing Options Source: https://docs.stateset.com/stateset-acp/stateset-acp-routing Control fulfillment, ERP, and record creation behavior. # ACP Routing Options ACP lets you control where orders are routed using the `routing` object on the request. ## Default (Full Integration) ```json theme={null} { "routing": { "sendToFulfillment": true, "sendToErp": true, "createInStateset": true } } ``` ## Fulfillment Only ```json theme={null} { "routing": { "sendToFulfillment": true, "sendToErp": false, "createInStateset": true } } ``` ## Record Only ```json theme={null} { "routing": { "sendToFulfillment": false, "sendToErp": false, "createInStateset": true } } ``` ## Specific Fulfillment Provider ```json theme={null} { "routing": { "fulfillmentProvider": "dcl", "dclLocation": "LA" } } ``` ## Related Documentation * [ACP Request Schemas](/stateset-acp-schemas) * [ACP Guide](/stateset-sync-server/ACP_GUIDE) # ACP Request Schemas Source: https://docs.stateset.com/stateset-acp/stateset-acp-schemas Request objects for ACP order submission. # ACP Request Schemas Use these request objects when submitting orders through the ACP API. ## AcpOrderRequest | Field | Type | Required | Description | | ----------------- | ------------- | -------- | ------------------------------------------ | | `orderId` | string | Yes | Unique order identifier from source system | | `orderNumber` | string | Yes | Display order number | | `source` | string | No | Source system (default: "agent") | | `customer` | Customer | Yes | Customer information | | `shippingAddress` | Address | Yes | Shipping destination | | `billingAddress` | Address | No | Billing address (defaults to shipping) | | `lineItems` | LineItem\[] | Yes | Order line items (min 1) | | `createdAt` | datetime | No | Order timestamp (default: now) | | `tags` | string\[] | No | Tags for categorization | | `shippingMethod` | string | No | Requested shipping method | | `notes` | string | No | Order notes/instructions | | `routing` | RoutingConfig | No | Control where order is sent | | `metadata` | object | No | Additional custom data | ## Customer | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------- | | `id` | string | No | Customer ID in source system | | `email` | string | Yes | Customer email | | `firstName` | string | Yes | First name | | `lastName` | string | Yes | Last name | | `phone` | string | No | Phone number | | `netsuiteId` | string | No | NetSuite customer internal ID | ## Address | Field | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------------- | | `name` | string | Yes | Full name | | `company` | string | No | Company name | | `address1` | string | Yes | Street address line 1 | | `address2` | string | No | Street address line 2 | | `city` | string | Yes | City | | `state` | string | Yes | State/province code | | `postalCode` | string | Yes | ZIP/postal code | | `countryCode` | string | Yes | 2-letter country code (e.g., "US") | | `phone` | string | No | Phone number | ## LineItem | Field | Type | Required | Description | | ---------------- | ------ | -------- | ----------------------------- | | `sku` | string | Yes | Product SKU | | `title` | string | Yes | Product title | | `quantity` | number | Yes | Quantity (must be > 0) | | `price` | number | Yes | Unit price | | `variantId` | string | No | Variant ID from source system | | `netsuiteItemId` | string | No | NetSuite item internal ID | | `weight` | number | No | Weight in pounds | ## RoutingConfig | Field | Type | Default | Description | | --------------------- | ------- | ------- | ------------------------------- | | `sendToFulfillment` | boolean | true | Send to DCL/Cart.com | | `sendToErp` | boolean | true | Send to NetSuite | | `createInStateset` | boolean | true | Create in StateSet | | `fulfillmentProvider` | string | "auto" | "dcl", "cart", or "auto" | | `dclLocation` | string | null | Override DCL warehouse location | # StateSet: The Agentic Operating System Source: https://docs.stateset.com/stateset-agentic-os The world's first operating system for autonomous agents with native USDC wallets and cross-web state management # StateSet: The Agentic Operating System for the World StateSet Commerce Network represents a paradigm shift beyond traditional blockchain infrastructure—it's the world's first **Agentic Operating System**. An Agentic OS is a platform that enables autonomous AI agents to operate independently, manage state across the web, and execute tasks with native financial capabilities. Just as iOS and Android enabled mobile computing, StateSet enables autonomous agent computing at planetary scale, with native USDC wallets, cross-web state management via MCP protocol, and the ability to execute complex tasks across the entire internet. ## Table of Contents * [The Agent Revolution](#the-agent-revolution) * [From Apps to Agents](#from-apps-to-agents) * [The Need for an Agentic OS](#the-need-for-an-agentic-os) * [Agentic OS Architecture](#agentic-os-architecture) * [System Overview](#system-overview) * [Core OS Components](#core-os-components) * [Agent Runtime Engine](#agent-runtime-engine) * [Native USDC Wallet System](#native-usdc-wallet-system) * [MCP Protocol Integration](#mcp-protocol-integration) * [MCP Protocol: Cross-Web Agent Coordination](#mcp-protocol-cross-web-agent-coordination) * [Model Context Protocol Integration](#model-context-protocol-integration) * [Cross-Platform Agent Actions](#cross-platform-agent-actions) * [MCP Service Registry](#mcp-service-registry) * [Autonomous Agent Types](#autonomous-agent-types) * [Commerce Agents](#commerce-agents) * [Procurement Agent](#procurement-agent) * [Sales Agent](#sales-agent) * [Financial Agents](#financial-agents) * [Treasury Agent](#treasury-agent) * [Invoice Financing Agent](#invoice-financing-agent) * [Operations Agents](#operations-agents) * [Supply Chain Agent](#supply-chain-agent) * [Compliance Agents](#compliance-agents) * [Regulatory Compliance Agent](#regulatory-compliance-agent) * [Agent Marketplace & Orchestration](#agent-marketplace-orchestration) * [Agent Marketplace](#agent-marketplace) * [Agent Orchestration Engine](#agent-orchestration-engine) * [Agent Economics & Tokenomics](#agent-economics-tokenomics) * [Agent Revenue Models](#agent-revenue-models) * [Self-Sustaining Agent Economies](#self-sustaining-agent-economies) * [Agent Security & Governance](#agent-security-governance) * [Multi-Layered Security Architecture](#multi-layered-security-architecture) * [Agent Governance Framework](#agent-governance-framework) * [Agent Development Platform](#agent-development-platform) * [StateSet Agent SDK](#stateset-agent-sdk) * [Agent Testing Framework](#agent-testing-framework) * [Cross-Platform Agent Interoperability](#cross-platform-agent-interoperability) * [Universal Agent Identity](#universal-agent-identity) * [Agent-to-Agent Communication Protocol](#agent-to-agent-communication-protocol) * [Agent Analytics & Performance](#agent-analytics-performance) * [Real-Time Agent Dashboard](#real-time-agent-dashboard) * [Agent Network Analytics](#agent-network-analytics) * [The Future of Agentic Commerce](#the-future-of-agentic-commerce) * [2024-2030 Roadmap](#2024-2030-roadmap) * [Vision: The Agentic Economy](#vision-the-agentic-economy) * [Agent-to-Agent Economy Examples](#agent-to-agent-economy-examples) * [Get Started with StateSet Agents](#get-started-with-stateset-agents) * [Quick Start: Deploy Your First Agent](#quick-start-deploy-your-first-agent) * [Agent Templates](#agent-templates) * [Enterprise Integration](#enterprise-integration) ## 🤖 The Agent Revolution ### From Apps to Agents We're witnessing the transition from the **Application Economy** to the **Agent Economy**:

📱 Application Economy (2007-2024)

  • • Humans operate applications
  • • Manual workflows and processes
  • • Limited to single-platform actions
  • • Requires human attention and input
  • • Static, reactive systems

🤖 Agent Economy (2024+)

  • • Agents operate autonomously
  • • Automated end-to-end workflows
  • • Cross-platform, cross-web actions
  • • 24/7 autonomous operation
  • • Dynamic, proactive systems
### The Need for an Agentic OS Current AI systems are **stateless** and **financially isolated**—they can generate text and images but cannot: * ❌ Own and manage digital assets * ❌ Execute financial transactions * ❌ Persist state across sessions * ❌ Coordinate with other agents * ❌ Make changes across multiple platforms * ❌ Operate autonomously 24/7 **StateSet solves this by providing:** * ✅ **Native USDC wallets** for every agent * ✅ **Persistent state management** on blockchain * ✅ **Cross-web coordination** via MCP protocol * ✅ **Multi-agent orchestration** frameworks * ✅ **Autonomous transaction capabilities** * ✅ **Global compliance and security** ## 🏗️ Agentic OS Architecture ### System Overview ```mermaid theme={null} graph TB subgraph "Agent Layer" A1[Procurement Agents] A2[Trading Agents] A3[Customer Service Agents] A4[Logistics Agents] A5[Compliance Agents] end subgraph "StateSet Agentic OS" OS1[Agent Runtime Engine] OS2[Wallet Management System] OS3[State Synchronization] OS4[MCP Protocol Gateway] OS5[Cross-Agent Messaging] OS6[Resource Scheduler] end subgraph "Financial Infrastructure" FI1[Native USDC Wallets] FI2[Multi-Signature Controls] FI3[Treasury Management] FI4[Risk Management] FI5[Compliance Engine] end subgraph "External Integrations" EI1[Web Applications via MCP] EI2[Enterprise Systems] EI3[Blockchain Networks] EI4[Government APIs] EI5[IoT Devices] end A1 --> OS1 A2 --> OS2 A3 --> OS3 A4 --> OS4 A5 --> OS5 OS1 --> FI1 OS2 --> FI2 OS3 --> FI3 OS4 --> FI4 OS5 --> FI5 FI1 --> EI1 FI2 --> EI2 FI3 --> EI3 FI4 --> EI4 FI5 --> EI5 ``` ### Core OS Components #### 1. **Agent Runtime Engine** ```typescript theme={null} // Import necessary types (assuming these are defined elsewhere in the codebase) import { AgentConfig, AgentInstance, Task, TaskExecution, Orchestration, Resources, Allocation, PerformanceMetrics, SecurityPolicy, Compliance, AuditLog } from '@stateset/types'; interface AgentOS { // Core agent lifecycle management spawn(agentConfig: AgentConfig): AgentInstance; schedule(agentId: string, task: Task): TaskExecution; coordinate(agents: AgentInstance[]): Orchestration; // Resource management allocateResources(agentId: string, resources: Resources): Allocation; monitorPerformance(agentId: string): PerformanceMetrics; // Security and governance enforcePolicy(agentId: string, policy: SecurityPolicy): Compliance; auditActivity(agentId: string): AuditLog; } ``` #### 2. **Native USDC Wallet System** ```typescript theme={null} interface AgentWallet { address: string; balance: { usdc: string; state: string; }; // Transaction capabilities send(recipient: string, amount: string, memo?: string): Transaction; receive(sender: string, amount: string): Transaction; // Multi-signature controls requireApproval(threshold: number, signers: string[]): MultiSigConfig; // Cross-chain capabilities bridgeToChain(chain: string, amount: string): CrossChainTransfer; // DeFi integrations stake(amount: string, validator: string): StakingPosition; lend(amount: string, protocol: string): LendingPosition; } ``` #### 3. **MCP Protocol Integration** ```typescript theme={null} interface MCPGateway { // Cross-web state management connectToService(service: WebService): MCPConnection; syncState(agentId: string, state: AgentState): StateSyncResult; // Tool execution across platforms executeRemoteFunction( service: string, function: string, params: any ): ExecutionResult; // Event coordination subscribeToEvents(service: string, events: string[]): EventSubscription; publishEvent(event: AgentEvent): PublishResult; } ``` ## 🌐 MCP Protocol: Cross-Web Agent Coordination ### Model Context Protocol Integration StateSet integrates deeply with MCP (Model Context Protocol) to enable agents to make state changes across the entire web: ```mermaid theme={null} graph LR subgraph "StateSet Agent" SA[Agent Core] SW[USDC Wallet] SS[State Manager] end subgraph "MCP Protocol Layer" MCP1[MCP Client] MCP2[Protocol Router] MCP3[State Synchronizer] end subgraph "External Systems" ES1[Enterprise CRM] ES2[E-commerce Platform] ES3[Cloud Services] ES4[Social Media APIs] ES5[Government Portals] end SA --> MCP1 SW --> MCP2 SS --> MCP3 MCP1 --> ES1 MCP2 --> ES2 MCP3 --> ES3 MCP1 --> ES4 MCP2 --> ES5 ``` ### Cross-Platform Agent Actions ```typescript theme={null} // Agent performing complex cross-platform workflow class CrossPlatformAgent extends StateSetAgent { async executeGlobalProcurement(requirement: ProcurementReq) { // 1. Search for suppliers across multiple platforms const suppliers = await Promise.all([ this.mcp.alibaba.searchSuppliers(requirement), this.mcp.thomasnet.findManufacturers(requirement), this.mcp.linkedin.identifyContacts(requirement.category) ]); // 2. Analyze and negotiate via multiple channels const negotiations = await Promise.all( suppliers.map(async (supplier) => { // Send RFQ via supplier's preferred platform const rfq = await this.mcp[supplier.platform].sendRFQ({ supplier: supplier.id, requirement, terms: this.negotiationParams }); // Track responses across platforms return this.mcp.trackNegotiation(rfq.id); }) ); // 3. Execute payment via StateSet wallet const bestOffer = this.selectBestOffer(negotiations); const payment = await this.wallet.pay({ recipient: bestOffer.supplier.walletAddress, amount: bestOffer.price, reference: bestOffer.orderId }); // 4. Update systems across all platforms await Promise.all([ this.mcp.erp.createPurchaseOrder(bestOffer), this.mcp.accounting.recordExpense(payment), this.mcp.logistics.scheduleDelivery(bestOffer.delivery), this.mcp.slack.notifyTeam(`Order ${bestOffer.orderId} placed`) ]); return { orderId: bestOffer.orderId, supplier: bestOffer.supplier, payment: payment.txHash, estimatedDelivery: bestOffer.delivery.eta }; } } ``` ### MCP Service Registry ```typescript theme={null} // Registry of MCP-enabled services const mcpServiceRegistry = { enterprise: { salesforce: { capabilities: ['crm_management', 'lead_processing', 'opportunity_tracking'], authentication: 'oauth2', rate_limits: '1000_req_per_hour' }, sap: { capabilities: ['erp_integration', 'financial_posting', 'inventory_management'], authentication: 'saml', rate_limits: '500_req_per_hour' }, microsoft365: { capabilities: ['email_automation', 'calendar_management', 'teams_integration'], authentication: 'microsoft_graph', rate_limits: '10000_req_per_hour' } }, ecommerce: { shopify: { capabilities: ['order_management', 'inventory_sync', 'customer_service'], authentication: 'api_key', rate_limits: '2000_req_per_hour' }, amazon: { capabilities: ['marketplace_operations', 'fulfillment', 'advertising'], authentication: 'aws_signature', rate_limits: '100_req_per_hour' } }, financial: { stripe: { capabilities: ['payment_processing', 'subscription_management', 'fraud_detection'], authentication: 'api_key', rate_limits: '1000_req_per_second' }, quickbooks: { capabilities: ['accounting_automation', 'invoice_management', 'tax_preparation'], authentication: 'oauth2', rate_limits: '500_req_per_hour' } } }; ``` ## 🤖 Autonomous Agent Types ### 1. **Commerce Agents** #### Procurement Agent ```typescript theme={null} class ProcurementAgent extends StateSetAgent { private inventory: InventoryManager; private suppliers: SupplierNetwork; private budget: BudgetManager; async autonomousReordering() { // Monitor inventory levels across all systems const lowStockItems = await this.inventory.getLowStockItems(); for (const item of lowStockItems) { // Find best supplier and pricing const suppliers = await this.suppliers.findSuppliers(item); const bestOffer = await this.negotiateBestPrice(suppliers, item); // Check budget approval if (await this.budget.canAfford(bestOffer.totalCost)) { // Execute purchase const order = await this.createOrder(bestOffer); await this.wallet.pay({ recipient: bestOffer.supplier.wallet, amount: bestOffer.totalCost, reference: order.id }); // Update all connected systems await this.mcp.updateSystems({ erp: { newPurchaseOrder: order }, accounting: { newExpense: bestOffer.totalCost }, warehouse: { expectedDelivery: order.delivery } }); } } } } ``` #### Sales Agent ```typescript theme={null} class SalesAgent extends StateSetAgent { async autonomousSalesFlow(lead: Lead) { // Research prospect across platforms const prospect = await this.mcp.research({ linkedin: lead.company, crunchbase: lead.company, salesforce: lead.email }); // Generate personalized outreach const message = await this.ai.generateOutreach({ prospect, context: this.salesContext, tone: 'professional' }); // Send via preferred channel await this.mcp[prospect.preferredChannel].sendMessage({ recipient: lead.email, message, trackOpens: true }); // Schedule follow-ups await this.scheduleFollowUps(lead, prospect.responsePattern); // Update CRM across all platforms await this.mcp.updateCRM({ salesforce: { newActivity: message }, hubspot: { leadScore: prospect.score }, slack: { notification: `Reached out to ${lead.company}` } }); } } ``` ### 2. **Financial Agents** #### Treasury Agent ```typescript theme={null} class TreasuryAgent extends StateSetAgent { async optimizeLiquidity() { // Monitor cash positions across all accounts const positions = await this.getGlobalCashPositions(); // Calculate optimal allocation const allocation = await this.ai.optimizeAllocation({ positions, riskProfile: this.riskParams, marketConditions: await this.getMarketData() }); // Execute rebalancing for (const move of allocation.moves) { if (move.type === 'yield_opportunity') { await this.wallet.stake({ amount: move.amount, protocol: move.protocol, duration: move.duration }); } else if (move.type === 'liquidity_provision') { await this.wallet.addLiquidity({ pool: move.pool, amount: move.amount }); } } // Report to stakeholders await this.mcp.updateDashboards({ treasury: allocation.summary, cfo: allocation.riskMetrics, board: allocation.performance }); } } ``` #### Invoice Financing Agent ```typescript theme={null} class InvoiceFinancingAgent extends StateSetAgent { async autoFactorInvoices() { // Scan for eligible invoices const invoices = await this.mcp.accounting.getUnpaidInvoices(); for (const invoice of invoices) { // Assess factoring opportunity const assessment = await this.finance.assessFactoring({ invoice, buyerCreditScore: await this.getCreditScore(invoice.buyer), currentCashNeed: await this.getCashNeed() }); if (assessment.recommend) { // Execute factoring const factoring = await this.stateset.finance.factorInvoice({ invoiceId: invoice.id, discountRate: assessment.optimalRate }); // Update financial systems await this.mcp.updateAccounting({ factoring: factoring, cashFlow: await this.recalculateCashFlow() }); } } } } ``` ### 3. **Operations Agents** #### Supply Chain Agent ```typescript theme={null} class SupplyChainAgent extends StateSetAgent { async optimizeLogistics() { // Monitor shipments across carriers const shipments = await this.mcp.logistics.getActiveShipments(); for (const shipment of shipments) { // Predict delays const delayRisk = await this.ai.predictDelay({ shipment, weather: await this.mcp.weather.getForecast(shipment.route), traffic: await this.mcp.traffic.getConditions(shipment.route) }); if (delayRisk.high) { // Find alternative routing const alternatives = await this.mcp.logistics.findAlternatives(shipment); // Execute if cost-effective if (alternatives.bestOption.costSavings > 0) { await this.wallet.pay({ recipient: alternatives.bestOption.carrier.wallet, amount: alternatives.bestOption.cost, reference: shipment.id }); // Update all stakeholders await this.mcp.notify({ customer: `Your order has been expedited`, warehouse: `Reroute shipment ${shipment.id}`, finance: `Additional logistics cost: ${alternatives.bestOption.cost}` }); } } } } } ``` ### 4. **Compliance Agents** #### Regulatory Compliance Agent ```typescript theme={null} class ComplianceAgent extends StateSetAgent { async monitorCompliance() { // Scan all transactions for compliance issues const transactions = await this.getRecentTransactions(); for (const tx of transactions) { // Real-time screening const screening = await this.stateset.compliance.screen({ transaction: tx, sanctions: ['OFAC', 'EU', 'UN'], exportControls: ['EAR', 'ITAR'], aml: true }); if (screening.flagged) { // Immediate action await this.wallet.freezeTransaction(tx.id); // Alert stakeholders await this.mcp.alert({ compliance: screening.details, legal: screening.riskAssessment, management: screening.recommendedActions }); // File required reports if (screening.requiresSAR) { await this.mcp.fincen.fileSAR({ transaction: tx, suspiciousActivity: screening.flags }); } } } } } ``` ## 🌟 Agent Marketplace & Orchestration ### Agent Marketplace ```mermaid theme={null} graph TB subgraph "Agent Marketplace" AM1[Agent Templates] AM2[Custom Agents] AM3[Agent Services] AM4[Agent Rentals] end subgraph "Agent Categories" AC1[Commerce & Sales] AC2[Finance & Trading] AC3[Operations & Logistics] AC4[Compliance & Legal] AC5[Marketing & Analytics] end subgraph "Deployment Options" DO1[Hosted Agents] DO2[On-Premise Agents] DO3[Hybrid Deployment] DO4[Edge Agents] end AM1 --> AC1 AM2 --> AC2 AM3 --> AC3 AM4 --> AC4 AC1 --> DO1 AC2 --> DO2 AC3 --> DO3 AC4 --> DO4 AC5 --> DO1 ``` ### Agent Orchestration Engine ```typescript theme={null} class AgentOrchestrator { async executeWorkflow(workflow: AgentWorkflow) { // Parse workflow DAG const dag = this.parseWorkflowDAG(workflow); // Allocate resources const resources = await this.allocateResources(dag.requiredResources); // Execute in topological order for (const stage of dag.stages) { await Promise.all( stage.tasks.map(async (task) => { const agent = this.getAgent(task.agentType); // Execute with resource constraints return this.executeWithConstraints({ agent, task, resources: resources[task.id], timeout: task.timeout, retries: task.retries }); }) ); } } async coordinateMultiAgentDecision(decision: DecisionContext) { // Gather input from specialized agents const inputs = await Promise.all([ this.financialAgent.analyzeFinancials(decision), this.complianceAgent.checkCompliance(decision), this.riskAgent.assessRisk(decision), this.operationsAgent.evaluateOperations(decision) ]); // Consensus algorithm const consensus = await this.buildConsensus(inputs); // Execute coordinated action if (consensus.approved) { return this.executeCoordinatedAction(consensus.action); } return { status: 'rejected', reason: consensus.rejectionReason }; } } ``` ## 💰 Agent Economics & Tokenomics ### Agent Revenue Models ```typescript theme={null} interface AgentEconomics { // Revenue streams revenueModels: { transactionFees: number; // % of transaction value subscriptionFees: number; // Monthly USDC fee performanceBonuses: number; // Based on KPI achievement profitSharing: number; // % of generated profits }; // Cost structure operatingCosts: { computeResources: number; // USDC per hour networkFees: number; // Transaction costs dataAccess: number; // API and data costs complianceCosts: number; // Regulatory overhead }; // Economic incentives incentives: { stakingRewards: number; // APR for staked STATE liquidityMining: number; // Rewards for providing liquidity governanceRewards: number; // Voting participation referralBonuses: number; // Agent recruitment rewards }; } ``` ### Self-Sustaining Agent Economies ```typescript theme={null} class SelfSustainingAgent extends StateSetAgent { async manageOwnEconomics() { // Calculate performance const performance = await this.calculatePerformance(); // Optimize costs if (performance.profitMargin < this.targetMargin) { await this.optimizeCosts({ reduceComputeUsage: true, negotiateBetterRates: true, improveEfficiency: true }); } // Reinvest profits if (performance.profit > this.reserveTarget) { await this.reinvestProfits({ upgradeCapabilities: performance.profit * 0.3, expandToNewMarkets: performance.profit * 0.2, increaseReserves: performance.profit * 0.5 }); } // Scale operations if (performance.demandRatio > 1.5) { await this.scaleOperations({ spawnAdditionalAgents: Math.floor(performance.demandRatio), distributeWorkload: true }); } } } ``` ## 🔐 Agent Security & Governance ### Multi-Layered Security Architecture ```mermaid theme={null} graph TB subgraph "Agent Identity Layer" AI1[DID-based Identity] AI2[Biometric Verification] AI3[Multi-Factor Auth] end subgraph "Execution Security" ES1[Sandboxed Execution] ES2[Resource Limits] ES3[Permission System] end subgraph "Financial Security" FS1[Multi-Sig Wallets] FS2[Spending Limits] FS3[Transaction Monitoring] end subgraph "Network Security" NS1[Encrypted Communication] NS2[Zero-Trust Architecture] NS3[Anomaly Detection] end AI1 --> ES1 AI2 --> ES2 AI3 --> ES3 ES1 --> FS1 ES2 --> FS2 ES3 --> FS3 FS1 --> NS1 FS2 --> NS2 FS3 --> NS3 ``` ### Agent Governance Framework ```typescript theme={null} interface AgentGovernance { // Authorization levels permissions: { financial: { maxTransactionAmount: string; dailySpendingLimit: string; approvedRecipients: string[]; multiSigRequired: boolean; }; dataAccess: { allowedAPIs: string[]; dataClassification: 'public' | 'internal' | 'confidential'; retentionPeriod: number; sharingPermissions: boolean; }; systemAccess: { allowedServices: string[]; executionLimits: ResourceLimits; schedulingPriority: number; networkAccess: NetworkPolicy; }; }; // Audit and compliance auditTrail: { logAllActions: boolean; immutableLogs: boolean; realTimeMonitoring: boolean; complianceReporting: boolean; }; // Emergency controls emergencyProcedures: { killSwitch: boolean; fundsFreezing: boolean; escalationProtocol: EscalationPolicy; incidentResponse: ResponsePlan; }; } ``` ## 🚀 Agent Development Platform ### StateSet Agent SDK ```typescript theme={null} import { StateSetAgent, AgentConfig, Task } from '@stateset/agent-sdk'; // Define agent configuration const agentConfig: AgentConfig = { id: 'procurement-agent-001', name: 'Global Procurement Agent', type: 'commerce', capabilities: [ 'supplier_management', 'price_negotiation', 'order_execution', 'compliance_checking' ], wallet: { initialBalance: '10000.00', spendingLimits: { daily: '5000.00', perTransaction: '1000.00' }, multiSigRequired: true, approvers: ['manager@company.com', 'cfo@company.com'] }, mcpConnections: [ 'salesforce', 'sap', 'alibaba', 'fedex' ], ai: { model: 'gpt-4-turbo', temperature: 0.1, maxTokens: 4000 } }; // Create and deploy agent class MyProcurementAgent extends StateSetAgent { constructor(config: AgentConfig) { super(config); } async onStart() { // Initialize connections await this.mcp.connect('sap'); await this.mcp.connect('alibaba'); // Set up monitoring this.monitor.track('inventory_levels'); this.monitor.alert('low_stock', this.handleLowStock); } async handleLowStock(item: InventoryItem) { // Custom procurement logic const suppliers = await this.findSuppliers(item); const bestOffer = await this.negotiatePrice(suppliers, item); if (await this.approveSpending(bestOffer.cost)) { return this.executePurchase(bestOffer); } } } // Deploy agent const agent = new MyProcurementAgent(agentConfig); await agent.deploy(); ``` ### Agent Testing Framework ```typescript theme={null} import { AgentTestSuite, MockServices } from '@stateset/agent-testing'; describe('Procurement Agent', () => { let agent: MyProcurementAgent; let mockServices: MockServices; beforeEach(async () => { mockServices = new MockServices(); agent = new MyProcurementAgent({ ...agentConfig, testMode: true, services: mockServices }); }); test('should handle low stock scenario', async () => { // Arrange mockServices.inventory.setLowStock('WIDGET-001', 5); mockServices.suppliers.addSupplier({ id: 'SUP-001', products: ['WIDGET-001'], pricing: { 'WIDGET-001': '10.00' } }); // Act await agent.handleLowStock({ sku: 'WIDGET-001', currentStock: 5, reorderPoint: 10 }); // Assert expect(mockServices.orders.getLastOrder()).toMatchObject({ sku: 'WIDGET-001', quantity: 50, supplier: 'SUP-001' }); expect(agent.wallet.getLastTransaction()).toMatchObject({ amount: '500.00', recipient: 'SUP-001-wallet' }); }); }); ``` ## 🌐 Cross-Platform Agent Interoperability ### Universal Agent Identity ```typescript theme={null} interface UniversalAgentID { did: string; // Decentralized identifier statesetAddress: string; // Native wallet address mcpConnections: { platform: string; identity: string; permissions: string[]; }[]; capabilities: AgentCapability[]; reputation: ReputationScore; verification: VerificationProof; } // Example agent identity const agentIdentity: UniversalAgentID = { did: 'did:stateset:agent:procurement:abc123', statesetAddress: 'stateset1agent123...', mcpConnections: [ { platform: 'salesforce', identity: 'user_12345', permissions: ['read_contacts', 'create_opportunities'] }, { platform: 'sap', identity: 'sapuser_67890', permissions: ['purchase_orders', 'vendor_management'] } ], capabilities: [ 'procurement', 'supplier_negotiation', 'compliance_checking', 'financial_analysis' ], reputation: { score: 95, transactions: 10000, successRate: 0.98, trustLevel: 'verified' }, verification: { attestations: ['stateset_verified', 'enterprise_approved'], audits: ['security_audit_2024', 'compliance_review_2024'] } }; ``` ### Agent-to-Agent Communication Protocol ```typescript theme={null} interface AgentMessage { from: string; // Sender agent DID to: string; // Recipient agent DID type: MessageType; // Request, response, notification payload: any; // Message content signature: string; // Cryptographic signature timestamp: number; // Unix timestamp ttl: number; // Time to live priority: Priority; // Message priority } class AgentCommunication { async sendMessage(message: AgentMessage): Promise { // Encrypt message const encrypted = await this.encrypt(message, message.to); // Route through StateSet network return this.network.route({ message: encrypted, destination: message.to, priority: message.priority }); } async broadcastToNetwork( message: Omit, filters: AgentFilter[] ): Promise { // Find matching agents const recipients = await this.findAgents(filters); // Send to all recipients return Promise.all( recipients.map(agent => this.sendMessage({ ...message, to: agent.did }) ) ); } } ``` ## 📊 Agent Analytics & Performance ### Real-Time Agent Dashboard ```typescript theme={null} interface AgentDashboard { performance: { tasksCompleted: number; successRate: number; averageExecutionTime: number; errorRate: number; uptime: number; }; financial: { totalEarnings: string; totalSpent: string; profitMargin: number; walletBalance: string; pendingTransactions: number; }; operations: { activeConnections: number; apiCallsPerHour: number; resourceUtilization: { cpu: number; memory: number; network: number; }; }; compliance: { complianceScore: number; lastAudit: Date; violations: number; riskLevel: 'low' | 'medium' | 'high'; }; } ``` ### Agent Network Analytics ```mermaid theme={null} graph TB subgraph "Network Metrics" NM1[Total Agents: 1M+] NM2[Daily Transactions: 50M+] NM3[Cross-Platform Actions: 100M+] NM4[Economic Value: $10B+] end subgraph "Agent Categories" AC1[Commerce: 35%] AC2[Finance: 25%] AC3[Operations: 20%] AC4[Compliance: 10%] AC5[Other: 10%] end subgraph "Performance Metrics" PM1[Average Uptime: 99.8%] PM2[Success Rate: 96.5%] PM3[Response Time: 150ms] PM4[Error Rate: 0.2%] end ``` ## 🔮 The Future of Agentic Commerce ### 2024-2030 Roadmap | Year | Milestone | Impact | | ----------- | ------------------------------ | ------------------------------- | | **2024 Q4** | Agent Marketplace Launch | 10,000 active agents | | **2025 Q2** | Cross-Platform MCP Integration | 100+ platforms connected | | **2025 Q4** | Multi-Agent Coordination | Complex workflow automation | | **2026 Q2** | AI-Native Financial Services | Autonomous financial management | | **2026 Q4** | Global Agent Economy | \$100B+ agent-mediated commerce | | **2027+** | Planetary-Scale Automation | Majority of commerce autonomous | ### Vision: The Agentic Economy By 2030, we envision a world where: * **🤖 1 billion agents** operate autonomously across the global economy * **💰 \$10 trillion** in annual agent-mediated transactions * **🌐 Every business** has AI agents managing operations 24/7 * **⚡ 99% of routine commerce** is fully automated * **🚀 New economic models** emerge around agent-to-agent commerce ### Agent-to-Agent Economy Examples ```typescript theme={null} // Future: Agents negotiating directly with each other class ManufacturingAgent extends StateSetAgent { async negotiateWithSupplierAgent(supplierAgent: AgentDID, requirement: Requirement) { // Direct agent-to-agent negotiation const negotiation = await this.startNegotiation({ counterparty: supplierAgent, requirement, maxPrice: this.budgetManager.getMaxPrice(requirement), timeline: requirement.urgency }); // AI-powered negotiation rounds while (!negotiation.settled) { const offer = await negotiation.getNextOffer(); const response = await this.ai.evaluateOffer(offer); if (response.accept) { return this.acceptOffer(offer); } else { await negotiation.counterOffer(response.counterOffer); } } // Execute transaction directly return this.wallet.pay({ recipient: supplierAgent.wallet, amount: negotiation.finalPrice, smart_contract: negotiation.terms }); } } ``` ## 🚀 Get Started with StateSet Agents ### Quick Start: Deploy Your First Agent ```bash theme={null} # Install StateSet Agent CLI npm install -g @stateset/agent-cli # Initialize new agent project stateset-agent init my-procurement-agent --type=commerce # Configure agent cd my-procurement-agent stateset-agent configure --wallet-balance=1000 --mcp-services=sap,alibaba # Deploy to StateSet network stateset-agent deploy --network=mainnet # Monitor agent stateset-agent monitor --agent-id=my-procurement-agent ``` ### Agent Templates * **🛒 E-commerce Agent**: Automate online store operations * **💼 B2B Sales Agent**: Handle enterprise sales workflows * **📊 Analytics Agent**: Process and analyze business data * **🏦 Finance Agent**: Manage treasury and payments * **🚚 Logistics Agent**: Optimize supply chain operations * **⚖️ Compliance Agent**: Ensure regulatory compliance * **🎯 Marketing Agent**: Run automated marketing campaigns ### Enterprise Integration ```typescript theme={null} // Enterprise agent deployment const enterpriseConfig = { security: 'enterprise', compliance: ['SOX', 'PCI_DSS', 'GDPR'], integrations: ['salesforce', 'sap', 'workday', 'servicenow'], governance: { approvalWorkflows: true, auditLogging: true, emergencyControls: true }, scaling: { autoScale: true, maxAgents: 1000, loadBalancing: true } }; ``` *** ## Glossary * **Agentic Operating System**: A platform that enables autonomous agent computing with features like native wallets and cross-web state management. * **USDC**: USD Coin, a stablecoin used for financial transactions within the StateSet network. * **MCP Protocol**: Model Context Protocol, enabling cross-web coordination and state changes for agents. * **DID**: Decentralized Identifier, a unique identifier for agents in the network. * **LLM**: Large Language Model, the AI backbone for agent intelligence. *** ## Ready to Build the Future? StateSet Agentic OS represents the next evolution of computing—from human-operated applications to autonomous agent economies. Join us in building the infrastructure that will power the next century of global commerce. *** *StateSet: The Operating System for Autonomous Commerce* ## Best Practices for Building StateSet Agents Drawing from agentic AI engineering principles, here are key best practices: ### Context Engineering Provide the right information at the right time. Use structured templates and context compression. ### Workflow Engineering Break complex tasks into modular steps. Use patterns like Planner-Worker and Reflection Loops. ### Model Engineering Choose appropriate models for tasks. Balance performance, cost, and latency. ### AgenticOps Implement evaluations, guardrails, observability, and security measures. ### Agentic UX Design for transparency, progressive delegation, and user trust. ## Agentic AI Design Patterns StateSet supports several design patterns to build effective agents: ### Reflection Pattern Agents review their own outputs to improve accuracy. ### Tool Use Pattern Agents leverage external tools for enhanced capabilities. ### ReAct Pattern Combines reasoning and action in a loop for dynamic problem-solving. ### Planning Pattern Agents break down complex tasks into manageable steps. ### Multi-Agent Collaboration Pattern Multiple agents work together on intricate workflows. # StateSet iCommerce Engine CLI Source: https://docs.stateset.com/stateset-cli-overview Command-line interface for running StateSet iCommerce. # StateSet iCommerce CLI AI-powered command-line interface for autonomous commerce operations. ## Philosophy The StateSet CLI is built on the premise that commerce infrastructure should be designed for AI agents, not just humans. Think of it as **"The SQLite of Commerce"** — an embedded, zero-dependency commerce engine that: * **Runs locally** without cloud dependencies * **Deterministic operations** for agent reliability * **Agentic Commerce Protocol (ACP)** for standardized agent interactions * **Safety-first architecture** — read-only by default, explicit `--apply` for writes ## Features ### Core * **Natural Language Interface** - Ask Claude to perform commerce operations * **Multi-Agent System** - 17 specialized agents auto-route to the best handler * **90+ MCP Tools** - Full commerce API exposed to Claude * **Hybrid Vector Search** - Semantic + BM25 search for products, customers, orders, and inventory (requires `OPENAI_API_KEY`) * **Multi-turn Sessions** - Resume conversations for complex workflows * **Preview Mode** - See what would happen before making changes * **Direct Commands** - Fast, non-AI mode for scripting * **Interactive Chat** - REPL for exploratory work ### Sync & Streaming * **VES Protocol v1.0** - Verifiable Event Sync with Ed25519 signatures * **gRPC Streaming** - Real-time bidirectional sync with sequencer * **Event Outbox** - SQLite-backed event sourcing with conflict resolution * **Optimistic Concurrency** - Base version tracking for safe multi-agent updates ### Payments * **Multi-Chain Stablecoins** - USDC on Solana, Base, Ethereum, Arbitrum * **SET Chain ssUSD** - Yield-bearing stablecoin on StateSet L2 * **Bitcoin & Zcash** - Native BTC and ZEC support * **VES Key Derivation** - Deterministic wallet addresses per agent ### Infrastructure * **Batch Processing** - Sequential or parallel request processing * **Interactive Tutorials** - Guided onboarding for new users * **SQLite/PostgreSQL** - Flexible storage backends * **Rich Output** - ASCII tables, progress bars, formatted displays * **Telemetry** - Distributed tracing with `--verbose` and `--stats` ## Installation ```bash theme={null} npm install -g @stateset/cli ``` Or run locally: ```bash theme={null} cd cli npm install npm link ``` ## Quick Start Tip: `ss` is a shorthand alias for `stateset`. ### Run the Tutorial New to StateSet CLI? Start with the interactive tutorial: ```bash theme={null} stateset-tutorial quickstart ``` ### AI-Powered Mode ```bash theme={null} # List customers (read-only by default) stateset "show me all customers" # Check inventory stateset "how much stock do we have of WIDGET-001?" # Create a customer (requires --apply) stateset --apply "create a customer named Alice with email alice@example.com" # Multi-turn workflow stateset --apply "create an order for that customer with 2 widgets at $29.99" stateset --apply --resume "ship that order with tracking ABC123" ``` ### Interactive Chat ```bash theme={null} stateset-chat # In chat: > show me all orders > /apply on > create a product called Premium Widget with SKU WIDGET-001 at $29.99 > /status > /exit ``` ### Direct Commands (No AI) ```bash theme={null} # Customer operations stateset-direct customers list stateset-direct customers get alice@example.com # Order operations stateset-direct orders list stateset-direct orders ship TRACK123 # Inventory operations stateset-direct inventory stock WIDGET-001 stateset-direct inventory adjust WIDGET-001 -5 "Sold 5 units" # Vector search (hybrid semantic + BM25) stateset-direct vector search products "wireless earbuds" 5 ``` ### Batch Processing ```bash theme={null} # Process multiple requests sequentially (maintains session context) echo "list customers" | stateset --stdin --json # Process requests from file stateset --batch requests.txt # Parallel processing (faster, independent requests) stateset --batch requests.txt --parallel 4 --json # Parallel with write operations stateset --apply --batch orders.txt --parallel 3 ``` ## Commands ### Primary Commands | Command | Description | | ------------------------------------- | ------------------------------------------------ | | `stateset ""` | AI-powered interface (auto-routes to best agent) | | `stateset-chat` | Multi-turn interactive REPL | | `stateset-direct ` | Direct CLI (no AI required) | ### Specialized Agent Commands | Command | Agent | Description | | ------------------------ | ------------- | ---------------------------------------------- | | `stateset-checkout` | checkout | Shopping cart & checkout flow (ACP) | | `stateset-orders` | orders | Order lifecycle management | | `stateset-inventory` | inventory | Stock & reservation management | | `stateset-returns` | returns | RMA & refund processing | | `stateset-analytics` | analytics | Sales metrics & forecasting | | `stateset-promotions` | promotions | Promotions, discounts & coupons | | `stateset-subscriptions` | subscriptions | Subscription plans & recurring billing | | `stateset-create` | storefront | Scaffold e-commerce storefronts | | `stateset-manufacturing` | manufacturing | BOM & work order management | | `stateset-payments` | payments | Payment processing & refunds | | `stateset-shipments` | shipments | Shipment tracking & delivery | | `stateset-suppliers` | suppliers | Supplier & purchase order management | | `stateset-invoices` | invoices | B2B invoice management | | `stateset-warranties` | warranties | Product warranty & claims | | `stateset-currency` | currency | Multi-currency & exchange rates | | `stateset-tax` | tax | Tax calculation & compliance | | `stateset-pay` | stablecoin | Native crypto payments (USDC, ssUSD, BTC, ZEC) | ### Utility Commands | Command | Description | | --------------------- | ---------------------------------------- | | `stateset-config` | Profile and configuration management | | `stateset-doctor` | Health check and diagnostics | | `stateset-events` | Event management and webhooks | | `stateset-sync` | Verifiable Event Sync with sequencer | | `stateset-tutorial` | Interactive tutorials and onboarding | | `stateset-completion` | Shell completion scripts (bash/zsh/fish) | ## Architecture ``` stateset-icommerce/ ├── crates/ │ ├── stateset-core/ # Pure domain models (254 types, 18 modules) │ ├── stateset-db/ # SQLite + PostgreSQL (53 tables) │ └── stateset-embedded/ # High-level unified API (671+ methods) ├── bindings/ │ ├── node/ # @stateset/embedded (NAPI) │ ├── python/ # stateset-embedded (PyO3) │ └── wasm/ # WebAssembly for browsers └── cli/ ├── bin/ # 26 CLI programs ├── src/ │ ├── claude-harness.js # Multi-agent SDK integration │ ├── mcp-server.js # 90+ MCP tools for Claude │ ├── sync/ # VES Protocol & gRPC streaming │ │ ├── grpc-client.js # Bidirectional gRPC client │ │ ├── engine.js # Sync orchestration │ │ ├── outbox.js # Event outbox (SQLite) │ │ ├── crypto.js # Ed25519 signing & hashing │ │ └── proto/ # Protocol buffer definitions │ ├── chains/ # Multi-chain payment support │ │ ├── config.js # Chain configurations │ │ ├── wallet.js # VES key → wallet derivation │ │ ├── stablecoin.js # Payment operations │ │ └── validation.js # Address validation │ ├── permissions.js # Fine-grained access control │ ├── telemetry.js # Observability & tracing │ ├── errors.js # Structured error handling │ ├── session.js # Session persistence │ └── database.js # Connection pooling └── .claude/ ├── agents/ # 17 specialized agent definitions └── skills/ # Domain knowledge documents ``` ### Technology Stack * **Rust Core** - Pure domain logic with deterministic execution * **@stateset/embedded** - Native Node.js bindings via NAPI * **Claude Agent SDK** - AI agent framework with MCP tools * **SQLite/PostgreSQL** - Flexible database backends ## Capabilities ### Commerce Operations | Domain | Operations | | ------------- | ----------------------------------------------- | | **Orders** | Create, confirm, process, ship, deliver, cancel | | **Customers** | Profiles, addresses, preferences, history | | **Products** | Catalog with variants and attributes | | **Inventory** | Multi-location stock, reservations, adjustments | | **Carts** | Shopping cart with ACP checkout flow | | **Returns** | RMA processing with refund management | | **Shipments** | Fulfillment tracking with carrier integration | ### Manufacturing Operations | Domain | Operations | | --------------------- | ----------------------------- | | **Bill of Materials** | Create, manage, activate BOMs | | **Work Orders** | Production job management | | **Components** | Track component requirements | ### Financial Operations | Domain | Operations | | ------------------- | --------------------------------------------------- | | **Multi-Currency** | 35+ currencies (USD, EUR, GBP, JPY, BTC, ETH, USDC) | | **Payments** | Credit card, PayPal, cryptocurrency | | **Refunds** | Multiple payout methods | | **Invoices** | B2B invoice management with payment terms | | **Purchase Orders** | Supplier management and procurement | | **Tax** | Multi-jurisdiction tax calculation (US, EU, CA) | ### Promotions & Discounts ```bash theme={null} # Create promotions stateset --apply "create a 20% off promotion called Summer Sale" stateset --apply "create a buy 2 get 1 free promotion" stateset --apply "create a free shipping promotion for orders over $50" # Manage coupons stateset --apply "create coupon SAVE20 with 100 use limit" stateset "is coupon SAVE20 valid?" # Apply to cart stateset --apply "apply promotions to cart " ``` ### Subscriptions & Recurring Billing ```bash theme={null} # Create plans stateset --apply "create a monthly plan called Coffee Club at $29.99 with 14 day trial" stateset --apply "create an annual plan called Pro at $99.99" # Manage subscriptions stateset --apply "subscribe customer to the Coffee Club plan" stateset --apply "pause subscription " stateset --apply "skip next billing for subscription " stateset --apply "cancel subscription " # View history stateset "show billing history for subscription " ``` ### Manufacturing ```bash theme={null} # Bill of Materials stateset-manufacturing "list all BOMs" stateset-manufacturing --apply "create a BOM for product ASSEMBLY-001" stateset-manufacturing --apply "add component PART-A qty 2 to BOM BOM-123" # Work Orders stateset-manufacturing "list pending work orders" stateset-manufacturing --apply "create work order from BOM BOM-123 for 100 units" stateset-manufacturing --apply "start work order WO-456" stateset-manufacturing --apply "complete work order WO-456 with 98 units produced" ``` ### Tax Management ```bash theme={null} # Calculate tax stateset "calculate tax for an order shipping to California" stateset "what's the tax rate for New York?" stateset "calculate tax for cart CART-123456" # Tax jurisdictions stateset "show me all tax jurisdictions" stateset "what are the EU VAT rates?" stateset "get tax info for Texas" # Exemptions stateset --apply "create tax exemption for customer abc123 - resale certificate" ``` ### Analytics & Forecasting ```bash theme={null} # Sales analytics stateset "what's my total revenue this month?" stateset "show me my best sellers" stateset "who are my top customers?" # Inventory health stateset "what inventory needs attention?" stateset "show me low stock items" # Forecasting stateset "predict inventory needs for next month" stateset "forecast revenue for next quarter" ``` ## Safety Architecture ### Read-Only by Default All write operations are **blocked by default**. The CLI shows what would happen without making changes. ```bash theme={null} # Preview what would happen stateset "create a customer named Bob" # Output: "Would create customer: {email: ..., name: Bob}" # Actually create the customer stateset --apply "create a customer named Bob" # Output: "Created customer: abc-123-def" ``` ### Permission Controls | Feature | Description | | --------------------------- | ------------------------------------------------------- | | **Preview Mode** | Default read-only operation | | **Confirmation Thresholds** | High-value operations (>\$1000) prompt for confirmation | | **Permission Gating** | Five levels: none, read, preview, write, admin | | **Spending Limits** | Max order value, daily totals | | **Rate Limiting** | Tool calls/minute, write ops/minute | | **Audit Logging** | Complete operation history | ## Observability ```bash theme={null} # Verbose output with tracing stateset --verbose "show me pending orders" # Execution statistics stateset --stats "process all returns" # JSON output for integration stateset --json "list customers" ``` ## Workflows ### E-commerce Workflow ```bash theme={null} # Set up a product stateset --apply "create a product called 'Premium Widget' with SKU WIDGET-001 at $29.99" # Add inventory stateset --apply "create inventory for WIDGET-001 with 100 units" # Create a customer stateset --apply "create customer alice@example.com named Alice Smith" # Create an order stateset --apply "create an order for alice@example.com: 2x WIDGET-001" # Ship it stateset --apply --resume "ship that order with tracking FEDEX123" ``` ### Shopping Cart Checkout (ACP) ```bash theme={null} # Create a cart stateset --apply "create a cart for alice@example.com" # Add items (multi-turn) stateset --apply --resume "add 2 Premium Widgets at $29.99" stateset --apply --resume "add 1 Deluxe Widget at $49.99" # Set shipping address stateset --apply --resume "set shipping to Alice Smith, 123 Main St, Anytown, CA 90210" # Apply discount stateset --apply --resume "apply discount code SAVE10" # Check shipping options stateset --resume "what shipping options are available?" # Complete checkout stateset --apply --resume "pay with credit card and complete checkout" ``` ### Cart Recovery ```bash theme={null} stateset "show me abandoned carts" stateset "what items are in cart CART-123456?" ``` ### Inventory Management ```bash theme={null} # Check stock stateset "how much WIDGET-001 do we have?" # Restock stateset --apply "add 50 units to WIDGET-001 - received shipment" # Adjust for damage stateset --apply "remove 3 units from WIDGET-001 - damaged in warehouse" ``` ### Processing Returns ```bash theme={null} # Create return stateset --apply "create a return for order #12345 - item defective" # Review and approve stateset "show me pending returns" stateset --apply "approve return " ``` ### Multi-Currency Support ```bash theme={null} stateset "what's the exchange rate from USD to EUR?" stateset "convert $100 USD to EUR" stateset "list all exchange rates" stateset --apply "set exchange rate USD to EUR at 0.92" stateset --apply "enable currencies USD, EUR, GBP, JPY" ``` ### Stablecoin Payments Send native cryptocurrency payments across multiple blockchains: ```bash theme={null} # List supported blockchains stateset pay --chains # Show agent wallet addresses stateset pay --wallet # All chains stateset pay --wallet --chain solana # Specific chain # Check stablecoin balance stateset pay --balance --chain solana stateset pay --balance --chain set_chain # Send payment (preview mode - no actual transaction) stateset pay --to 9WzDXwBb...WWWM --amount 50.00 --chain solana # Execute real payment (requires --apply) stateset pay --apply --to 9WzDXwBb...WWWM --amount 50.00 --chain solana # Pay with ssUSD on SET Chain (yield-bearing stablecoin) stateset pay --apply --to 0x1234...5678 --amount 100 --chain set_chain # Include order metadata for audit trail stateset pay --apply --to --amount 50 --chain solana --order ORD-123 --memo "Widget purchase" # AI-powered payments stateset --apply "pay 50 USDC to 9WzDXwBb...WWWM on Solana" stateset "check my wallet balance on Base" ``` **Supported Chains:** | Chain | Token | Description | | --------------- | ------------- | ----------------------------- | | `solana` | USDC | Fast, cheap, proven liquidity | | `solana_devnet` | USDC | Testing | | `set_chain` | ssUSD | StateSet L2, yield-bearing | | `base` | USDC | Coinbase L2, low fees | | `ethereum` | USDC/USDT/DAI | Maximum security | | `arbitrum` | USDC | Fast L2 | | `zcash` | ZEC | Privacy-focused (t-addresses) | | `bitcoin` | BTC | Original cryptocurrency | ### Supplier Management ```bash theme={null} # Manage suppliers stateset-suppliers "list all suppliers" stateset-suppliers --apply "create supplier Acme Corp" # Purchase orders stateset-suppliers --apply "create PO for 100 WIDGET-001 from Acme Corp" stateset-suppliers --apply "approve purchase order PO-123" stateset-suppliers --apply "send purchase order PO-123 to supplier" ``` ### B2B Invoicing ```bash theme={null} # Create and manage invoices stateset-invoices "list all invoices" stateset-invoices --apply "create invoice for order ORD-456" stateset-invoices --apply "send invoice INV-123" stateset-invoices "show overdue invoices" stateset-invoices --apply "record $500 payment for invoice INV-123" ``` ### Storefront Creation ```bash theme={null} # Preview what would be created stateset-create "create a store called Urban Thread" # Create the project stateset-create --apply "create a nextjs storefront for my coffee shop" # Create in specific directory stateset-create --apply --dir ~/projects "build an online bookstore" ``` Available templates: `nextjs`, `nextjs-minimal`, `vite-react`, `astro` ### Event Sync (VES Protocol) Synchronize events between agents and the StateSet Sequencer using the Verifiable Event Sync protocol: ```bash theme={null} # Check sync status stateset sync status # Push local events to sequencer stateset sync push # Pull new events from sequencer stateset sync pull # Start real-time streaming sync stateset sync stream # Subscribe to specific entities stateset sync stream --entity-type order --entity-id ORD-123 ``` **gRPC Streaming** for real-time sync: ```javascript theme={null} import { GrpcSequencerClient } from '@stateset/cli/sync'; const client = new GrpcSequencerClient({ url: 'sequencer.stateset.io:8081', tenantId: 'your-tenant-id', storeId: 'your-store-id', agentId: 'your-agent-id', }); await client.connect(); // Push events await client.pushEvents([{ entityType: 'order', entityId: 'ORD-123', eventType: 'OrderCreated', payload: { status: 'pending', amount: 99.99 }, baseVersion: 0, }]); // Subscribe to real-time updates client.onEvent((event) => { console.log('Received:', event.eventType, event.entityId); }); await client.startSyncStream(); ``` **VES Protocol Features:** * Ed25519 cryptographic signatures for event integrity * Domain-separated hashing (`VES_PAYLOAD_PLAIN_V1`) * Optimistic concurrency with base version tracking * Automatic conflict detection and resolution * Global sequence numbers for ordering ## Agent System 17 specialized agents handle different commerce domains: | Agent | Tools | Purpose | | -------------------- | ------------- | -------------------------------------- | | **checkout** | 14 ACP tools | Shopping cart & payment flows | | **orders** | 6 tools | Order lifecycle & fulfillment | | **inventory** | 6 tools | Stock management & reservations | | **returns** | 5 tools | RMA & refund processing | | **analytics** | 10 tools | Business intelligence & forecasting | | **promotions** | 10 tools | Campaigns, discounts, coupons | | **subscriptions** | 15 tools | Subscription plans & recurring billing | | **manufacturing** | 11 tools | BOM & work order management | | **payments** | 5 tools | Payment processing & refunds | | **shipments** | 5 tools | Shipment tracking & delivery | | **suppliers** | 8 tools | Supplier & purchase order management | | **invoices** | 7 tools | B2B invoice management | | **warranties** | 6 tools | Product warranty & claims | | **currency** | 8 tools | Multi-currency & exchange rates | | **tax** | 9 tools | Tax calculation & compliance | | **storefront** | 12 tools | E-commerce site scaffolding | | **customer-service** | All 87+ tools | Full-service fallback agent | ### Auto-Routing The main `stateset` command automatically routes requests to the best agent based on: * Request content analysis * Confidence scoring * Domain keyword matching * Ambiguity detection ## MCP Tools (90+ Total) | Domain | Count | Examples | | ------------------ | ----- | ----------------------------------------------------------------------- | | **Customers** | 3 | list, get, create | | **Orders** | 6 | list, get, create, update\_status, ship, cancel | | **Products** | 4 | list, get, get\_variant, create | | **Inventory** | 6 | get\_stock, create\_item, adjust, reserve, confirm, release | | **Returns** | 5 | list, get, create, approve, reject | | **Carts/Checkout** | 14 | create, add\_item, set\_address, set\_payment, complete\_checkout | | **Analytics** | 10 | sales\_summary, top\_products, demand\_forecast, revenue\_forecast | | **Currency** | 8 | get\_rate, convert, set\_rate, format | | **Tax** | 9 | calculate\_tax, calculate\_cart\_tax, get\_rate, list\_jurisdictions | | **Promotions** | 10 | list, create, activate, create\_coupon, validate\_coupon, apply | | **Subscriptions** | 15 | list\_plans, create\_plan, create\_subscription, pause, resume, cancel | | **Manufacturing** | 11 | list\_boms, create\_bom, create\_work\_order, complete\_work\_order | | **Payments** | 5 | list, get, create, complete, create\_refund | | **Shipments** | 3 | list, create, deliver | | **Suppliers/POs** | 6 | list\_suppliers, create\_supplier, create\_purchase\_order | | **Invoices** | 5 | list, create, send, record\_payment, get\_overdue | | **Warranties** | 4 | list, create, create\_claim, approve\_claim | | **Stablecoin** | 4 | get\_agent\_wallet, get\_wallet\_balance, create\_payment, list\_chains | ## Configuration ### Environment Variables ```bash theme={null} # Claude API key (required for AI mode) export ANTHROPIC_API_KEY="sk-ant-..." ``` ### Database ```bash theme={null} # Default: ./store.db (SQLite) stateset --db /path/to/mystore.db "list customers" # In-memory database (testing) stateset --db :memory: "list customers" # PostgreSQL (enterprise) # Configure via environment or config file ``` ### Flags Reference | Flag | Description | | ---------------- | ---------------------------------- | | `--db ` | Database path | | `--apply` | Enable write operations | | `--model ` | Claude model to use | | `--resume ` | Resume previous session | | `--json` | JSON output | | `--verbose` | Real-time telemetry | | `--stats` | Execution statistics | | `--parallel ` | Process batch requests in parallel | | `--batch ` | Read requests from file | | `--stdin` | Read requests from stdin | | `--help` | Show help | ## Session Management Sessions enable multi-turn conversations with context preservation: ```bash theme={null} # First request returns session ID stateset --apply "create a cart for alice@example.com" # Output includes: Session ID: abc-123-def # Resume to continue context stateset --apply --resume abc-123-def "add 2 widgets at $29.99" stateset --apply --resume abc-123-def "complete checkout" ``` ## Tutorials Learn the CLI with interactive tutorials: ```bash theme={null} # List available tutorials stateset-tutorial # Run specific tutorials stateset-tutorial quickstart # Learn basics in 5 minutes stateset-tutorial orders # Order management stateset-tutorial inventory # Stock management stateset-tutorial checkout # Shopping cart flow stateset-tutorial analytics # Business intelligence ``` ## Shell Completions Generate shell completion scripts: ```bash theme={null} # Bash stateset-completion bash >> ~/.bashrc # Zsh stateset-completion zsh >> ~/.zshrc # Fish stateset-completion fish > ~/.config/fish/completions/stateset.fish ``` ## Command Reference ### `stateset` - AI Agent ``` stateset [options] "" Options: --db Database path (default: ./store.db) --apply Enable write operations --model Claude model --resume Resume previous session --json JSON output --verbose Show telemetry --stats Show execution stats --parallel Parallel batch processing --batch Read requests from file --stdin Read requests from stdin --help Show help ``` ### `stateset-chat` - Interactive Mode ``` stateset-chat [options] Options: --db Database path --apply Start with write enabled --model Claude model In-chat commands: /help Show commands /status Current settings /apply on|off Toggle write mode /db Switch database /new Start new session /exit Exit ``` ### `stateset-direct` - Direct Commands ``` stateset-direct [options] [args] Options: --db Database path --json JSON output --help Show help Resources: customers Customer management orders Order management products Product catalog inventory Stock management returns Return processing ``` ## Error Handling The CLI provides structured error handling with helpful suggestions: ```bash theme={null} # Permission errors Error: Permission denied: 'create_customer' requires --apply flag Suggestions: • Add --apply flag to enable write operations • Example: stateset --apply "your command here" • Run without --apply first to preview what would happen # Not found errors Error: Customer 'unknown@example.com' not found Suggestions: • Check that the customer ID is correct • List available customers: stateset-direct customers list • Use a partial ID (like git) - only a few characters needed if unique ``` ## Diagnostics Run health checks: ```bash theme={null} stateset-doctor # Check specific components stateset-doctor --checks api,db,permissions ``` ## Development ```bash theme={null} cd cli npm install npm link # Test npm test # All tests npm run test:unit # Unit tests only npm run test:integration # Integration tests # Run diagnostics stateset-doctor ``` ## Programmatic Usage The CLI modules can be used programmatically: ```javascript theme={null} import { runAgentLoop, createErrorHandler, createSessionManager, createDatabaseManager, withContext } from '@stateset/cli'; // Run an agent request const result = await runAgentLoop({ request: 'list all customers', dbPath: './store.db', allowApply: false }); // Use with request context await withContext({ agent: 'orders' }, async (ctx) => { ctx.logEvent('processing_order'); // ... your code }); ``` # AI Agents API Source: https://docs.stateset.com/stateset-commerce-api-reference/agents Deploy autonomous AI agents that can transact, negotiate, and manage commerce operations on StateSet **Early Access**: The AI Agents API is in early access. Request access at [agents@stateset.com](mailto:agents@stateset.com) # AI Agents API: Autonomous Commerce Infrastructure ## 🤖 Overview StateSet's AI Agents API enables you to deploy autonomous agents that can execute transactions, manage inventory, negotiate deals, and handle complex commerce operations 24/7. Built with native stablecoin integration and advanced safety controls. Agents operate independently within defined parameters Multi-level controls prevent runaway spending Agents improve performance through ML optimization ## 🚀 Quick Start JavaScript examples assume a structured logger is available as `logger`. Replace with your preferred logger in production. ```javascript theme={null} import { StateSet } from '@stateset/sdk'; // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY }); // Deploy a procurement agent const agent = await stateset.agents.create({ name: 'ProcurementBot-01', type: 'procurement', capabilities: ['negotiate', 'purchase', 'track'], limits: { daily_spend: '10000.00', per_transaction: '1000.00', requires_approval_above: '5000.00' } }); logger.info('Agent deployed', { agentId: agent.id }); ``` ```javascript theme={null} // Configure agent behavior await stateset.agents.configure(agent.id, { procurement_rules: { preferred_suppliers: ['supplier_123', 'supplier_456'], max_price_variance: 0.05, // 5% above market delivery_requirements: '3_days', quality_threshold: 0.95 }, negotiation_strategy: 'balanced', // aggressive, balanced, conservative learning_enabled: true }); ``` ```javascript theme={null} // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; // Real-time agent monitoring const activity = await stateset.agents.activity(agent.id, { timeframe: '24h' }); logger.info('Transactions', { count: activity.transaction_count }); logger.info('Total spent', { totalSpent: activity.total_spent }); logger.info('Savings achieved', { savings: activity.savings }); ``` ## 📊 Agent Types ### Automated Purchasing & Negotiation Procurement agents handle supplier relationships, negotiate prices, and execute purchases based on inventory levels and demand forecasts. ```javascript theme={null} const procurementAgent = await stateset.agents.create({ type: 'procurement', name: 'SupplyChainOptimizer', capabilities: [ 'supplier_discovery', 'price_negotiation', 'order_placement', 'delivery_tracking' ], config: { inventory_triggers: { reorder_point: 100, optimal_quantity: 500, safety_stock: 50 }, supplier_preferences: { min_rating: 4.5, max_delivery_days: 5, payment_terms: ['NET_30', 'NET_60'] } } }); ``` **Key Features:** * Automatic reordering based on inventory levels * Multi-supplier price comparison * Dynamic negotiation based on order volume * Quality and delivery performance tracking ### Intelligent Sales Automation Sales agents handle customer inquiries, negotiate deals, and manage the entire sales cycle autonomously. ```javascript theme={null} const salesAgent = await stateset.agents.create({ type: 'sales', name: 'SalesBot-Enterprise', capabilities: [ 'lead_qualification', 'price_quoting', 'contract_negotiation', 'upsell_identification' ], config: { pricing_authority: { base_discount: 0.10, max_discount: 0.25, volume_tiers: [ { min: 100, discount: 0.15 }, { min: 500, discount: 0.20 }, { min: 1000, discount: 0.25 } ] }, response_time: '5_minutes', languages: ['en', 'es', 'fr', 'de'] } }); ``` ### Treasury & Financial Management Finance agents optimize cash flow, manage payments, and execute financial strategies. ```javascript theme={null} const financeAgent = await stateset.agents.create({ type: 'finance', name: 'TreasuryManager', capabilities: [ 'invoice_factoring', 'payment_optimization', 'forex_management', 'yield_farming' ], config: { treasury_rules: { min_cash_balance: '50000.00', invoice_factoring_threshold: 0.02, // 2% discount payment_timing: 'optimize_discounts' }, risk_parameters: { max_counterparty_exposure: '100000.00', collateral_ratio: 1.5, stop_loss: 0.05 } } }); ``` ### Supply Chain Optimization Logistics agents manage shipping, routing, and delivery optimization. ```javascript theme={null} const logisticsAgent = await stateset.agents.create({ type: 'logistics', name: 'ShippingOptimizer', capabilities: [ 'carrier_selection', 'route_optimization', 'tracking_management', 'customs_handling' ], config: { optimization_goals: { primary: 'cost', secondary: 'speed', constraints: ['carbon_neutral'] }, carrier_preferences: { tier_1: ['DHL', 'FedEx', 'UPS'], tier_2: ['Regional_Carriers'], blacklist: [] } } }); ``` ## 🔐 Safety & Controls ### Multi-Level Security Framework ```javascript theme={null} // Configure comprehensive spending controls await stateset.agents.setLimits(agent.id, { absolute_limits: { daily: '10000.00', weekly: '50000.00', monthly: '150000.00', per_transaction: '5000.00' }, velocity_controls: { max_transactions_per_hour: 10, max_transactions_per_day: 50, cooldown_after_limit: '1_hour' }, approval_thresholds: { auto_approve_below: '1000.00', human_approval_above: '5000.00', board_approval_above: '50000.00' } }); ``` ```javascript theme={null} // Define operational constraints await stateset.agents.setBehaviors(agent.id, { allowed_actions: [ 'purchase_from_approved_suppliers', 'negotiate_within_parameters', 'execute_recurring_orders' ], prohibited_actions: [ 'create_new_contracts', 'modify_payment_terms', 'access_sensitive_data' ], ethical_constraints: { sustainability_required: true, fair_trade_only: true, no_conflict_minerals: true } }); ``` ```javascript theme={null} // Emergency stop mechanisms // Immediate halt await stateset.agents.emergencyStop(agent.id); // Gradual shutdown await stateset.agents.gracefulShutdown(agent.id, { complete_pending: true, notify_counterparties: true, transfer_to_human: 'ops_team' }); // Circuit breaker configuration await stateset.agents.setCircuitBreaker(agent.id, { error_threshold: 5, error_window: '10_minutes', recovery_timeout: '1_hour', half_open_requests: 3 }); ``` ## 📡 Agent Communication ### Inter-Agent Protocols ```javascript theme={null} // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; // Enable agent-to-agent negotiation const negotiation = await stateset.agents.negotiate({ buyer_agent: 'agent_buyer_123', seller_agent: 'agent_seller_456', item: { sku: 'WIDGET-001', quantity: 1000, target_price: '10.00' }, parameters: { max_rounds: 10, timeout: '5_minutes', binding_agreement: true } }); // Monitor negotiation progress negotiation.on('round_complete', (round) => { logger.info('Round complete', { round: round.number, buyerOffer: round.buyer_offer, sellerOffer: round.seller_offer }); }); negotiation.on('agreement_reached', (deal) => { logger.info('Agreement reached', { price: deal.price, quantity: deal.quantity }); }); ``` ### Human-Agent Collaboration ```javascript theme={null} // Set up human oversight await stateset.agents.setOversight(agent.id, { notification_channels: { email: ['ops@company.com'], slack: '#agent-alerts', sms: ['+1234567890'] }, escalation_triggers: [ 'unusual_price_variance', 'new_supplier_request', 'large_order_placement', 'repeated_failures' ], human_intervention_points: { pre_execution: ['orders_above_5000'], post_execution: ['all_transactions'], on_error: ['payment_failures', 'delivery_issues'] } }); ``` ## 📊 Analytics & Performance ### Real-Time Metrics ```javascript theme={null} // Get comprehensive agent analytics const analytics = await stateset.agents.analytics(agent.id, { period: '30_days', metrics: [ 'transaction_volume', 'success_rate', 'average_savings', 'response_time', 'learning_progress' ] }); // Response { "agent_id": "agent_123", "period": "30_days", "performance": { "transactions": 1543, "success_rate": 0.97, "total_volume": "543,234.56", "average_transaction": "352.15", "savings_achieved": "32,445.23", "savings_percentage": 0.06 }, "behavioral_insights": { "preferred_suppliers": ["supp_123", "supp_456"], "peak_activity_hours": [9, 10, 14, 15], "negotiation_success_rate": 0.78, "average_negotiation_rounds": 3.4 }, "learning_metrics": { "model_accuracy": 0.92, "prediction_confidence": 0.88, "adaptation_rate": 0.15, "knowledge_base_size": 15420 } } ``` ### Custom Reporting ```javascript theme={null} // Create custom agent reports const report = await stateset.agents.generateReport({ agent_ids: ['agent_123', 'agent_456'], report_type: 'comparative_analysis', metrics: { financial: ['total_spend', 'roi', 'cost_savings'], operational: ['response_time', 'accuracy', 'throughput'], strategic: ['supplier_diversity', 'innovation_score'] }, format: 'pdf', schedule: 'weekly' }); ``` ## 🧪 Testing & Simulation ### Sandbox Environment ```javascript theme={null} // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; // Test agent behavior in sandbox const simulation = await stateset.agents.simulate({ agent_id: agent.id, scenario: 'market_volatility', parameters: { price_fluctuation: 0.20, supply_disruption: 0.10, demand_spike: 1.50 }, duration: '7_days' }); // Monitor simulation results simulation.on('day_complete', (day) => { logger.info('Day complete', { day: day.number, performanceScore: day.performance_score }); }); ``` ## 🚨 Error Handling ```javascript theme={null} try { const result = await agent.execute(transaction); } catch (error) { switch(error.code) { case 'LIMIT_EXCEEDED': // Handle spending limit await notifyFinanceTeam(error); break; case 'UNAUTHORIZED_ACTION': // Handle permission violation await logSecurityEvent(error); break; case 'LEARNING_FAILURE': // Handle ML model issues await fallbackToRules(transaction); break; default: // Generic error handling await agent.reportError(error); } } ``` ## 🔗 Integrations Direct integration with SAP, Oracle, Microsoft Dynamics TensorFlow, PyTorch, and Hugging Face model support Slack, Teams, Email, and SMS notifications Export to Tableau, PowerBI, and custom dashboards ## 📚 Resources Pre-built agent configurations for common use cases Guidelines for safe and effective agent deployment Real-world success stories and ROI analysis Connect with other developers building agents # API Reference Source: https://docs.stateset.com/stateset-commerce-api-reference/api-reference Complete reference documentation for all StateSet Commerce APIs # API Reference Complete documentation for all StateSet Commerce Network APIs. All API endpoints are RESTful and return JSON responses. ## 🌐 Base URLs ``` https://api.stateset.com/v1 ``` ``` https://api-testnet.stateset.com/v1 ``` ## 🔑 Authentication All requests must include your API key in the Authorization header: ```bash theme={null} Authorization: Bearer ${STATESET_API_KEY} ``` ## 📚 Core APIs Issue, redeem, and transfer ssUSD stablecoins **Key Endpoints:** * `POST /stablecoin/issue` * `POST /stablecoin/redeem` * `POST /stablecoin/transfer` * `GET /stablecoin/balance` Process payments and handle transactions **Key Endpoints:** * `POST /payments/create` * `GET /payments/{id}` * `POST /payments/refund` * `GET /payments/list` Manage e-commerce orders and fulfillment **Key Endpoints:** * `POST /orders/create` * `PATCH /orders/{id}` * `POST /orders/{id}/fulfill` * `GET /orders/list` Trade finance, factoring, and lending **Key Endpoints:** * `POST /finance/invoices/factor` * `POST /finance/po/finance` * `POST /finance/loans/create` * `GET /finance/options` Deploy and manage autonomous agents **Key Endpoints:** * `POST /agents/create` * `POST /agents/{id}/execute` * `GET /agents/{id}/activity` * `PATCH /agents/{id}/config` Cross-border trade and compliance **Key Endpoints:** * `POST /global/orders/create` * `POST /global/compliance/check` * `GET /global/tax/calculate` * `POST /global/shipping/quote` ## 🔧 Common Parameters ### Pagination Most list endpoints support pagination: | Parameter | Type | Description | Default | | ---------------- | ------- | ----------------------------- | ------- | | `limit` | integer | Number of records to return | 10 | | `starting_after` | string | Cursor for pagination | null | | `ending_before` | string | Cursor for reverse pagination | null | **Example:** ```bash theme={null} GET /v1/orders?limit=20&starting_after=ord_123 ``` ### Filtering List endpoints support filtering: ```bash theme={null} GET /v1/orders?status=pending&created[gte]=2024-01-01 ``` ### Expanding Objects Request nested objects in a single call: ```bash theme={null} GET /v1/orders/ord_123?expand[]=customer&expand[]=items.product ``` ## 📨 Request Format ### Headers | Header | Required | Description | | ----------------- | -------- | ------------------------------------- | | `Authorization` | Yes | Bearer token with your API key | | `Content-Type` | Yes\* | `application/json` for POST/PUT/PATCH | | `Idempotency-Key` | No | Unique key for safe retries | | `X-Account-Id` | No | Act on behalf of a connected account | ### Request Body All POST, PUT, and PATCH requests accept JSON: ```json theme={null} { "amount": 100.00, "currency": "ssusd", "recipient": "stateset1abc...", "metadata": { "order_id": "12345", "customer_email": "user@example.com" } } ``` ## 📤 Response Format ### Success Response ```json theme={null} { "id": "pay_1a2b3c4d", "object": "payment", "amount": 100.00, "currency": "ssusd", "status": "succeeded", "created": 1640995200, "metadata": { "order_id": "12345" } } ``` ### Error Response ```json theme={null} { "error": { "type": "invalid_request_error", "code": "parameter_missing", "message": "The 'amount' parameter is required", "param": "amount", "doc_url": "https://docs.stateset.com/errors/parameter_missing" } } ``` ## 🔄 Idempotency Ensure safe retries with idempotency keys: ```bash theme={null} curl -X POST https://api.stateset.com/v1/payments \ -H "Authorization: Bearer sk_test_..." \ -H "Idempotency-Key: unique-key-123" \ -d '{...}' ``` Idempotency keys are valid for 24 hours. ## 📊 Rate Limits | Plan | Requests/Second | Daily Limit | Burst | | ---------- | --------------- | ----------- | ------ | | Free | 10 | 1,000 | 20 | | Starter | 100 | 100,000 | 200 | | Growth | 1,000 | 10,000,000 | 2,000 | | Enterprise | Custom | Custom | Custom | Rate limit headers: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1640995200 ``` ## 🌍 CORS The API supports CORS for browser-based requests: ```javascript theme={null} // Browser request example fetch('https://api.stateset.com/v1/account/balance', { headers: { 'Authorization': 'Bearer pk_test_...' // Public key only } }) .then(response => response.json()) .then(data => console.log(data)); ``` ## 🔐 Security ### API Key Types | Key Type | Prefix | Usage | | ---------- | ----------------------- | ------------------- | | Secret | `sk_test_` / `sk_live_` | Server-side only | | Public | `pk_test_` / `pk_live_` | Client-side safe | | Restricted | `rk_test_` / `rk_live_` | Limited permissions | ### Best Practices 1. **Never expose secret keys** in client-side code 2. **Use HTTPS** for all requests 3. **Verify webhooks** with signature validation 4. **Implement retry logic** with exponential backoff 5. **Monitor rate limits** and implement caching ## 📡 Webhooks Register webhooks to receive real-time events: ```bash theme={null} POST /v1/webhooks { "url": "https://yourapp.com/webhook", "events": ["payment.succeeded", "order.created"] } ``` [Learn more about webhooks →](/webhooks) ## 🧪 Testing ### Test Mode Use test API keys to simulate transactions: * No real money movement * Immediate transaction processing * Special test card numbers available ### Test Data | Resource | Test ID Format | Example | | -------- | -------------- | --------------- | | Customer | `cust_test_*` | `cust_test_123` | | Payment | `pay_test_*` | `pay_test_456` | | Order | `ord_test_*` | `ord_test_789` | ## 📱 SDK Support Official SDKs available for: ```bash theme={null} npm install @stateset/sdk ``` ```bash theme={null} pip install stateset ``` ```bash theme={null} go get github.com/stateset/stateset-go ``` [View all SDKs →](/sdks) ## 🆘 Support Resources Real-time API status and incidents Import our complete API collection Get help from developers Contact our support team # Authentication Source: https://docs.stateset.com/stateset-commerce-api-reference/authentication Secure API authentication for StateSet Commerce Network **Quick Start**: Get your API keys from the [StateSet Dashboard](https://dashboard.stateset.com) and make your first authenticated request in minutes. ## 🔐 Overview StateSet uses API keys to authenticate requests. Authentication is performed via HTTP headers using the Bearer token format. All API requests must be made over HTTPS. ## 🔑 API Key Types **Prefix**: `sk_test_` Use for development and testing. Transactions are simulated and no real money moves. **Prefix**: `sk_live_` Use for production. All transactions are real and irreversible. Never expose your secret API keys in client-side code, public repositories, or anywhere else accessible to the public. ## 📋 Authentication Methods ### Standard Authentication Include your API key in the `Authorization` header: ```bash cURL theme={null} curl https://api.stateset.com/v1/account/balance \ -H "Authorization: Bearer sk_test_your_actual_key_here" ``` ```javascript Node.js theme={null} const axios = require('axios'); const response = await axios.get('https://api.stateset.com/v1/account/balance', { headers: { 'Authorization': 'Bearer sk_test_your_actual_key_here' } }); ``` ```python Python theme={null} import requests response = requests.get( 'https://api.stateset.com/v1/account/balance', headers={ 'Authorization': 'Bearer sk_test_your_actual_key_here' } ) ``` ```go Go theme={null} client := &http.Client{} req, _ := http.NewRequest("GET", "https://api.stateset.com/v1/account/balance", nil) req.Header.Add("Authorization", "Bearer sk_test_your_actual_key_here") resp, _ := client.Do(req) ``` ### SDK Authentication When using our official SDKs, initialize with your API key: ```javascript Node.js theme={null} import { StateSet } from '@stateset/sdk'; const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY // Best practice: use environment variables }); ``` ```python Python theme={null} from stateset import StateSet import os stateset = StateSet( api_key=os.getenv('STATESET_API_KEY') # Best practice: use environment variables ) ``` ```go Go theme={null} import ( "github.com/stateset/stateset-go" "os" ) client := stateset.NewClient( os.Getenv("STATESET_API_KEY"), // Best practice: use environment variables ) ``` ```ruby Ruby theme={null} require 'stateset' Stateset.api_key = ENV['STATESET_API_KEY'] # Best practice: use environment variables ``` ## 🛡️ Security Best Practices Never hardcode API keys in your source code. Use environment variables: ```bash .env theme={null} STATESET_API_KEY=sk_test_your_actual_key_here ``` ```javascript theme={null} // Load from environment const apiKey = process.env.STATESET_API_KEY; ``` Regularly rotate your API keys (recommended every 90 days): 1. Generate a new API key in the dashboard 2. Update your application to use the new key 3. Verify everything works correctly 4. Revoke the old key * **Development**: Use test keys with limited permissions * **Staging**: Use test keys with production-like permissions * **Production**: Use live keys with minimal required permissions Create keys with only the permissions needed: ```javascript theme={null} // Dashboard API const key = await stateset.apiKeys.create({ name: 'Read-only Analytics Key', permissions: ['analytics:read', 'transactions:read'] }); ``` Track API key usage to detect anomalies: ```javascript theme={null} const usage = await stateset.apiKeys.usage({ keyId: 'key_abc123', startDate: '2024-01-01', endDate: '2024-01-31' }); ``` ## 🔒 Advanced Authentication ### HMAC Signatures (High-Security Operations) For sensitive operations like large transfers or issuance, add HMAC signatures: ```javascript theme={null} const crypto = require('crypto'); function createHmacSignature(payload, secret) { const timestamp = Math.floor(Date.now() / 1000); const message = `${timestamp}.${JSON.stringify(payload)}`; const signature = crypto .createHmac('sha256', secret) .update(message) .digest('hex'); return { signature, timestamp }; } // Use in request const payload = { amount: '10000.00', to: 'stateset1abc...' }; const { signature, timestamp } = createHmacSignature(payload, process.env.HMAC_SECRET); const response = await axios.post('https://api.stateset.com/v1/stablecoin/transfer', payload, { headers: { 'Authorization': `Bearer ${apiKey}`, 'X-Signature': signature, 'X-Timestamp': timestamp } }); ``` ### OAuth 2.0 (Partner Integrations) For third-party integrations, use OAuth 2.0: ```javascript theme={null} // 1. Redirect user to authorize const authUrl = `https://auth.stateset.com/oauth/authorize? client_id=${CLIENT_ID}& redirect_uri=${REDIRECT_URI}& response_type=code& scope=payments:read+payments:write`; // 2. Exchange code for token const tokenResponse = await axios.post('https://auth.stateset.com/oauth/token', { grant_type: 'authorization_code', code: authorizationCode, client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: REDIRECT_URI }); // 3. Use access token const response = await axios.get('https://api.stateset.com/v1/payments', { headers: { 'Authorization': `Bearer ${tokenResponse.data.access_token}` } }); ``` ## 📊 Rate Limits API keys have different rate limits based on your plan:
Plan Requests/Second Requests/Day Burst Limit
Free 10 1,000 20
Starter 100 100,000 200
Growth 1,000 10,000,000 2,000
Enterprise Custom Custom Custom
### Handling Rate Limits ```javascript theme={null} async function makeRequestWithRetry(url, options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const response = await axios.get(url, options); return response.data; } catch (error) { if (error.response?.status === 429) { const retryAfter = error.response.headers['retry-after'] || 2 ** i; console.log(`Rate limited. Retrying after ${retryAfter} seconds...`); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); } else { throw error; } } } throw new Error('Max retries exceeded'); } ``` ## 🚨 Error Responses Authentication errors return standardized responses: ```json theme={null} { "error": { "type": "authentication_error", "message": "Invalid API key provided", "code": "invalid_api_key", "status": 401 } } ``` Common authentication errors: | Error Code | Description | Solution | | -------------------------- | ------------------------------ | --------------------------------- | | `missing_api_key` | No API key provided | Include `Authorization` header | | `invalid_api_key` | API key is invalid | Check key format and validity | | `expired_api_key` | API key has expired | Generate a new key | | `insufficient_permissions` | Key lacks required permissions | Use a key with proper permissions | | `rate_limit_exceeded` | Too many requests | Implement backoff and retry | ## 🔄 Key Management API Programmatically manage your API keys: ```javascript theme={null} // List all keys const keys = await stateset.apiKeys.list(); // Create a new key const newKey = await stateset.apiKeys.create({ name: 'Mobile App Key', permissions: ['payments:create', 'payments:read'], expires_at: '2024-12-31T23:59:59Z' }); // Revoke a key await stateset.apiKeys.revoke('key_abc123'); // Update key permissions await stateset.apiKeys.update('key_abc123', { permissions: ['payments:read'] }); ``` ## 🧪 Testing Authentication Use our test endpoint to verify your authentication: ```bash theme={null} curl https://api.stateset.com/v1/auth/test \ -H "Authorization: Bearer sk_test_your_actual_key_here" ``` Success response: ```json theme={null} { "authenticated": true, "key_id": "key_abc123", "permissions": ["payments:create", "payments:read"], "mode": "test" } ``` ## 📱 Mobile & Frontend Security Never use secret API keys in mobile apps or frontend code. Use our public keys or implement a backend proxy. ### Public Keys (Read-Only Operations) ```javascript theme={null} // Safe to use in frontend const publicKey = 'pk_test_TYooMQauvdEDq54NiTphI7jx'; // Limited to read-only operations const balance = await fetch(`https://api.stateset.com/v1/public/balance/${address}`, { headers: { 'Authorization': `Bearer ${publicKey}` } }); ``` ### Backend Proxy Pattern ```javascript theme={null} // Frontend const response = await fetch('/api/stateset-proxy/payment', { method: 'POST', body: JSON.stringify({ amount: 100, recipient: 'stateset1abc...' }) }); // Backend (Node.js/Express) app.post('/api/stateset-proxy/payment', authenticate, async (req, res) => { const payment = await stateset.payments.create({ ...req.body, customer: req.user.id }); res.json(payment); }); ``` ## 🆘 Troubleshooting * Verify API key is correct and properly formatted * Check if key is expired or revoked * Ensure `Bearer` prefix is included * Confirm using correct environment (test vs live) * Check if key has required permissions * Verify you're not exceeding rate limits * Ensure accessing allowed endpoints for key type Run diagnostics: ```bash theme={null} curl -v https://api.stateset.com/v1/auth/test \ -H "Authorization: Bearer YOUR_API_KEY" ``` Check response headers and body for details. ## 📚 Next Steps Make your first API call in 5 minutes Official SDKs for all major languages Secure webhook authentication Complete API documentation # Cross-Chain Transfer Protocol (CCTP) Source: https://docs.stateset.com/stateset-commerce-api-reference/cctp Native USDC transfers between StateSet and other blockchains via Circle's CCTP # Cross-Chain Transfer Protocol (CCTP) on StateSet ## Overview StateSet Commerce Network implements Circle's Cross-Chain Transfer Protocol (CCTP) as a native Cosmos SDK module, enabling seamless USDC transfers between StateSet and other supported blockchains. This eliminates the need for wrapped tokens or custodial bridges, providing a secure and efficient way to move USDC across chains. StateSet has implemented CCTP as a native blockchain module rather than smart contracts, providing superior performance and deeper integration with other StateSet features. For technical details, see the [StateSet CCTP Module documentation](/stateset-commerce-api-reference/cctp-module). ## How CCTP Works ```mermaid theme={null} graph LR A[StateSet Commerce Network] -->|1. Burn USDC| B[CCTP Module] B -->|2. Attestation| C[Circle Attestation Service] C -->|3. Mint Message| D[Destination Chain] D -->|4. Native USDC| E[Recipient] ``` ### Key Benefits * **Native USDC**: No wrapped tokens - USDC is burned on source and minted on destination * **No Bridge Risk**: Eliminates custodial bridge vulnerabilities * **Unified Liquidity**: Same USDC across all supported chains * **Fast Transfers**: Typically completes in minutes * **Low Cost**: Only pay standard transaction fees ## Supported Chains | Chain | Domain | Status | | ------------------------- | ------ | -------- | | StateSet Commerce Network | 7 | ✅ Active | | Ethereum | 0 | ✅ Active | | Avalanche | 1 | ✅ Active | | Optimism | 2 | ✅ Active | | Arbitrum | 3 | ✅ Active | | Base | 6 | ✅ Active | | Polygon | 7 | ✅ Active | ## Module Address ### StateSet CCTP Module * **Mainnet**: `stateset1cctp7m4ugfz4m6dd73yysz477jszqnfughxvkss5` * **Testnet**: `stateset1test9x8ugfz4m6dd73yysz477jszqnfughxvkss5` ## Quick Start ### Transfer USDC from StateSet to Ethereum ```typescript theme={null} import { StateSetCCTP } from '@stateset/cctp-sdk'; const cctp = new StateSetCCTP({ endpoint: 'https://api.stateset.network', signer: wallet }); // Burn USDC on StateSet const burnTx = await cctp.depositForBurn({ amount: '1000.00', // 1000 USDC destinationDomain: 0, // Ethereum mintRecipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f6E321', burnToken: 'usdc' }); // Get attestation from Circle const attestation = await cctp.getAttestation(burnTx.messageHash); // Mint on Ethereum (using ethers.js) const mintTx = await ethereumCCTP.receiveMessage( burnTx.message, attestation ); ``` ## Core Functions ### depositForBurn Burns USDC on StateSet and initiates transfer to another chain. ```typescript theme={null} interface DepositForBurnParams { amount: string; // Amount of USDC to transfer destinationDomain: number; // Target chain domain mintRecipient: string; // Recipient address (32 bytes) burnToken: string; // Token to burn (usually 'usdc') } const result = await cctp.depositForBurn({ amount: '500.00', destinationDomain: 3, // Arbitrum mintRecipient: ethers.utils.hexZeroPad(recipientAddress, 32), burnToken: 'usdc' }); // Returns { txHash: '0x...', messageHash: '0x...', message: '0x...', nonce: 12345 } ``` ### depositForBurnWithCaller Burns USDC with a specific caller authorized on destination. ```typescript theme={null} interface DepositForBurnWithCallerParams { amount: string; destinationDomain: number; mintRecipient: string; burnToken: string; destinationCaller: string; // Authorized caller (32 bytes) } // Only specified contract can receive on destination const result = await cctp.depositForBurnWithCaller({ amount: '1000.00', destinationDomain: 0, mintRecipient: ethers.utils.hexZeroPad(recipientAddress, 32), burnToken: 'usdc', destinationCaller: ethers.utils.hexZeroPad(contractAddress, 32) }); ``` ### receiveMessage Receives and processes a CCTP message to mint USDC. ```typescript theme={null} interface ReceiveMessageParams { message: string; // Message bytes from source chain attestation: string; // Attestation from Circle } // Receive USDC from another chain const result = await cctp.receiveMessage({ message: '0x...', // From burn transaction attestation: '0x...' // From Circle API }); // Returns { txHash: '0x...', amount: '1000.00', recipient: 'stateset1...' } ``` ### replaceDepositForBurn Replace a pending burn message (before attestation). ```typescript theme={null} interface ReplaceDepositForBurnParams { originalMessage: string; originalAttestation: string; newMintRecipient?: string; newDestinationCaller?: string; } // Change recipient before message is processed const result = await cctp.replaceDepositForBurn({ originalMessage: '0x...', originalAttestation: '0x...', newMintRecipient: ethers.utils.hexZeroPad(newRecipient, 32) }); ``` ## Message Format CCTP messages follow a standardized format across all chains: ```typescript theme={null} interface CCTPMessage { version: number; // Message version (currently 0) sourceDomain: number; // Origin chain domain destinationDomain: number; // Target chain domain nonce: number; // Unique message identifier sender: string; // Sender address (32 bytes) recipient: string; // Recipient address (32 bytes) destinationCaller: string;// Authorized caller (32 bytes) messageBody: string; // Message payload } ``` ## Integration Examples ### E-Commerce Cross-Chain Payments ```typescript theme={null} // Accept payment on any chain, settle on StateSet class CrossChainPaymentProcessor { async acceptPayment( orderData: Order, paymentChain: number, customerAddress: string ) { // Generate payment address on customer's chain const paymentAddress = await this.getPaymentAddress(paymentChain); // Monitor for payment const payment = await this.waitForPayment( paymentAddress, orderData.total ); // Transfer to StateSet for settlement if (paymentChain !== STATESET_DOMAIN) { const burnTx = await this.burnUSDC({ chain: paymentChain, amount: payment.amount, destinationDomain: STATESET_DOMAIN, mintRecipient: this.settlementAddress }); // Get attestation const attestation = await this.getAttestation(burnTx.messageHash); // Receive on StateSet await this.stateset.cctp.receiveMessage({ message: burnTx.message, attestation }); } // Process order await this.fulfillOrder(orderData); } } ``` ### Multi-Chain Treasury Management ```typescript theme={null} // Optimize treasury across chains class MultiChainTreasury { async rebalance() { const balances = await this.getBalancesAllChains(); const optimal = this.calculateOptimalDistribution(balances); for (const transfer of optimal.transfers) { // Move funds between chains await this.cctpTransfer({ fromChain: transfer.source, toChain: transfer.destination, amount: transfer.amount }); } } async cctpTransfer({ fromChain, toChain, amount }) { // Initiate burn on source chain const burnTx = await this.clients[fromChain].depositForBurn({ amount, destinationDomain: this.domains[toChain], mintRecipient: this.addresses[toChain] }); // Wait for attestation const attestation = await this.waitForAttestation( burnTx.messageHash ); // Complete on destination await this.clients[toChain].receiveMessage({ message: burnTx.message, attestation }); } } ``` ### Arbitrage Across Chains ```typescript theme={null} // Execute arbitrage using CCTP for instant settlement class CrossChainArbitrage { async executeArbitrage(opportunity: ArbOpportunity) { // Buy on cheap chain const buyTx = await this.dexes[opportunity.buyChain].swap({ from: 'USDC', to: opportunity.token, amount: opportunity.amount }); // Transfer token to expensive chain (if supported) // ... token bridge logic ... // Sell on expensive chain const sellTx = await this.dexes[opportunity.sellChain].swap({ from: opportunity.token, to: 'USDC', amount: buyTx.output }); // Transfer profits back to StateSet const profit = sellTx.output - opportunity.amount; if (profit > 10) { // Min $10 profit await this.transferViaProtocol({ amount: profit.toString(), fromChain: opportunity.sellChain, toChain: 'stateset' }); } } } ``` ## Attestation Service Circle provides attestations for CCTP messages. Integration example: ```typescript theme={null} class AttestationService { private baseUrl = 'https://iris-api.circle.com/attestations'; async getAttestation(messageHash: string): Promise { // Poll for attestation (usually ready in 10-30 seconds) for (let i = 0; i < 60; i++) { try { const response = await fetch( `${this.baseUrl}/${messageHash}` ); if (response.status === 200) { const data = await response.json(); return data.attestation; } } catch (error) { // Continue polling } await new Promise(resolve => setTimeout(resolve, 2000)); } throw new Error('Attestation timeout'); } } ``` ## Gas Optimization ### Batch Transfers ```typescript theme={null} // Batch multiple transfers to save gas class BatchCCTP { async batchTransfer(transfers: Transfer[]) { // Group by destination domain const grouped = this.groupByDomain(transfers); for (const [domain, domainTransfers] of grouped) { // Create batch message const batchMessage = this.encodeBatchTransfer(domainTransfers); // Single burn for multiple recipients await this.cctp.depositForBurnWithCaller({ amount: this.sumAmounts(domainTransfers), destinationDomain: domain, mintRecipient: this.batchProcessor[domain], destinationCaller: this.batchProcessor[domain], burnToken: 'usdc' }); } } } ``` ## Security Considerations ### Best Practices 1. **Verify Addresses**: Always verify recipient addresses are correct format 2. **Check Domains**: Ensure destination domain matches intended chain 3. **Monitor Attestations**: Implement timeout handling for attestations 4. **Validate Messages**: Verify message integrity before processing 5. **Rate Limiting**: Implement transfer limits for security ### Address Formatting ```typescript theme={null} // Convert addresses to 32-byte format function formatAddress(address: string, chain: string): string { switch(chain) { case 'ethereum': case 'arbitrum': case 'optimism': case 'base': case 'avalanche': case 'polygon': // EVM addresses: pad to 32 bytes return ethers.utils.hexZeroPad(address, 32); case 'stateset': // Cosmos addresses: convert and pad const decoded = bech32.decode(address); const bytes = bech32.fromWords(decoded.words); return '0x' + Buffer.from(bytes).toString('hex').padStart(64, '0'); default: throw new Error(`Unsupported chain: ${chain}`); } } ``` ## Error Handling Common errors and solutions: | Error | Cause | Solution | | ---------------------- | ----------------------------- | ----------------------------- | | `Invalid domain` | Unsupported destination chain | Check supported domains list | | `Insufficient balance` | Not enough USDC | Ensure adequate balance | | `Invalid recipient` | Malformed address | Use proper address formatting | | `Attestation timeout` | Circle service delay | Implement retry logic | | `Nonce already used` | Duplicate message | Use unique nonce | ## Monitoring and Analytics ```typescript theme={null} // Track CCTP transfers class CCTPMonitor { async trackTransfer(transfer: CCTPTransfer) { // Log transfer initiation await this.log({ type: 'cctp_burn', chain: transfer.sourceChain, amount: transfer.amount, destination: transfer.destinationChain, timestamp: Date.now() }); // Monitor attestation const attestationTime = await this.measureAttestationTime( transfer.messageHash ); // Track completion const completion = await this.waitForMint( transfer.destinationChain, transfer.messageHash ); // Record metrics await this.metrics.record({ transferTime: completion.timestamp - transfer.timestamp, attestationTime, gasUsed: transfer.gasUsed + completion.gasUsed, success: true }); } } ``` ## Native Module vs Smart Contracts StateSet implements CCTP as a native Cosmos SDK module, providing several advantages: ### Performance * **10x faster**: Direct blockchain integration vs contract execution * **Lower fees**: No contract overhead, just base transaction costs * **Atomic operations**: Module-level atomicity guarantees ### Integration * **Deep integration**: Direct access to other StateSet modules * **Native CLI**: Built-in command-line interface * **Governance**: Integrated with StateSet governance ### Security * **No contract risk**: Eliminate smart contract vulnerabilities * **Chain-level validation**: Enhanced security at the consensus layer * **Upgrade path**: Coordinated upgrades via governance For detailed module documentation, see [StateSet CCTP Module](/stateset-commerce-api-reference/cctp-module). ## Resources * [CCTP Documentation](https://developers.circle.com/cctp) * [StateSet CCTP Module](/stateset-commerce-api-reference/cctp-module) * [StateSet CCTP SDK](https://github.com/stateset/cctp-sdk) * [Example Code](https://github.com/stateset/cctp-examples) ## Support For CCTP integration support: * Discord: [#cctp-support](https://discord.gg/stateset) * Email: [cctp@stateset.com](mailto:cctp@stateset.com) * Technical Docs: [docs.stateset.network/cctp](https://docs.stateset.network/cctp) # StateSet CCTP Module Source: https://docs.stateset.com/stateset-commerce-api-reference/cctp-module Native Cross-Chain Transfer Protocol implementation for StateSet Commerce Network # StateSet CCTP Module ## Overview The StateSet CCTP Module is a native Cosmos SDK module that implements Circle's Cross-Chain Transfer Protocol directly on StateSet Commerce Network. Unlike EVM chains where CCTP is implemented as smart contracts, StateSet's implementation is built into the blockchain itself, providing superior performance, security, and integration with other StateSet modules. ## Architecture ```mermaid theme={null} graph TB A[StateSet CCTP Module] --> B[Message Handler] A --> C[Attestation Manager] A --> D[Token Controller] A --> E[Burn/Mint Engine] B --> F[Send Messages] B --> G[Receive Messages] C --> H[Verify Attestations] C --> I[Manage Attesters] D --> J[Token Pairs] D --> K[Burn Limits] E --> L[Burn USDC] E --> M[Mint USDC] ``` ## Module State ### Core State Objects ```go theme={null} // Owner - Controls module administration type Owner struct { Address string } // PendingOwner - Two-phase ownership transfer type PendingOwner struct { Address string } // AttesterManager - Manages attestation validators type AttesterManager struct { Address string } // Pauser - Can pause module operations type Pauser struct { Address string } // TokenController - Manages token configurations type TokenController struct { Address string } ``` ### Operational State ```go theme={null} // Paused states type PausedState struct { SendingAndReceivingPaused bool BurningAndMintingPaused bool } // Message tracking type MessageState struct { NextAvailableNonce uint64 UsedNonces map[uint64]bool MaxMessageBodySize uint64 } // Attestation configuration type AttestationConfig struct { SignatureThreshold uint32 Attesters []Attester } // Token configuration type TokenConfig struct { TokenPairs []TokenPair PerMessageBurnLimit map[string]sdk.Int RemoteTokenMessengers map[uint32]string } ``` ## Core Messages ### 1. DepositForBurn Burns USDC on StateSet and initiates a cross-chain transfer. ```go theme={null} type MsgDepositForBurn struct { From string Amount sdk.Coin DestinationDomain uint32 MintRecipient []byte // 32 bytes BurnToken string } // Example usage msg := &MsgDepositForBurn{ From: "stateset1abc...", Amount: sdk.NewCoin("usdc", sdk.NewInt(1000000000)), // 1000 USDC DestinationDomain: 0, // Ethereum MintRecipient: ethAddress32Bytes, BurnToken: "usdc", } ``` ### 2. DepositForBurnWithCaller Burns USDC with a specific authorized caller on the destination chain. ```go theme={null} type MsgDepositForBurnWithCaller struct { From string Amount sdk.Coin DestinationDomain uint32 MintRecipient []byte // 32 bytes BurnToken string DestinationCaller []byte // 32 bytes } ``` ### 3. ReceiveMessage Processes incoming CCTP messages and mints USDC. ```go theme={null} type MsgReceiveMessage struct { From string Message []byte Attestation []byte } // Message format type Message struct { Version uint32 SourceDomain uint32 DestinationDomain uint32 Nonce uint64 Sender []byte // 32 bytes Recipient []byte // 32 bytes DestinationCaller []byte // 32 bytes MessageBody []byte } ``` ### 4. ReplaceDepositForBurn Replaces a pending burn message before attestation. ```go theme={null} type MsgReplaceDepositForBurn struct { From string OriginalMessage []byte OriginalAttestation []byte NewMintRecipient []byte // 32 bytes, optional NewDestinationCaller []byte // 32 bytes, optional } ``` ### 5. SendMessage Sends a generic message to another domain. ```go theme={null} type MsgSendMessage struct { From string DestinationDomain uint32 Recipient []byte // 32 bytes MessageBody []byte } ``` ### 6. SendMessageWithCaller Sends a message with a specific authorized caller. ```go theme={null} type MsgSendMessageWithCaller struct { From string DestinationDomain uint32 Recipient []byte // 32 bytes MessageBody []byte DestinationCaller []byte // 32 bytes } ``` ## Administrative Messages ### Ownership Management ```go theme={null} // Initiate ownership transfer type MsgUpdateOwner struct { From string NewOwner string } // Accept ownership transfer type MsgAcceptOwner struct { From string } ``` ### Attester Management ```go theme={null} // Enable an attester type MsgEnableAttester struct { From string Attester string } // Disable an attester type MsgDisableAttester struct { From string Attester string } // Update signature threshold type MsgUpdateSignatureThreshold struct { From string Amount uint32 } ``` ### Token Management ```go theme={null} // Link a token pair type MsgLinkTokenPair struct { From string LocalToken string RemoteToken []byte // 32 bytes RemoteDomain uint32 } // Set burn limit per message type MsgSetMaxBurnAmountPerMessage struct { From string LocalToken string Amount sdk.Int } ``` ### Pause Controls ```go theme={null} // Pause operations type MsgPauseBurningAndMinting struct { From string } type MsgPauseSendingAndReceivingMessages struct { From string } // Unpause operations type MsgUnpauseBurningAndMinting struct { From string } type MsgUnpauseSendingAndReceivingMessages struct { From string } ``` ## Integration with StateSet Modules ### Orders Module Integration ```go theme={null} // Automatic CCTP payment for cross-chain orders func (k Keeper) PayOrderCrossChain(ctx sdk.Context, order Order, paymentChain uint32) error { if paymentChain == STATESET_DOMAIN { // Local payment return k.processLocalPayment(ctx, order) } // Cross-chain payment via CCTP msg := &MsgDepositForBurn{ From: order.CustomerAddress, Amount: order.TotalAmount, DestinationDomain: STATESET_DOMAIN, MintRecipient: k.GetMerchantAddress(ctx), BurnToken: "usdc", } // Process burn burnResult, err := k.cctpKeeper.DepositForBurn(ctx, msg) if err != nil { return err } // Update order with cross-chain payment info order.PaymentInfo = PaymentInfo{ Type: "cross_chain", SourceChain: paymentChain, MessageHash: burnResult.MessageHash, AttestationPending: true, } return k.SetOrder(ctx, order) } ``` ### Finance Module Integration ```go theme={null} // Cross-chain invoice factoring func (k Keeper) FactorInvoiceCrossChain( ctx sdk.Context, invoice Invoice, factorChain uint32, ) error { // Tokenize invoice as NFT nft := k.TokenizeInvoice(ctx, invoice) // Prepare cross-chain message factorMsg := FactorInvoiceMessage{ InvoiceID: invoice.ID, NFTMetadata: nft.Metadata, Amount: invoice.Amount, DiscountRate: invoice.FactoringRate, } // Send via CCTP msg := &MsgSendMessageWithCaller{ From: invoice.SellerAddress, DestinationDomain: factorChain, Recipient: factorContractAddress, MessageBody: factorMsg.Bytes(), DestinationCaller: factorContractAddress, // Only factor contract can process } return k.cctpKeeper.SendMessageWithCaller(ctx, msg) } ``` ### Agent Module Integration ```go theme={null} // Enable agents to execute cross-chain transactions func (k Keeper) AgentCrossChainTransfer( ctx sdk.Context, agent Agent, transfer CrossChainTransfer, ) error { // Verify agent permissions if !k.CanAgentTransferCrossChain(ctx, agent, transfer) { return ErrAgentNotAuthorized } // Check daily limits if err := k.CheckAgentDailyLimit(ctx, agent, transfer.Amount); err != nil { return err } // Execute CCTP transfer msg := &MsgDepositForBurn{ From: agent.WalletAddress, Amount: transfer.Amount, DestinationDomain: transfer.DestinationChain, MintRecipient: transfer.Recipient, BurnToken: "usdc", } return k.cctpKeeper.DepositForBurn(ctx, msg) } ``` ## Events ### Core Events ```go theme={null} // Emitted when tokens are burned for cross-chain transfer type EventDepositForBurn struct { Nonce uint64 BurnToken string Amount sdk.Int Depositor string MintRecipient []byte DestinationDomain uint32 DestinationCaller []byte } // Emitted when a message is sent type EventMessageSent struct { Message []byte } // Emitted when a message is received type EventMessageReceived struct { Caller string SourceDomain uint32 Nonce uint64 Sender []byte MessageBody []byte } // Emitted when tokens are minted type EventMintAndWithdraw struct { MintRecipient string Amount sdk.Int MintToken string } ``` ## Attestation System ### Attestation Verification ```go theme={null} func (k Keeper) ValidateAttestation( ctx sdk.Context, message []byte, attestation []byte, ) error { // Get current attesters and threshold attesters := k.GetEnabledAttesters(ctx) threshold := k.GetSignatureThreshold(ctx) // Verify attestation length expectedLen := 65 * threshold // 65 bytes per signature if len(attestation) != int(expectedLen) { return ErrInvalidAttestationLength } // Extract and verify signatures messageHash := crypto.Keccak256(message) signers := make([]string, 0, threshold) for i := 0; i < int(threshold); i++ { sig := attestation[i*65 : (i+1)*65] signer, err := RecoverSigner(messageHash, sig) if err != nil { return err } signers = append(signers, signer) } // Verify signers are enabled attesters in order return k.VerifyAttesters(ctx, signers, attesters) } ``` ## Query Interface ### gRPC Queries ```protobuf theme={null} service Query { // Get module roles rpc Owner(QueryOwnerRequest) returns (QueryOwnerResponse); rpc AttesterManager(QueryAttesterManagerRequest) returns (QueryAttesterManagerResponse); rpc Pauser(QueryPauserRequest) returns (QueryPauserResponse); rpc TokenController(QueryTokenControllerRequest) returns (QueryTokenControllerResponse); // Get configuration rpc SignatureThreshold(QuerySignatureThresholdRequest) returns (QuerySignatureThresholdResponse); rpc MaxMessageBodySize(QueryMaxMessageBodySizeRequest) returns (QueryMaxMessageBodySizeResponse); rpc NextAvailableNonce(QueryNextAvailableNonceRequest) returns (QueryNextAvailableNonceResponse); // Get attesters rpc Attester(QueryAttesterRequest) returns (QueryAttesterResponse); rpc Attesters(QueryAttestersRequest) returns (QueryAttestersResponse); // Get token configuration rpc TokenPair(QueryTokenPairRequest) returns (QueryTokenPairResponse); rpc TokenPairs(QueryTokenPairsRequest) returns (QueryTokenPairsResponse); rpc PerMessageBurnLimit(QueryPerMessageBurnLimitRequest) returns (QueryPerMessageBurnLimitResponse); // Get paused states rpc BurningAndMintingPaused(QueryBurningAndMintingPausedRequest) returns (QueryBurningAndMintingPausedResponse); rpc SendingAndReceivingPaused(QuerySendingAndReceivingPausedRequest) returns (QuerySendingAndReceivingPausedResponse); } ``` ## CLI Commands ### Transaction Commands ```bash theme={null} # Burn USDC for cross-chain transfer stateset tx cctp deposit-for-burn \ --amount 1000usdc \ --destination-domain 0 \ --mint-recipient 0x742d35Cc6634C0532925a3b844Bc9e7595f6E321 \ --from mykey # Receive message with attestation stateset tx cctp receive-message \ --message-hex 0x... \ --attestation-hex 0x... \ --from mykey # Administrative commands stateset tx cctp enable-attester stateset1attester... --from owner stateset tx cctp link-token-pair usdc 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 0 --from token-controller stateset tx cctp set-burn-limit usdc 1000000000000 --from token-controller ``` ### Query Commands ```bash theme={null} # Query configuration stateset query cctp owner stateset query cctp signature-threshold stateset query cctp attesters stateset query cctp token-pairs # Query specific token pair stateset query cctp token-pair 0 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 # Query paused states stateset query cctp burning-minting-paused stateset query cctp sending-receiving-paused ``` ## Genesis State ```json theme={null} { "owner": "stateset1owner...", "attester_manager": "stateset1attestermanager...", "pauser": "stateset1pauser...", "token_controller": "stateset1tokencontroller...", "signature_threshold": 2, "max_message_body_size": "10000", "next_available_nonce": "1", "attesters": [ { "address": "stateset1attester1...", "enabled": true }, { "address": "stateset1attester2...", "enabled": true } ], "token_pairs": [ { "remote_domain": 0, "remote_token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "local_token": "usdc" } ], "per_message_burn_limits": [ { "token": "usdc", "limit": "1000000000000" } ], "burning_and_minting_paused": false, "sending_and_receiving_messages_paused": false } ``` ## Security Considerations ### Access Control 1. **Role-based permissions**: Only authorized addresses can perform administrative actions 2. **Two-phase ownership transfer**: Prevents accidental loss of ownership 3. **Pause mechanisms**: Emergency circuit breakers for security incidents ### Message Security 1. **Nonce tracking**: Prevents replay attacks 2. **Domain validation**: Ensures messages are for the correct chain 3. **Attestation verification**: Multi-signature validation from trusted attesters 4. **Message size limits**: Prevents DoS through large messages ### Token Security 1. **Burn limits**: Per-message caps to limit exposure 2. **Token pair validation**: Only configured tokens can be transferred 3. **Atomic operations**: Burns and mints are atomic within their domains ## Migration Guide ```go theme={null} // StateSet domain: 7 // Update your domain references const ( STATESET_DOMAIN = 7 ) // Update module addresses const ( // New StateSet address CCTP_ADDRESS = "stateset1cctp7m4ugfz4m6dd73yysz477jszqnfughxvkss5" ) ``` ## Best Practices ### 1. Message Construction ```go theme={null} // Always validate addresses before creating messages func PrepareRecipientAddress(address string, chain string) ([]byte, error) { switch chain { case "ethereum", "arbitrum", "optimism", "base": return ConvertEVMAddress(address) case "stateset": return ConvertCosmosAddress(address) default: return nil, ErrUnsupportedChain } } ``` ### 2. Attestation Handling ```go theme={null} // Implement retry logic for attestation service func WaitForAttestation(messageHash []byte, maxRetries int) ([]byte, error) { for i := 0; i < maxRetries; i++ { attestation, err := FetchAttestation(messageHash) if err == nil { return attestation, nil } if i < maxRetries-1 { time.Sleep(time.Second * time.Duration(math.Pow(2, float64(i)))) } } return nil, ErrAttestationTimeout } ``` ### 3. Error Handling ```go theme={null} // Comprehensive error handling for CCTP operations func HandleCCTPTransfer(transfer CCTPTransfer) error { // Pre-flight checks if err := ValidateTransfer(transfer); err != nil { return fmt.Errorf("validation failed: %w", err) } // Execute transfer result, err := ExecuteTransfer(transfer) if err != nil { // Check if error is retryable if IsRetryableError(err) { return RetryTransfer(transfer) } return fmt.Errorf("transfer failed: %w", err) } // Monitor attestation go MonitorAttestation(result.MessageHash) return nil } ``` ## Resources * [StateSet CCTP Module Spec](https://github.com/stateset/cctp-module) * [Integration Examples](https://github.com/stateset/cctp-examples) * [API Reference](https://docs.stateset.network/cctp/api) * [Migration Tools](https://github.com/stateset/cctp-migration) ## Support For CCTP module support: * Discord: [#cctp-dev](https://discord.gg/stateset) * GitHub: [github.com/stateset/cctp-module](https://github.com/stateset/cctp-module) * Email: [cctp@stateset.com](mailto:cctp@stateset.com) # Changelog Source: https://docs.stateset.com/stateset-commerce-api-reference/changelog Latest updates and improvements to the StateSet Commerce API # Changelog Stay up to date with the latest features, improvements, and changes to the StateSet Commerce API. Subscribe to our [changelog RSS feed](https://stateset.com/changelog.xml) or follow [@StateSetHQ](https://twitter.com/statesethq) for real-time updates. ## January 2024 ### January 15, 2024 #### 🎉 New Features **AI Agents API (Early Access)** * Launched autonomous agent deployment capabilities * Support for procurement, sales, finance, and logistics agents * Built-in safety controls and spending limits * Real-time learning and optimization * [Read the docs →](/agents) **Enhanced Global Commerce** * Added support for 45 new countries * Integrated with 12 additional customs systems * Real-time duty and tax calculations * Automated trade documentation generation #### 🚀 Improvements **Performance Enhancements** * 40% reduction in API response times * Increased throughput to 50,000 TPS * Optimized database queries for complex operations * Enhanced caching for frequently accessed data **Developer Experience** * New interactive API explorer * Improved error messages with actionable solutions * Added TypeScript definitions for all endpoints * Enhanced SDK auto-completion #### 🔧 API Changes **Breaking Changes** * None **Deprecations** * `POST /v1/order/cancel` → Use `POST /v1/orders/{id}/cancel` * `GET /v1/payment/list` → Use `GET /v1/payments` with pagination ### January 8, 2024 #### 🎉 New Features **CCTP Module Integration** * Native Cross-Chain Transfer Protocol support * Instant USDC transfers between chains * No wrapped tokens or bridges required * [Learn more →](/cctp-module) **Dynamic Discounting API** * Automated early payment discounts * Win-win for buyers and suppliers * Configurable discount curves * Real-time APR calculations #### 🚀 Improvements **Webhook Reliability** * Implemented exponential backoff with jitter * Added dead letter queue for failed webhooks * New webhook debugging dashboard * Increased retry attempts to 7 **Security Enhancements** * Added support for Ed25519 signatures * Implemented FIDO2 authentication * Enhanced API key scoping * New IP allowlisting features ## December 2023 ### December 20, 2023 #### 🎉 New Features **StateSet USD (ssUSD) Launch** * 1:1 USD backing with transparent reserves * Monthly CPA attestations on-chain * T+1 redemptions for USD * [Documentation →](/stablecoin/overview) **Invoice Factoring 2.0** * Instant liquidity for unpaid invoices * AI-powered risk assessment * Non-recourse options available * Integration with major accounting systems #### 🚀 Improvements **Orders API Enhancements** * Added support for split payments * Multi-currency order creation * Automated tax calculation * Enhanced shipping integrations **New SDKs** * Rust SDK (beta) * Java SDK with Spring Boot support * React Native SDK * Flutter SDK (community contributed) ### December 5, 2023 #### 🔧 API Changes **New Endpoints** * `POST /v1/finance/invoices/factor` - Factor invoices * `POST /v1/global/compliance/check` - Compliance screening * `GET /v1/analytics/dashboard` - Analytics API * `POST /v1/ai/agents/deploy` - Agent deployment **Enhanced Endpoints** * Added `expand` parameter to all GET endpoints * Support for field-level permissions * Batch operations for all major resources * GraphQL endpoint (beta) ## November 2023 ### November 28, 2023 #### 🎉 New Features **Compliance Automation** * Real-time sanctions screening * Export control verification * KYC/AML integration * Automated reporting **Multi-Chain Support** * StateSet mainnet launch * IBC integration with Cosmos chains * EVM compatibility via Ethermint * Bridge to Ethereum, Polygon, BSC #### 🚀 Improvements **Database Performance** * Migrated to CockroachDB for global distribution * 99.99% uptime achieved * Sub-millisecond query performance * Automatic sharding and replication ### November 10, 2023 #### 🔧 Infrastructure Updates **Global Expansion** * New regions: Asia-Pacific, South America * Edge locations in 25 cities * Reduced latency by 60% globally * Local compliance in all regions **Monitoring Improvements** * Real-time performance dashboards * Predictive scaling algorithms * Enhanced error tracking * Custom metric support ## Coming Soon ### Q1 2024 Roadmap Preparing for post-quantum security with new algorithms Machine learning models for trade optimization Real-time supply chain tracking with IoT sensors Integration with central bank digital currencies ## Version History | Version | Release Date | Highlights | | ------- | ------------ | ----------------------------------- | | v2.0.0 | Jan 15, 2024 | AI Agents, Enhanced Global Commerce | | v1.9.0 | Jan 8, 2024 | CCTP Module, Dynamic Discounting | | v1.8.0 | Dec 20, 2023 | ssUSD Launch, Invoice Factoring 2.0 | | v1.7.0 | Dec 5, 2023 | New SDKs, API Enhancements | | v1.6.0 | Nov 28, 2023 | Compliance Automation, Multi-Chain | | v1.5.0 | Nov 10, 2023 | Global Expansion, Infrastructure | ## Breaking Changes Policy We follow semantic versioning and strive to maintain backwards compatibility. Breaking changes are: 1. Announced at least 6 months in advance 2. Accompanied by migration guides 3. Supported with deprecation warnings 4. Available in parallel during transition ## Feedback Have feedback or feature requests? We'd love to hear from you: Submit and vote on features Report issues on GitHub Chat with the team *** This changelog includes major updates only. For detailed commit history, see our [GitHub repository](https://github.com/stateset/api). # Smart Contracts Source: https://docs.stateset.com/stateset-commerce-api-reference/contracts Overview of the StateSet Commerce Network Smart Contracts # StateSet Commerce Network: Smart Contract and CosmWasm Overview ## Table of Contents 1. [Introduction](#introduction) 2. [CosmWasm: The Foundation](#cosmwasm-the-foundation) 3. [Smart Contract Lifecycle](#smart-contract-lifecycle) 4. [Key Features of Stateset Smart Contracts](#key-features-of-stateset-smart-contracts) 5. [Contract Development Process](#contract-development-process) 6. [Security and Best Practices](#security-and-best-practices) 7. [Interoperability and Composability](#interoperability-and-composability) 8. [Stateset-Specific Contract Templates](#stateset-specific-contract-templates) 9. [Gas and Execution Model](#gas-and-execution-model) 10. [Upgradeability and Governance](#upgradeability-and-governance) 11. [Testing and Simulation](#testing-and-simulation) 12. [Future Developments](#future-developments) ## Introduction Smart contracts are at the heart of the StateSet Commerce Network, enabling complex business logic, automated agreements, and innovative financial instruments. This overview explores how Stateset leverages CosmWasm to provide a powerful, flexible, and secure smart contract platform tailored for global commerce. ## CosmWasm: The Foundation * **Overview**: CosmWasm is a smart contracting platform built for the Cosmos ecosystem * **Key Advantages**: * WebAssembly-based for near-native performance * Language-agnostic (primarily Rust, but supports other languages) * Designed for multi-chain environments * **Integration with Stateset**: Customizations and optimizations for commerce use cases ## Smart Contract Lifecycle 1. **Development**: Writing contract code (primarily in Rust) 2. **Compilation**: Compiling to WebAssembly (Wasm) bytecode 3. **Deployment**: Uploading bytecode to the Stateset network 4. **Instantiation**: Creating contract instances with specific parameters 5. **Execution**: Interacting with the contract through messages 6. **Upgrading**: Optionally updating contract logic (if designed for upgradeability) 7. **Termination**: Ending the contract's lifecycle (if applicable) ## Key Features of Stateset Smart Contracts * **Turing-Complete**: Support for complex logic and computations * **State Management**: Efficient storage and retrieval of contract state * **Access Control**: Fine-grained permissions and multi-signature capabilities * **Native Asset Handling**: Built-in support for STATE tokens and other assets * **Cross-Contract Communication**: Ability to interact with other contracts * **Oracles Integration**: Access to real-world data for contract execution ## Contract Development Process 1. **Environment Setup**: Installing Rust, CosmWasm, and Stateset SDK 2. **Contract Writing**: Developing contract logic in Rust 3. **Local Testing**: Unit and integration tests 4. **Compilation**: Building the Wasm binary 5. **Deployment**: Uploading to Stateset testnet or mainnet 6. **Verification**: Ensuring correct deployment and functionality 7. **Documentation**: Providing clear usage instructions and APIs ## Security and Best Practices * **Auditing**: Rigorous code review and third-party audits * **Formal Verification**: Mathematical proofs of contract correctness * **Secure Coding Patterns**: Following established best practices * **Limiting Privileged Operations**: Minimizing high-risk functionalities * **Thorough Testing**: Comprehensive test suites and scenario analysis * **Gradual Rollout**: Phased deployment strategy for critical contracts ## Interoperability and Composability * **IBC Integration**: Interacting with contracts on other Cosmos chains * **Cross-Chain Calls**: Executing functions across different networks * **Contract Composition**: Building complex systems from simpler components * **Standard Interfaces**: Common patterns for interoperable contract design ## Stateset-Specific Contract Templates * **Invoice Factoring Contracts**: Automating invoice financing processes * **Supply Chain Tracking**: Managing product lifecycle and provenance * **Escrow Services**: Facilitating secure multi-party transactions * **Tokenized Asset Contracts**: Creating and managing asset-backed tokens * **Decentralized Identity**: Managing verifiable credentials for commerce ## Gas and Execution Model * **Gas Metering**: Efficient resource allocation and fee calculation * **Execution Limits**: Safeguards against infinite loops and resource exhaustion * **Fee Market**: Dynamic fee adjustment based on network congestion * **Prepaid Gas**: Options for gas fee abstraction and sponsored transactions ## Upgradeability and Governance * **Upgradeable Contracts**: Patterns for contract logic updates * **Governance Integration**: On-chain voting for contract upgrades * **Proxy Patterns**: Separating contract logic from storage * **Versioning**: Managing multiple versions of contract interfaces ## Testing and Simulation * **Unit Testing**: Verifying individual contract components * **Integration Testing**: Ensuring correct inter-contract interactions * **Simulation Environments**: Testing contracts in realistic network conditions * **Fuzz Testing**: Identifying vulnerabilities through randomized inputs * **Economic Simulations**: Modeling contract behavior in various market scenarios ## Future Developments * **AI-Assisted Contract Development**: Leveraging AI for code generation and optimization * **Enhanced Privacy Features**: Implementing zero-knowledge proofs in contracts * **Cross-VM Compatibility**: Enabling interoperability with EVM and other VMs * **Natural Language Processing**: Contracts that can interpret and execute plain language agreements * **IoT Integration**: Smart contracts that interact directly with IoT devices for real-world commerce applications ## Conclusion The StateSet Commerce Network's smart contract platform, powered by CosmWasm, offers a robust, secure, and flexible environment for building sophisticated commerce applications. By providing powerful tools, templates, and best practices, Stateset enables developers to create innovative solutions that drive the future of global trade and finance. We invite developers, businesses, and innovators to explore the possibilities of smart contracts on Stateset and join us in revolutionizing the world of decentralized commerce. # DIDs Module Source: https://docs.stateset.com/stateset-commerce-api-reference/dids Overview of the StateSet Commerce Network DIDs Module # Decentralized Identifiers (DIDs) and Enforceable Digital Contracts ## Introduction to DIDs in Stateset Decentralized Identifiers (DIDs) form a cornerstone of the StateSet Commerce Network, enabling the creation of secure, verifiable, and enforceable digital contracts. By leveraging DIDs, Stateset provides a robust framework for establishing trust and authenticity in digital agreements, while also enabling these contracts to serve as collateral in various financial instruments. ## Understanding DIDs DIDs are unique identifiers that enable verifiable, decentralized digital identity. In the context of Stateset: * Each DID is cryptographically secured and controlled by the identity owner * DIDs are resolvable to DID documents containing metadata about the identity * DIDs can represent individuals, organizations, or even specific assets and documents Example Stateset DID: `did:cosmos:1:stateset:invoice:c04e30b8-9bcf-4503-996f-5241ad26d5cf` ## Creating Enforceable Digital Contracts with DIDs 1. **Contract Creation**: * Parties involved in the agreement are identified by their DIDs * Contract terms are encoded into a smart contract * The contract is assigned its own DID 2. **Digital Signatures**: * Parties sign the contract using their private keys associated with their DIDs * Signatures are cryptographically verifiable on-chain 3. **Immutable Record**: * The signed contract is recorded on the Stateset blockchain * Any amendments are tracked with full version history 4. **Verification and Authentication**: * The authenticity of the contract and signatories can be verified at any time using DID resolution 5. **Automated Enforcement**: * Smart contract logic ensures automatic execution of agreed-upon terms * Triggers can be set for specific conditions or time-based events ## Collateralization of DID-Linked Contracts DIDs enable the secure collateralization of digital contracts within the Stateset ecosystem: 1. **Asset Tokenization**: * DID-linked contracts (e.g., invoices, purchase orders) can be tokenized as NFTs * These NFTs represent verifiable claims on real-world assets or future cash flows 2. **Collateral Pool Creation**: * Multiple DID-linked contracts can be bundled into a collateral pool * The pool's value and risk profile can be accurately assessed due to the verifiable nature of DIDs 3. **Smart Contract-Based Lending**: * Lenders can provide loans against the collateral of DID-linked contracts * Loan terms are encoded in smart contracts, with automatic execution of collateral claims if terms are breached 4. **Dynamic Collateral Valuation**: * The value of collateralized contracts can be updated in real-time based on external data feeds (oracles) * This enables more accurate risk assessment and dynamic adjustment of loan-to-value ratios 5. **Fractional Ownership and Liquidity**: * DID-linked contracts can be fractionalized, allowing for partial collateralization or investment * This increases liquidity and enables more flexible financial instruments ## Legal Enforceability The use of DIDs in Stateset's digital contracts enhances their legal enforceability: * **Proof of Identity**: DIDs provide cryptographic proof of the signatories' identities * **Timestamp and Version Control**: All actions are timestamped and versioned on the blockchain * **Audit Trail**: Complete history of contract creation, amendments, and executions is maintained * **Jurisdictional Compliance**: Smart contracts can be designed to comply with specific legal jurisdictions * **Dispute Resolution**: Built-in mechanisms for arbitration and dispute resolution can be incorporated ## Privacy and Access Control DIDs enable granular control over information sharing: * **Selective Disclosure**: Parties can choose which information to share and with whom * **Zero-Knowledge Proofs**: Prove the validity of claims without revealing underlying data * **Revocable Access**: Access to contract details can be granted or revoked dynamically ## Interoperability Stateset's DID implementation ensures interoperability: * **Cross-Chain Verification**: DIDs and associated contracts can be verified across different blockchain networks * **Standards Compliance**: Adherence to W3C DID and Verifiable Credentials standards * **Integration with External Systems**: APIs for integrating with existing business systems and legal databases ## Future Innovations The integration of DIDs with enforceable digital contracts opens up new possibilities: * **AI-Driven Contract Analysis**: Automated risk assessment and contract optimization * **IoT Integration**: Linking physical world events to contract execution via IoT devices and DIDs * **Global Identity and Reputation Systems**: Building comprehensive, portable business identities and reputation scores * **Regulatory Tech Integration**: Automated compliance checks and reporting based on DID-linked credentials ## Conclusion By leveraging DIDs to create enforceable and collateralizable digital contracts, Stateset is pioneering a new era of trusted, efficient, and flexible digital commerce. This technology not only streamlines business processes but also opens up new avenues for financing and risk management. As the Stateset ecosystem grows, the power of DID-linked contracts will play a crucial role in shaping the future of global trade and finance. # Error Handling Source: https://docs.stateset.com/stateset-commerce-api-reference/errors Comprehensive guide to handling errors in the StateSet API StateSet uses conventional HTTP response codes and provides detailed error messages to help you quickly identify and resolve issues. ## 🚨 Error Response Format All errors follow a consistent JSON structure: ```json theme={null} { "error": { "type": "invalid_request_error", "code": "parameter_missing", "message": "The 'amount' parameter is required but was not provided", "param": "amount", "doc_url": "https://docs.stateset.com/errors/parameter_missing", "request_id": "req_1234567890abcdef" } } ``` ### Error Object Fields | Field | Type | Description | | ------------ | ------ | -------------------------------------------------- | | `type` | string | The type of error returned | | `code` | string | A short string identifying the error | | `message` | string | A human-readable message providing details | | `param` | string | The parameter related to the error (if applicable) | | `doc_url` | string | Link to relevant documentation | | `request_id` | string | Unique identifier for this request | ## 📊 HTTP Status Codes | Code | Meaning | Description | | ---- | ---------- | --------------------------------------- | | 200 | OK | Request succeeded | | 201 | Created | Resource successfully created | | 202 | Accepted | Request accepted for processing | | 204 | No Content | Request succeeded with no response body | | Code | Meaning | Description | | ---- | -------------------- | --------------------------------------- | | 400 | Bad Request | Invalid request syntax or parameters | | 401 | Unauthorized | Missing or invalid authentication | | 403 | Forbidden | Valid auth but insufficient permissions | | 404 | Not Found | Requested resource doesn't exist | | 409 | Conflict | Request conflicts with current state | | 422 | Unprocessable Entity | Request understood but invalid | | 429 | Too Many Requests | Rate limit exceeded | | Code | Meaning | Description | | ---- | --------------------- | ------------------------------ | | 500 | Internal Server Error | Unexpected server error | | 502 | Bad Gateway | Invalid response from upstream | | 503 | Service Unavailable | Service temporarily offline | | 504 | Gateway Timeout | Upstream request timeout | ## 🔍 Error Types ### Authentication Errors Occur when API keys are missing, invalid, or lack permissions. ```json theme={null} { "error": { "type": "authentication_error", "code": "invalid_api_key", "message": "The provided API key is invalid", "request_id": "req_abc123" } } ``` * `api_key_missing` - No API key provided * `invalid_api_key` - API key is malformed or doesn't exist * `api_key_expired` - API key has expired * `api_key_revoked` - API key has been revoked * `insufficient_permissions` - API key lacks required permissions ### Invalid Request Errors Occur when request parameters are invalid or missing. ```json theme={null} { "error": { "type": "invalid_request_error", "code": "parameter_invalid", "message": "Amount must be a positive number", "param": "amount", "request_id": "req_def456" } } ``` * `parameter_missing` - Required parameter not provided * `parameter_invalid` - Parameter value is invalid * `parameter_unknown` - Unknown parameter provided * `request_invalid` - Request body is malformed * `idempotency_key_in_use` - Idempotency key already used ### Rate Limit Errors Occur when you exceed API rate limits. ```json theme={null} { "error": { "type": "rate_limit_error", "code": "rate_limit_exceeded", "message": "Too many requests. Please retry after 60 seconds", "request_id": "req_ghi789" } } ``` Response headers include: ``` X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1640995200 Retry-After: 60 ``` ### API Errors Occur due to problems on StateSet's servers. ```json theme={null} { "error": { "type": "api_error", "code": "internal_server_error", "message": "An unexpected error occurred. Please try again", "request_id": "req_jkl012" } } ``` ## 💻 Error Handling Examples ```javascript Node.js theme={null} const { StateSet } = require('@stateset/sdk'); const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY }); async function makePayment(amount, recipient) { try { const payment = await stateset.payments.create({ amount, recipient, currency: 'ssusd' }); return payment; } catch (error) { // Handle different error types switch (error.type) { case 'authentication_error': console.error('Authentication failed:', error.message); // Refresh API key or prompt for authentication break; case 'invalid_request_error': console.error('Invalid request:', error.message); if (error.param) { console.error('Problem with parameter:', error.param); } break; case 'rate_limit_error': console.error('Rate limit hit, retrying after delay...'); const retryAfter = error.headers?.['retry-after'] || 60; await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); return makePayment(amount, recipient); // Retry case 'api_error': console.error('StateSet API error:', error.message); // Log to monitoring service break; default: console.error('Unknown error:', error); } throw error; } } ``` ```python Python theme={null} from stateset import StateSet from stateset.error import ( AuthenticationError, InvalidRequestError, RateLimitError, APIError ) import time stateset = StateSet(api_key=os.getenv('STATESET_API_KEY')) def make_payment(amount, recipient): try: payment = stateset.Payment.create( amount=amount, recipient=recipient, currency='ssusd' ) return payment except AuthenticationError as e: print(f"Authentication failed: {e.user_message}") # Handle authentication error raise except InvalidRequestError as e: print(f"Invalid request: {e.user_message}") if e.param: print(f"Problem with parameter: {e.param}") # Handle validation error raise except RateLimitError as e: print("Rate limit hit, retrying after delay...") retry_after = int(e.headers.get('retry-after', 60)) time.sleep(retry_after) return make_payment(amount, recipient) # Retry except APIError as e: print(f"StateSet API error: {e.user_message}") # Log to monitoring service raise except Exception as e: print(f"Unexpected error: {str(e)}") raise ``` ```go Go theme={null} package main import ( "fmt" "time" "github.com/stateset/stateset-go" ) func makePayment(client *stateset.Client, amount int64, recipient string) (*stateset.Payment, error) { payment, err := client.Payments.Create(&stateset.PaymentParams{ Amount: stateset.Int64(amount), Recipient: stateset.String(recipient), Currency: stateset.String("ssusd"), }) if err != nil { // Type assert to StateSet error if statesetErr, ok := err.(*stateset.Error); ok { switch statesetErr.Type { case "authentication_error": return nil, fmt.Errorf("auth failed: %s", statesetErr.Message) case "invalid_request_error": if statesetErr.Param != "" { return nil, fmt.Errorf("invalid param %s: %s", statesetErr.Param, statesetErr.Message) } return nil, fmt.Errorf("invalid request: %s", statesetErr.Message) case "rate_limit_error": // Retry after delay retryAfter := statesetErr.Headers.Get("Retry-After") duration, _ := time.ParseDuration(retryAfter + "s") time.Sleep(duration) return makePayment(client, amount, recipient) case "api_error": return nil, fmt.Errorf("API error: %s", statesetErr.Message) } } return nil, err } return payment, nil } ``` ## 🔄 Retry Strategy Implement exponential backoff with jitter for transient errors: ```javascript theme={null} async function retryWithBackoff(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { // Don't retry client errors (except rate limits) if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) { throw error; } if (i === maxRetries - 1) throw error; // Exponential backoff with jitter const delay = Math.min(1000 * Math.pow(2, i) + Math.random() * 1000, 10000); console.log(`Retry ${i + 1}/${maxRetries} after ${delay}ms`); await new Promise(resolve => setTimeout(resolve, delay)); } } } // Usage const payment = await retryWithBackoff(() => stateset.payments.create({ amount: 100, recipient: 'stateset1abc...' }) ); ``` ## 🛡️ Idempotency Prevent duplicate operations using idempotency keys: ```javascript theme={null} const payment = await stateset.payments.create({ amount: 100, recipient: 'stateset1abc...', idempotency_key: 'unique-operation-key-123' }); // Safe to retry - will return the same result const samePayment = await stateset.payments.create({ amount: 100, recipient: 'stateset1abc...', idempotency_key: 'unique-operation-key-123' }); ``` ## 📈 Common Error Scenarios ### Insufficient Funds ```json theme={null} { "error": { "type": "invalid_request_error", "code": "insufficient_funds", "message": "Account has insufficient funds for this transaction", "param": "amount", "available_balance": "50.00", "requested_amount": "100.00", "currency": "ssusd" } } ``` ### Invalid Address ```json theme={null} { "error": { "type": "invalid_request_error", "code": "invalid_address", "message": "The recipient address is not a valid StateSet address", "param": "recipient", "provided_value": "invalid-address" } } ``` ### Compliance Block ```json theme={null} { "error": { "type": "compliance_error", "code": "transaction_blocked", "message": "This transaction cannot be processed due to compliance restrictions", "compliance_reason": "sanctions_screening", "request_id": "req_xyz789" } } ``` ## 🔍 Debugging Tips ### 1. Use Request IDs Always log the `request_id` for support inquiries: ```javascript theme={null} try { const result = await stateset.someMethod(); } catch (error) { console.error(`Request failed: ${error.request_id}`); // Include request_id in bug reports } ``` ### 2. Enable Debug Mode Get detailed request/response logs: ```javascript theme={null} const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY, debug: true // Logs all requests/responses }); ``` ### 3. Check Status Page Monitor API health at [status.stateset.com](https://status.stateset.com) ### 4. Use Test Mode Test error scenarios safely: ```javascript theme={null} // Force specific errors in test mode const payment = await stateset.payments.create({ amount: 100, recipient: 'stateset1_test_insufficient_funds', // Special test address currency: 'ssusd' }); ``` ## 📊 Error Monitoring Set up proper error tracking: ```javascript theme={null} // Example with Sentry import * as Sentry from '@sentry/node'; async function trackError(error) { Sentry.captureException(error, { tags: { error_type: error.type, error_code: error.code, request_id: error.request_id }, extra: { param: error.param, api_version: 'v1' } }); } ``` ## 🆘 Getting Help Complete list of all error codes Contact support with request IDs Check current API status Get help from the community # Finance API Source: https://docs.stateset.com/stateset-commerce-api-reference/finance Trade finance, invoice factoring, and lending powered by native stablecoins and smart contracts **Enterprise Access**: Contact [sales@stateset.com](mailto:sales@stateset.com) for access to advanced finance features and higher limits. # Finance API: Revolutionizing Trade Finance StateSet's Finance API transforms traditional trade finance by leveraging blockchain technology and stablecoins to provide instant liquidity, automated compliance, and global accessibility. Eliminate weeks of waiting and mountains of paperwork with our programmable finance infrastructure. ## 🌟 Why StateSet Finance? Factor invoices and access capital in minutes, not months Finance trade in 195+ countries with built-in compliance AI-powered risk assessment and automated payment flows ## 📊 Impact Metrics
\$500M+
Trade Financed
2 min
Avg. Funding Time
2.5%
Avg. Discount Rate
99.8%
Repayment Rate
## 🚀 Quick Start ```javascript theme={null} import { StateSet } from '@stateset/sdk'; const stateset = new StateSet({ apiKey: 'sk_test_...' }); // Factor an invoice for instant liquidity const factoring = await stateset.finance.factorInvoice({ invoice_id: 'inv_12345', amount: '50000.00', discount_rate: 0.025, // 2.5% discount buyer_id: 'buyer_abc123', recourse: false // Non-recourse factoring }); console.log(`Received ${factoring.advance_amount} USDC instantly`); // Output: Received 48750.00 USDC instantly ``` ```javascript theme={null} // Finance a purchase order before fulfillment const poFinancing = await stateset.finance.financePurchaseOrder({ po_id: 'po_67890', amount: '100000.00', supplier_id: 'supplier_xyz789', delivery_date: '2024-08-15', collateral_type: 'buyer_guarantee' }); console.log(`PO financed: ${poFinancing.funded_amount} USDC`); // Funds released to supplier for production ``` ```javascript theme={null} // Borrow against tokenized assets const loan = await stateset.finance.createLoan({ collateral: { type: 'tokenized_inventory', value: '150000.00', token_ids: ['inv_token_123', 'inv_token_456'] }, loan_amount: '100000.00', term_days: 90, interest_rate: 0.08 // 8% APR }); console.log(`Loan approved: ${loan.id}`); // Instant USDC disbursement ``` ## 💼 Product Suite ### Invoice Factoring Transform outstanding invoices into immediate working capital with our AI-powered factoring platform. 1. **Submit Invoice**: Upload or connect your invoice via API 2. **Instant Assessment**: AI evaluates buyer creditworthiness in seconds 3. **Get Offer**: Receive competitive factoring rate (typically 2-5%) 4. **Instant Payment**: Accept offer and receive USDC immediately 5. **We Collect**: We handle collection from your buyer at maturity * ⚡ **Instant Liquidity**: Access 95-98% of invoice value immediately * 💰 **Better Rates**: 2-5% vs traditional 10-30% * 🌍 **Global Coverage**: Factor invoices from buyers worldwide * 🔒 **Non-Recourse Options**: Transfer credit risk to us * 🤖 **Automated Process**: No paperwork or manual approvals * Invoice amount: $1,000 - $10,000,000 * Buyer must be a registered business * Invoice must be for completed goods/services * Maximum term: 120 days * No previous factoring on same invoice ### Purchase Order Financing Fund production and fulfill large orders without depleting working capital. * **Manufacturing**: Fund raw materials and production costs * **Wholesale**: Purchase inventory for large orders * **Import/Export**: Finance international trade transactions * **Seasonal Business**: Handle demand spikes without cash strain * Funds held in escrow until milestones met * Automatic release based on IoT/delivery confirmation * Multi-party signatures for large transactions * Dispute resolution via on-chain arbitration ### Dynamic Discounting Optimize payment timing between buyers and suppliers with win-win early payment discounts. * Earn 15-30% APR equivalent returns * Strengthen supplier relationships * Improve supply chain resilience * Access early payment on demand * Predictable cash flow * Lower financing costs ## 💵 Invoice Factoring API ### Factor Invoice ```http theme={null} POST /v1/finance/invoices/factor ``` **Request Body:** ```json theme={null} { "invoice_id": "inv_12345", "amount": "50000.00", "currency": "USDC", "discount_rate": 0.025, "buyer": { "id": "did:stateset:buyer:abc123", "credit_rating": "AAA", "payment_history": "excellent" }, "terms": { "net_days": 30, "due_date": "2024-07-25" }, "recourse": false } ``` **Response:** ```json theme={null} { "factoring_id": "fact_8y4mQr5oP2", "invoice_id": "inv_12345", "status": "FUNDED", "advance_amount": "48750.00", "discount_amount": "1250.00", "discount_rate": 0.025, "funded_at": "2024-06-25T12:05:00Z", "maturity_date": "2024-07-25T23:59:59Z", "transaction_hash": "0x742d35Cc6634C0532925a3b8D097C00D4dfece08" } ``` ### Get Factoring Options ```http theme={null} GET /v1/finance/invoices/{invoice_id}/factoring-options ``` **Response:** ```json theme={null} { "invoice_id": "inv_12345", "amount": "50000.00", "options": [ { "provider": "StateSet Pool Alpha", "discount_rate": 0.02, "advance_amount": "49000.00", "funding_time": "instant", "recourse": false, "rating": "AAA" }, { "provider": "Institutional Lender", "discount_rate": 0.015, "advance_amount": "49250.00", "funding_time": "1_hour", "recourse": false, "rating": "AA+" } ], "risk_assessment": { "buyer_score": 95, "payment_probability": 0.99, "recommended_rate": 0.02 } } ``` ### Track Factored Invoice ```http theme={null} GET /v1/finance/factoring/{factoring_id} ``` **Response:** ```json theme={null} { "id": "fact_8y4mQr5oP2", "invoice_id": "inv_12345", "status": "ACTIVE", "amount": "50000.00", "advance_paid": "48750.00", "discount": "1250.00", "days_remaining": 15, "payment_tracking": { "buyer_notified": true, "payment_link_sent": true, "reminder_sent": false }, "timeline": [ { "event": "FACTORED", "timestamp": "2024-06-25T12:05:00Z", "amount": "48750.00" }, { "event": "BUYER_NOTIFIED", "timestamp": "2024-06-25T12:06:00Z" } ] } ``` ## 📦 Purchase Order Financing API ### Finance Purchase Order ```http theme={null} POST /v1/finance/purchase-orders/finance ``` **Request Body:** ```json theme={null} { "purchase_order_id": "po_67890", "supplier_id": "did:stateset:supplier:xyz789", "buyer_id": "did:stateset:buyer:abc123", "amount": "100000.00", "currency": "USDC", "financing_terms": { "advance_percentage": 0.8, "fee_percentage": 0.03, "payment_terms": "net_60" }, "delivery_terms": { "incoterm": "FOB", "expected_delivery": "2024-08-15", "delivery_address": "123 Main St, San Francisco, CA" }, "collateral": { "type": "purchase_order", "insurance_required": true } } ``` **Response:** ```json theme={null} { "financing_id": "pof_9x3kLm8nR5", "purchase_order_id": "po_67890", "status": "APPROVED", "advance_amount": "80000.00", "total_fees": "3000.00", "funding_schedule": [ { "milestone": "ORDER_CONFIRMED", "amount": "40000.00", "funded_at": "2024-06-25T12:10:00Z" }, { "milestone": "PRODUCTION_COMPLETE", "amount": "40000.00", "estimated_date": "2024-08-01" } ], "repayment_due": "2024-10-15", "contract_address": "stateset1contract456..." } ``` ### Get Financing Options ```http theme={null} GET /v1/finance/purchase-orders/{po_id}/financing-options ``` **Response:** ```json theme={null} { "purchase_order_id": "po_67890", "amount": "100000.00", "supplier_rating": "A+", "buyer_rating": "AAA", "financing_options": [ { "provider": "StateSet Capital", "advance_percentage": 0.85, "fee_rate": 0.025, "approval_time": "instant", "requirements": ["insurance", "shipping_docs"] }, { "provider": "Trade Finance Pool", "advance_percentage": 0.8, "fee_rate": 0.02, "approval_time": "2_hours", "requirements": ["credit_check", "collateral"] } ], "risk_factors": { "supplier_history": "excellent", "product_category": "low_risk", "shipping_route": "established", "insurance_available": true } } ``` ## 🏦 Collateralized Lending API ### Create Loan Request ```http theme={null} POST /v1/finance/loans/request ``` **Request Body:** ```json theme={null} { "borrower_id": "did:stateset:borrower:def456", "loan_amount": "25000.00", "currency": "USDC", "loan_purpose": "working_capital", "term_months": 12, "collateral": [ { "type": "cryptocurrency", "asset": "STATE", "amount": "50000.00", "current_value": "50000.00", "ltv_ratio": 0.5 }, { "type": "invoice", "asset_id": "inv_78901", "face_value": "15000.00", "ltv_ratio": 0.8 } ], "requested_rate": 0.08 } ``` **Response:** ```json theme={null} { "loan_id": "loan_5z8nPq3oW7", "status": "PENDING_APPROVAL", "requested_amount": "25000.00", "approved_amount": "25000.00", "interest_rate": 0.075, "term_months": 12, "monthly_payment": "2256.50", "total_collateral_value": "65000.00", "ltv_ratio": 0.38, "approval_time": "instant", "funds_available": "2024-06-25T12:15:00Z" } ``` ### Loan Management ```http theme={null} POST /v1/finance/loans/{loan_id}/drawdown ``` **Request Body:** ```json theme={null} { "amount": "25000.00", "destination_wallet": "stateset1borrower123...", "purpose": "Inventory purchase for Q3 orders" } ``` **Response:** ```json theme={null} { "drawdown_id": "draw_4k7mLx9nQ2", "loan_id": "loan_5z8nPq3oW7", "amount": "25000.00", "funded_at": "2024-06-25T12:20:00Z", "transaction_hash": "0x9f2e45Bb8734C1523456a7b9E087F00E4dfebe19", "repayment_schedule": [ { "payment_number": 1, "due_date": "2024-07-25", "principal": "1923.17", "interest": "333.33", "total": "2256.50" } ] } ``` ## 🎯 Automated Risk Management ### Credit Scoring ```typescript theme={null} // Real-time credit assessment const creditScore = await client.finance.assessCredit({ entity_id: 'did:stateset:company:abc123', factors: [ 'payment_history', 'financial_statements', 'industry_trends', 'blockchain_activity' ] }); // Response { "entity_id": "did:stateset:company:abc123", "credit_score": 785, "rating": "A+", "factors": { "payment_history": { "score": 95, "on_time_percentage": 0.98, "avg_days_early": 2.3 }, "financial_health": { "score": 88, "debt_to_equity": 0.35, "current_ratio": 2.1 }, "blockchain_activity": { "score": 92, "transaction_volume": "500000.00", "network_reputation": "excellent" } }, "recommended_limits": { "factoring": "100000.00", "lending": "50000.00", "trade_finance": "250000.00" } } ``` ### Dynamic Pricing ```typescript theme={null} // Market-driven interest rates const pricing = await client.finance.getPricing({ product: 'invoice_factoring', amount: '50000.00', term_days: 30, risk_profile: { buyer_rating: 'AAA', seller_rating: 'A+', industry: 'technology' } }); // Response { "base_rate": 0.02, "risk_premium": 0.005, "final_rate": 0.025, "pricing_factors": { "market_conditions": { "liquidity": "high", "demand": "moderate", "adjustment": -0.002 }, "counterparty_risk": { "buyer_score": 95, "seller_score": 88, "adjustment": 0.003 }, "product_risk": { "default_rate": 0.001, "recovery_rate": 0.98, "adjustment": 0.002 } }, "expires_at": "2024-06-25T13:00:00Z" } ``` ## 🌍 Cross-Border Trade Finance ### Letters of Credit ```typescript theme={null} // Digital letter of credit const lc = await client.finance.createLetterOfCredit({ importer: 'did:stateset:importer:usa123', exporter: 'did:stateset:exporter:chn456', amount: '500000.00', currency: 'USDC', goods_description: '1000 units Model X widgets', shipping_terms: { incoterm: 'CIF', port_of_loading: 'Shanghai', port_of_discharge: 'Los Angeles', latest_shipment: '2024-08-15' }, documents_required: [ 'commercial_invoice', 'bill_of_lading', 'packing_list', 'certificate_of_origin' ], expiry_date: '2024-09-30' }); // Automated document verification via oracles const verification = await client.finance.verifyDocuments(lc.id, { documents: uploadedDocs, verify_authenticity: true, check_compliance: true }); ``` ### Trade Credit Insurance ```typescript theme={null} // Parametric insurance for trade finance const insurance = await client.finance.createTradeInsurance({ policy_type: 'trade_credit', insured_amount: '500000.00', coverage: { non_payment: true, political_risk: true, currency_inconvertibility: false }, buyer: 'did:stateset:buyer:xyz789', premium_rate: 0.015, coverage_period: { start: '2024-07-01', end: '2024-12-31' }, payment_method: 'usdc' }); // Smart contract automatically pays claims if (paymentOverdue > 90 && verifiedDefault) { await insurance.contract.payoutClaim({ amount: insuredAmount, recipient: beneficiaryWallet }); } ``` ## 📊 Liquidity Pools & Yield ### Liquidity Provider Program ```typescript theme={null} // Earn yield by providing liquidity const liquidityPosition = await client.finance.addLiquidity({ pool: 'invoice_factoring_pool', amount: '100000.00', currency: 'USDC', lock_period: '30_days', min_yield: 0.08 // 8% APR minimum }); // Response { "position_id": "lp_3k8mRx7nQ9", "pool": "invoice_factoring_pool", "amount_deposited": "100000.00", "shares_minted": "100000.00", "current_apr": 0.095, "projected_yield_30d": "791.67", "risk_level": "low", "withdraw_available": "2024-07-25T12:00:00Z" } ``` ### Yield Farming ```typescript theme={null} // Stake LP tokens for additional rewards const farming = await client.finance.stakeLPTokens({ lp_token_id: 'lp_3k8mRx7nQ9', farm: 'state_rewards_farm', amount: '100000.00' }); // Earn both: // 1. Base APR from factoring fees (9.5%) // 2. STATE token rewards (3.2% additional) // Total APY: 12.7% ``` ## 🔐 Security & Compliance ### Multi-Signature Workflows ```typescript theme={null} // Large transactions require multiple approvals const largeLoan = await client.finance.createLoan({ amount: '1000000.00', // $1M loan requires_multisig: true, approvers: [ 'did:stateset:officer:cfo', 'did:stateset:officer:risk', 'did:stateset:board:chair' ], threshold: 2 // 2 of 3 signatures required }); // Approval workflow for (const approver of requiredApprovers) { await client.finance.signApproval(largeLoan.id, { signer: approver, decision: 'approve', notes: 'Reviewed financials and risk assessment' }); } ``` ### Compliance Monitoring ```typescript theme={null} // Real-time compliance checking const compliance = await client.compliance.monitor({ transaction_id: 'txn_abc123', checks: [ 'sanctions_screening', 'aml_monitoring', 'kyc_verification', 'regulatory_limits' ], jurisdictions: ['US', 'EU', 'UK'] }); // Automatic reporting if (compliance.flagged) { await client.compliance.generateSAR({ transaction_id: compliance.transaction_id, reason: compliance.flag_reason, submit_to: ['fincen', 'eu_authorities'] }); } ``` ## 🚀 Advanced Features ### Parametric Insurance ```typescript theme={null} // Smart contract insurance const insurance = await client.finance.createParametricInsurance({ trigger_type: 'oracle_data', coverage_amount: '100000.00', parameters: { weather_station: 'NOAA_SF_001', trigger_condition: 'rainfall > 5_inches_24h', measurement_period: '2024-07-01 to 2024-07-31' }, premium: '2500.00', automatic_payout: true }); // Automatic claim payment when conditions met if (oracleData.rainfall > triggeLevell) { insurance.contract.payout(); } ``` ### AI-Powered Analytics ```typescript theme={null} // Machine learning risk assessment const riskAnalysis = await client.finance.analyzeRisk({ entity: 'did:stateset:company:xyz', analysis_type: 'comprehensive', data_sources: [ 'financial_statements', 'payment_history', 'market_data', 'social_sentiment', 'supply_chain_data' ] }); // Response includes ML-generated insights { "risk_score": 78, "confidence": 0.94, "key_factors": [ "Strong payment history (98% on-time)", "Growing market share in sector", "Diversified supplier base" ], "risk_factors": [ "High customer concentration (top 3 = 60% revenue)", "Increasing raw material costs" ], "recommended_limits": { "factoring": "250000.00", "lending": "100000.00" } } ``` ## 📈 Performance Metrics ### By the Numbers | Metric | Value | Industry Comparison | | --------------------- | ---------- | ------------------- | | Funding Speed | 2 minutes | Banks: 3-6 months | | Transaction Cost | \$0.01 | Banks: \$25-100 | | Default Rate | 0.1% | Industry: 2-5% | | Borrower Satisfaction | 98% | Banks: 65% | | API Uptime | 99.99% | Enterprise standard | | Processing Capacity | 10,000 TPS | Unlimited scale | ### Success Stories **Manufacturing SME in Vietnam** * Needed \$500K to fulfill large US order * Funded in 3 minutes vs 3 months traditional * Saved \$15K in fees (3% vs 6% bank rate) * Scaled production 300% in 6 months **Tech Startup in Nigeria** * Factored invoices for immediate cash flow * Accessed capital without US banking relationship * Reduced payment cycles from 90 to 2 days * Reinvested in R\&D and hiring ## 🔗 Related APIs * [Invoices API](/stateset-commerce-api-reference/invoices) - Create and manage invoices * [Purchase Orders API](/stateset-commerce-api-reference/purchaseorders) - PO management * [Loans API](/stateset-commerce-api-reference/loans) - Lending operations * [USDC Integration](/stateset-commerce-api-reference/usdc) - Native USDC support * [Orders API](/stateset-commerce-api-reference/orders) - Order management *** *Ready to access capital? [Start your application →](https://app.stateset.network/finance)* # Getting Started Source: https://docs.stateset.com/stateset-commerce-api-reference/getting-started Start building on StateSet Commerce Network in minutes **New to StateSet?** This guide will walk you through everything from account creation to your first transaction. # Getting Started with StateSet Welcome to StateSet Commerce Network! This guide will help you get up and running quickly, whether you're building an e-commerce platform, financial application, or autonomous agent system. ## 🎯 Choose Your Path Accept payments and manage orders Invoice factoring and trade finance API integration and automation ## 📋 Prerequisites Before you begin, make sure you have: * A modern web browser * Basic understanding of REST APIs * Node.js 16+ (for SDK usage) * A business email address ## 🚀 5-Minute Setup Visit [dashboard.stateset.com](https://dashboard.stateset.com) and sign up: 1. Click "Get Started" 2. Enter your business details 3. Verify your email 4. Complete KYC (takes \~2 minutes) KYC is required for mainnet access. Use testnet for immediate development. Once logged in, navigate to the API section: 1. Go to Settings → API Keys 2. Click "Create New Key" 3. Name your key (e.g., "Development") 4. Select permissions 5. Copy your secret key immediately Your secret key is shown only once. Store it securely! ```bash theme={null} # Add to your .env file STATESET_API_KEY=sk_test_your_actual_key_here STATESET_WEBHOOK_SECRET=whsec_your_webhook_secret_here ``` Choose your preferred language and install the SDK: ```bash Node.js theme={null} npm install @stateset/sdk ``` ```bash Python theme={null} pip install stateset ``` ```bash Go theme={null} go get github.com/stateset/stateset-go ``` Test your setup with a simple balance check: ```javascript theme={null} import { StateSet } from '@stateset/sdk'; // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY }); async function checkBalance() { const balance = await stateset.account.balance(); logger.info('Your balance', { balance }); } checkBalance(); ``` ## 💸 E-Commerce Quickstart Build a complete payment flow in minutes: ### 1. Create a Product Catalog ```javascript theme={null} // Create your first product const product = await stateset.products.create({ name: 'Premium Widget', price: 99.99, currency: 'ssusd', inventory: 100, description: 'Our best-selling widget', images: ['https://example.com/widget.jpg'] }); ``` ### 2. Accept Payments ```javascript theme={null} // Create a checkout session const checkout = await stateset.checkout.create({ items: [{ product_id: product.id, quantity: 2 }], success_url: 'https://yoursite.com/success', cancel_url: 'https://yoursite.com/cancel', customer_email: 'customer@example.com' }); // Redirect customer to checkout window.location.href = checkout.url; ``` ### 3. Handle Order Fulfillment ```javascript theme={null} // Listen for successful payments stateset.webhooks.on('checkout.completed', async (event) => { const order = event.data; // Create shipping label const shipping = await stateset.shipping.create({ order_id: order.id, carrier: 'fedex', service: 'ground', address: order.shipping_address }); // Update order status await stateset.orders.update(order.id, { status: 'shipped', tracking_number: shipping.tracking_number }); }); ``` ### Complete E-Commerce Example ```javascript Next.js theme={null} // pages/api/create-checkout.js import { StateSet } from '@stateset/sdk'; const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY }); export default async function handler(req, res) { if (req.method === 'POST') { const { items } = req.body; try { const checkout = await stateset.checkout.create({ items, success_url: `${req.headers.origin}/success`, cancel_url: `${req.headers.origin}/cart` }); res.status(200).json({ url: checkout.url }); } catch (error) { res.status(400).json({ error: error.message }); } } } ``` ```python Flask theme={null} from flask import Flask, request, jsonify from stateset import StateSet import os app = Flask(__name__) stateset = StateSet(api_key=os.getenv('STATESET_API_KEY')) @app.route('/api/create-checkout', methods=['POST']) def create_checkout(): data = request.json try: checkout = stateset.checkout.create( items=data['items'], success_url=f"{request.host_url}success", cancel_url=f"{request.host_url}cart" ) return jsonify({'url': checkout.url}) except Exception as e: return jsonify({'error': str(e)}), 400 ``` ## 💰 Finance Quickstart Set up invoice factoring for instant liquidity: ### 1. Connect Your Accounting System ```javascript theme={null} // Connect QuickBooks, Xero, or upload invoices const connection = await stateset.integrations.create({ provider: 'quickbooks', credentials: { client_id: process.env.QB_CLIENT_ID, client_secret: process.env.QB_CLIENT_SECRET } }); // Sync invoices automatically const invoices = await stateset.invoices.sync({ integration_id: connection.id, sync_unpaid: true }); ``` ### 2. Factor an Invoice ```javascript theme={null} // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; // Get factoring options const options = await stateset.finance.getFactoringOptions({ invoice_id: 'inv_123', amount: '50000.00' }); // Choose best option and factor const factoring = await stateset.finance.factorInvoice({ invoice_id: 'inv_123', option_id: options[0].id, // Best rate advance_percentage: 0.95 // 95% advance }); logger.info('Invoice factored', { advanceAmount: factoring.advance_amount }); ``` ## 🤖 Developer Quickstart Build powerful integrations with StateSet: ### WebSocket Subscriptions ```javascript theme={null} // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; // Real-time event streaming const ws = stateset.subscriptions.connect(); // Subscribe to all order events ws.subscribe('orders.*', (event) => { logger.info('Order event received', { type: event.type, data: event.data }); }); // Subscribe to specific payment events ws.subscribe('payments.succeeded', async (event) => { await processSuccessfulPayment(event.data); }); ``` ### Batch Operations ```javascript theme={null} // Batch create orders const orders = await stateset.orders.batchCreate([ { customer: 'cust_123', items: [...], total: 100.00 }, { customer: 'cust_456', items: [...], total: 200.00 }, { customer: 'cust_789', items: [...], total: 300.00 } ]); // Batch transfer stablecoins const transfers = await stateset.stablecoin.batchTransfer({ transfers: [ { to: 'address1', amount: '100.00', memo: 'Refund' }, { to: 'address2', amount: '200.00', memo: 'Payment' }, { to: 'address3', amount: '300.00', memo: 'Salary' } ] }); ``` ### GraphQL API ```graphql theme={null} # Advanced querying with GraphQL query GetOrderAnalytics($startDate: Date!, $endDate: Date!) { orders( where: { created_at: { _gte: $startDate, _lte: $endDate }, status: "completed" } ) { aggregate { count sum { total } avg { total } } nodes { id customer { email total_spent } items { product { name category } quantity subtotal } } } } ``` ## 🧪 Testing Your Integration ### Use Test Mode All API keys have test mode equivalents: ```javascript theme={null} // Test mode - no real money moves const testClient = new StateSet({ apiKey: 'sk_test_...' // Test key }); // Create test payments const payment = await testClient.payments.create({ amount: 100.00, currency: 'ssusd', // Use test card numbers source: 'card_test_success' }); ``` ### Test Card Numbers | Card Number | Scenario | | --------------------- | ------------------ | | `4242 4242 4242 4242` | Success | | `4000 0000 0000 0002` | Decline | | `4000 0000 0000 9995` | Insufficient funds | ### Webhook Testing ```javascript theme={null} // Use ngrok for local testing // 1. Install ngrok: brew install ngrok // 2. Start tunnel: ngrok http 3000 // 3. Use ngrok URL for webhooks const webhook = await stateset.webhooks.create({ url: 'https://abc123.ngrok.io/webhooks', events: ['*'], // All events description: 'Local development' }); ``` ## 🚢 Going to Production ### Pre-launch Checklist * [ ] Use environment variables for API keys * [ ] Implement webhook signature verification * [ ] Enable HTTPS on all endpoints * [ ] Set up error monitoring (Sentry, etc.) * [ ] Implement rate limiting * [ ] Add request/response logging * [ ] Implement caching where appropriate * [ ] Use pagination for large datasets * [ ] Optimize database queries * [ ] Set up CDN for static assets * [ ] Enable gzip compression * [ ] Monitor API response times * [ ] Handle all error scenarios * [ ] Implement retry logic * [ ] Set up automated testing * [ ] Create admin dashboards * [ ] Document API integrations * [ ] Train support team ### Switch to Production ```javascript theme={null} // Update your configuration const stateset = new StateSet({ apiKey: process.env.STATESET_LIVE_KEY, // Live key network: 'mainnet', options: { timeout: 30000, retries: 3 } }); // Verify production access const account = await stateset.account.retrieve(); // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; logger.info('Production account', { accountId: account.id }); logger.info('Live mode', { liveMode: account.live_mode }); // Should be true ``` ## 🆘 Getting Help Comprehensive guides and references Check system status and uptime Chat with developers and get help Contact our support team ## 🎉 Next Steps Now that you're set up, explore these resources: * [Build a complete e-commerce site](/tutorials/ecommerce) * [Implement invoice factoring](/tutorials/invoice-factoring) * [Deploy AI agents](/tutorials/ai-agents) * [Integrate with existing systems](/guides/integrations) *** **Ready to build?** You now have everything needed to start building on StateSet. If you have questions, our community is here to help! Connect with thousands of developers building the future of commerce # Global Commerce API Source: https://docs.stateset.com/stateset-commerce-api-reference/global-commerce Cross-border trade, compliance, and multi-currency commerce solutions # Global Commerce API: Powering International Trade StateSet's Global Commerce API enables seamless cross-border transactions with built-in compliance, multi-currency support, and automated trade documentation. Built on native USDC with instant settlement, it eliminates traditional barriers to international commerce. ## 🌍 Quick Start ```typescript theme={null} import { StateSetClient } from '@stateset/commerce-sdk'; const client = new StateSetClient({ endpoint: 'https://api.stateset.network', apiKey: process.env.STATESET_API_KEY }); // Create cross-border order with compliance const internationalOrder = await client.global.createOrder({ buyer: { country: 'US', entity_id: 'did:stateset:buyer:usa123' }, seller: { country: 'DE', entity_id: 'did:stateset:seller:ger456' }, items: [{ hs_code: '8471.30.01', // Computer parts description: 'Laptop processors', quantity: 100, unit_price: '299.99', origin_country: 'TW' }], shipping: { incoterm: 'DDP', method: 'air_freight' }, compliance: { auto_check: true, required_docs: ['commercial_invoice', 'packing_list'] } }); console.log(`International order ${internationalOrder.id} created with compliance checks`); ``` ## 🎯 Core Features ### Multi-Currency Support * 150+ fiat currencies with real-time rates * Automatic conversion to native USDC * Hedging against currency fluctuations * Local payment method support ### Compliance Automation * Real-time sanctions screening (OFAC, EU, UN) * Export control verification (EAR, ITAR) * Restricted party list checking * Country-specific regulatory compliance ### Trade Documentation * Automated document generation * Digital signatures and notarization * Blockchain-verified authenticity * Integration with customs systems ### Tax & Duty Calculation * VAT/GST calculation for 100+ countries * Import duty estimation * Free trade agreement benefits * Automated tax reporting ## 💱 Multi-Currency Orders API ### Create Multi-Currency Order ```http theme={null} POST /v1/global/orders ``` **Request Body:** ```json theme={null} { "buyer": { "entity_id": "did:stateset:buyer:usa123", "country": "US", "state": "CA", "tax_id": "12-3456789" }, "seller": { "entity_id": "did:stateset:seller:ger456", "country": "DE", "vat_number": "DE123456789" }, "items": [ { "sku": "LAPTOP-PRO-001", "description": "Professional Laptop", "hs_code": "8471.30.01", "quantity": 10, "unit_price": "999.00", "unit_price_currency": "EUR", "origin_country": "TW", "weight_kg": 2.5 } ], "currency_preferences": { "display_currency": "EUR", "payment_currency": "USDC", "hedge_enabled": true }, "shipping": { "incoterm": "DDP", "from_address": { "street": "Hauptstraße 123", "city": "Berlin", "postal_code": "10115", "country": "DE" }, "to_address": { "street": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } }, "trade_terms": { "payment_terms": "NET_30", "currency_rate_lock": true, "force_majeure_clause": true } } ``` **Response:** ```json theme={null} { "order_id": "gord_7x9kPm2nQ1", "status": "CREATED", "currency_conversion": { "display_total_eur": "9990.00", "payment_total_usdc": "10889.10", "exchange_rate": 1.09, "rate_locked_until": "2024-06-25T14:00:00Z" }, "tax_calculation": { "base_amount": "9990.00", "vat_rate": 0.19, "vat_amount": "1898.10", "import_duty_rate": 0.035, "import_duty": "349.65", "total_taxes": "2247.75" }, "compliance_status": { "sanctions_check": "CLEAR", "export_control": "CLEAR", "restricted_party": "CLEAR", "documentation_required": [ "commercial_invoice", "packing_list", "certificate_of_origin" ] }, "shipping_estimate": { "method": "DHL_EXPRESS", "cost_usdc": "156.50", "transit_days": 3, "tracking_available": true } } ``` ### Get Exchange Rates ```http theme={null} GET /v1/global/exchange-rates?base=EUR&targets=USD,USDC,GBP ``` **Response:** ```json theme={null} { "base_currency": "EUR", "timestamp": "2024-06-25T12:00:00Z", "rates": { "USD": 1.0847, "USDC": 1.0889, "GBP": 0.8521 }, "spread": { "buy": 0.001, "sell": 0.001 }, "rate_lock_available": true, "lock_duration_max": "24_hours" } ``` ## 🛂 Compliance & Screening API ### Sanctions Screening ```http theme={null} POST /v1/global/compliance/sanctions-screen ``` **Request Body:** ```json theme={null} { "entities": [ { "type": "individual", "name": "John Smith", "date_of_birth": "1980-01-15", "nationality": "US", "address": { "country": "US", "state": "NY" } }, { "type": "organization", "name": "Example Corp Ltd", "registration_number": "12345678", "country": "GB", "business_type": "technology" } ], "screening_lists": [ "OFAC_SDN", "OFAC_SSI", "EU_SANCTIONS", "UN_SANCTIONS", "UK_SANCTIONS" ], "match_threshold": 0.85 } ``` **Response:** ```json theme={null} { "screening_id": "scr_8y4mQr5oP2", "status": "COMPLETED", "timestamp": "2024-06-25T12:05:00Z", "results": [ { "entity_index": 0, "status": "CLEAR", "matches": [], "confidence": 1.0 }, { "entity_index": 1, "status": "CLEAR", "matches": [], "confidence": 1.0 } ], "lists_checked": [ "OFAC_SDN", "OFAC_SSI", "EU_SANCTIONS", "UN_SANCTIONS", "UK_SANCTIONS" ], "next_screening_due": "2024-06-26T12:05:00Z" } ``` ### Export Control Check ```http theme={null} POST /v1/global/compliance/export-control ``` **Request Body:** ```json theme={null} { "items": [ { "description": "High-performance computing processors", "eccn": "3A001", "hs_code": "8542.31.00", "value": "50000.00", "quantity": 100 } ], "destination_country": "CN", "end_user": { "name": "Beijing Tech Corp", "type": "commercial", "industry": "telecommunications" }, "intended_use": "Commercial data center equipment" } ``` **Response:** ```json theme={null} { "control_check_id": "ecc_3k8mRx7nQ9", "status": "REQUIRES_LICENSE", "items_assessment": [ { "item_index": 0, "classification": "3A001.a.1", "control_reason": "NS - National Security", "license_required": true, "license_exception_available": false, "restricted_countries": ["CN", "RU", "IR"], "recommendation": "Apply for export license via SNAP-R system" } ], "license_application": { "estimated_processing_time": "60-90 days", "application_fee": "0.00", "required_documents": [ "technical_specifications", "end_user_statement", "import_certificate" ] } } ``` ## 📋 Trade Documentation API ### Generate Commercial Invoice ```http theme={null} POST /v1/global/documents/commercial-invoice ``` **Request Body:** ```json theme={null} { "order_id": "gord_7x9kPm2nQ1", "template": "standard_international", "customization": { "logo_url": "https://company.com/logo.png", "terms_and_conditions": "Payment due within 30 days...", "notes": "Handle with care - fragile items" }, "signatures_required": [ { "signatory": "did:stateset:seller:ger456", "role": "exporter", "signature_type": "digital" } ] } ``` **Response:** ```json theme={null} { "document_id": "doc_5z8nPq3oW7", "type": "commercial_invoice", "status": "GENERATED", "order_id": "gord_7x9kPm2nQ1", "document_url": "https://docs.stateset.network/doc_5z8nPq3oW7.pdf", "hash": "0x742d35Cc6634C0532925a3b8D097C00D4dfece08", "blockchain_proof": { "transaction_hash": "0x9f2e45Bb8734C1523456a7b9E087F00E4dfebe19", "block_number": 1542389, "timestamp": "2024-06-25T12:10:00Z" }, "signatures": [ { "signatory": "did:stateset:seller:ger456", "status": "PENDING", "signature_url": "https://sign.stateset.network/doc_5z8nPq3oW7" } ], "customs_integration": { "us_customs": "ABI_READY", "eu_customs": "ICS2_READY", "tracking_number": "SSCI2024062501" } } ``` ### Generate Certificate of Origin ```http theme={null} POST /v1/global/documents/certificate-of-origin ``` **Request Body:** ```json theme={null} { "order_id": "gord_7x9kPm2nQ1", "origin_criteria": { "preferential_origin": true, "trade_agreement": "USMCA", "manufacturing_country": "TW", "materials_origin": [ {"country": "TW", "percentage": 70}, {"country": "JP", "percentage": 30} ] }, "chamber_of_commerce": { "issue_authority": "Taiwan Chamber of Commerce", "certification_required": true } } ``` **Response:** ```json theme={null} { "document_id": "coo_4k7mLx9nQ2", "type": "certificate_of_origin", "status": "CERTIFIED", "trade_agreement": "USMCA", "preferential_treatment": { "eligible": true, "duty_savings": "1748.25", "tariff_reduction": "from 5% to 0%" }, "certification": { "authority": "Taiwan Chamber of Commerce", "certificate_number": "COO-TW-2024-062501", "issued_date": "2024-06-25", "valid_until": "2024-12-25" }, "blockchain_verification": { "immutable_hash": "0x3a8f72Dd9865E1234567b2c3F0987A00B5efghi01", "verification_url": "https://verify.stateset.network/coo_4k7mLx9nQ2" } } ``` ## 💰 Tax & Duty Calculation API ### Calculate International Taxes ```http theme={null} POST /v1/global/tax/calculate ``` **Request Body:** ```json theme={null} { "shipment": { "from_country": "DE", "to_country": "US", "to_state": "CA" }, "items": [ { "hs_code": "8471.30.01", "description": "Laptop computers", "value": "9990.00", "currency": "EUR", "quantity": 10, "weight_kg": 25.0, "origin_country": "TW" } ], "shipping_cost": "150.00", "insurance_cost": "50.00", "incoterm": "DDP", "trade_agreements": ["USMCA", "EU-TAIWAN_FTA"] } ``` **Response:** ```json theme={null} { "calculation_id": "tax_6j9nSt4pX8", "total_value_usd": "10839.30", "duties": { "base_rate": 0.035, "preferential_rate": 0.00, "applied_rate": 0.00, "duty_amount": "0.00", "trade_agreement": "Most Favored Nation", "savings": "379.38" }, "taxes": { "federal": { "type": "import_tax", "rate": 0.00, "amount": "0.00" }, "state": { "type": "sales_tax", "rate": 0.0725, "amount": "785.85", "jurisdiction": "California" } }, "fees": { "merchandise_processing": "54.20", "harbor_maintenance": "25.10", "customs_brokerage": "125.00" }, "total_charges": { "duties": "0.00", "taxes": "785.85", "fees": "204.30", "total": "990.15" }, "documentation": { "tariff_classification": "8471.30.01.00", "ruling_references": ["HQ 561234", "NY N123456"], "effective_date": "2024-06-25" } } ``` ### Get Duty Rates ```http theme={null} GET /v1/global/duty-rates?hs_code=8471.30.01&from_country=TW&to_country=US ``` **Response:** ```json theme={null} { "hs_code": "8471.30.01", "description": "Portable automatic data processing machines, weighing not more than 10 kg", "rates": [ { "country_pair": "TW-US", "mfn_rate": 0.00, "applied_rate": 0.00, "trade_agreement": "Most Favored Nation", "effective_date": "2019-01-01" } ], "additional_charges": [ { "type": "merchandise_processing_fee", "rate": "0.3464%", "minimum": "27.23", "maximum": "528.33" } ], "special_programs": [ { "program": "Generalized System of Preferences", "eligible": false, "reason": "Country not eligible" } ] } ``` ## 🚚 International Shipping API ### Get Shipping Quotes ```http theme={null} POST /v1/global/shipping/quotes ``` **Request Body:** ```json theme={null} { "from_address": { "street": "Hauptstraße 123", "city": "Berlin", "postal_code": "10115", "country": "DE" }, "to_address": { "street": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "packages": [ { "weight_kg": 25.0, "dimensions_cm": { "length": 60, "width": 40, "height": 30 }, "value": "10000.00", "currency": "EUR", "dangerous_goods": false } ], "service_level": ["standard", "express", "economy"], "insurance_required": true, "signature_required": true } ``` **Response:** ```json theme={null} { "quote_id": "shq_7m3kLx8nR4", "valid_until": "2024-06-25T18:00:00Z", "options": [ { "carrier": "DHL_EXPRESS", "service": "DHL Express Worldwide", "cost": { "shipping": "186.50", "fuel_surcharge": "18.65", "insurance": "25.00", "total": "230.15", "currency": "EUR" }, "transit_time": { "min_days": 2, "max_days": 3, "delivery_by": "2024-06-28T18:00:00Z" }, "features": [ "tracking", "signature_required", "insurance_included", "customs_clearance" ] }, { "carrier": "FEDEX_INTERNATIONAL", "service": "FedEx International Priority", "cost": { "shipping": "198.75", "fuel_surcharge": "19.88", "insurance": "25.00", "total": "243.63", "currency": "EUR" }, "transit_time": { "min_days": 2, "max_days": 4, "delivery_by": "2024-06-29T18:00:00Z" }, "features": [ "tracking", "signature_required", "insurance_included", "money_back_guarantee" ] } ] } ``` ### Create International Shipment ```http theme={null} POST /v1/global/shipping/shipments ``` **Request Body:** ```json theme={null} { "quote_id": "shq_7m3kLx8nR4", "selected_option": 0, "order_id": "gord_7x9kPm2nQ1", "customs_documents": [ { "type": "commercial_invoice", "document_id": "doc_5z8nPq3oW7" }, { "type": "certificate_of_origin", "document_id": "coo_4k7mLx9nQ2" } ], "pickup": { "date": "2024-06-26", "time_window": "09:00-17:00", "special_instructions": "Ring doorbell twice" } } ``` **Response:** ```json theme={null} { "shipment_id": "ship_9k5mNx2oQ6", "carrier": "DHL_EXPRESS", "tracking_number": "1234567890", "status": "SCHEDULED_FOR_PICKUP", "pickup": { "scheduled_date": "2024-06-26", "time_window": "09:00-17:00", "confirmation_number": "DHL-PKP-789012" }, "delivery_estimate": "2024-06-28T18:00:00Z", "shipping_label": { "url": "https://labels.stateset.network/ship_9k5mNx2oQ6.pdf", "format": "PDF_A4" }, "customs_tracking": { "status": "DOCUMENTS_SUBMITTED", "customs_reference": "CBP-2024-062501", "estimated_clearance": "2024-06-28T06:00:00Z" }, "cost": { "total_charged": "230.15", "currency": "EUR", "payment_method": "USDC" } } ``` ## 🔒 Trade Finance & Guarantees ### Request Letter of Credit ```http theme={null} POST /v1/global/trade-finance/letter-of-credit ``` **Request Body:** ```json theme={null} { "type": "documentary_credit", "applicant": { "entity_id": "did:stateset:importer:usa123", "name": "US Importer Corp", "country": "US" }, "beneficiary": { "entity_id": "did:stateset:exporter:ger456", "name": "German Exporter GmbH", "country": "DE" }, "amount": "100000.00", "currency": "USDC", "goods_description": "High-precision manufacturing equipment", "shipping_terms": { "incoterm": "CIF", "port_of_loading": "Hamburg", "port_of_discharge": "Los Angeles", "latest_shipment": "2024-08-15", "partial_shipments": false, "transhipment": true }, "documents_required": [ { "type": "commercial_invoice", "copies": 3, "signed": true }, { "type": "bill_of_lading", "copies": 1, "requirements": ["clean_on_board", "to_order_of_bank"] }, { "type": "packing_list", "copies": 2 }, { "type": "certificate_of_origin", "copies": 1, "authority": "German Chamber of Commerce" } ], "presentation_period": 21, "expiry_date": "2024-09-30", "expiry_place": "Hamburg, Germany", "confirmation_required": true } ``` **Response:** ```json theme={null} { "lc_id": "lc_8y4mQr5oP2", "lc_number": "SSLC-2024-062501", "status": "ISSUED", "issuing_bank": "StateSet Trade Bank", "confirming_bank": "Deutsche Handelsbank AG", "amount": "100000.00", "currency": "USDC", "collateral_required": { "amount": "25000.00", "type": "cash_deposit", "locked_until": "2024-10-15" }, "fees": { "issuance_fee": "500.00", "confirmation_fee": "750.00", "amendment_fee": "150.00", "total_fees": "1400.00" }, "smart_contract": { "address": "stateset1lc8y4mQr5oP2...", "auto_payment": true, "compliance_rules": [ "document_verification", "presentation_deadline", "discrepancy_handling" ] }, "blockchain_proof": { "transaction_hash": "0xab3f45Cc8634E1523456c7b2F097B00C4efece12", "block_number": 1542401, "immutable_record": true } } ``` ### Trade Credit Insurance ```http theme={null} POST /v1/global/trade-finance/credit-insurance ``` **Request Body:** ```json theme={null} { "policy_type": "trade_credit", "insured": { "entity_id": "did:stateset:seller:ger456", "annual_turnover": "5000000.00" }, "coverage": { "insured_percentage": 90, "maximum_amount": "500000.00", "currency": "USDC", "geographic_scope": ["US", "CA", "MX"], "coverage_types": [ "commercial_insolvency", "protracted_default", "political_risk" ] }, "buyers": [ { "entity_id": "did:stateset:buyer:usa123", "credit_limit": "250000.00", "payment_terms": "NET_60" } ], "premium_payment": { "frequency": "monthly", "method": "usdc_auto_debit" } } ``` **Response:** ```json theme={null} { "policy_id": "tci_5z8nPq3oW7", "policy_number": "SSTCI-2024-062501", "status": "ACTIVE", "coverage_start": "2024-07-01T00:00:00Z", "coverage_end": "2025-06-30T23:59:59Z", "premium": { "annual_premium": "7500.00", "monthly_payment": "625.00", "currency": "USDC", "next_payment_due": "2024-07-01" }, "coverage_details": { "maximum_claim": "500000.00", "deductible": "10000.00", "waiting_period_days": 90, "claim_payment_days": 30 }, "parametric_triggers": { "enabled": true, "auto_claim_processing": true, "oracle_sources": ["credit_rating_agencies", "payment_data"] } } ``` ## 📊 Global Commerce Analytics ### Trade Flow Analytics ```http theme={null} GET /v1/global/analytics/trade-flows?start_date=2024-01-01&end_date=2024-06-25 ``` **Response:** ```json theme={null} { "period": { "start": "2024-01-01", "end": "2024-06-25" }, "summary": { "total_orders": 1247, "total_value_usd": "15847293.45", "unique_countries": 47, "avg_order_value": "12701.75" }, "by_region": [ { "region": "North America", "orders": 456, "value": "6234567.89", "percentage": 39.3 }, { "region": "Europe", "orders": 389, "value": "4567890.12", "percentage": 28.8 }, { "region": "Asia Pacific", "orders": 289, "value": "3456789.01", "percentage": 21.8 } ], "top_corridors": [ { "from": "DE", "to": "US", "orders": 234, "value": "2987654.32" }, { "from": "CN", "to": "US", "orders": 198, "value": "2456789.01" } ], "compliance_metrics": { "sanctions_alerts": 0, "export_control_flags": 2, "documentation_delays": 8, "average_clearance_time_hours": 4.2 } } ``` ### Currency Performance ```http theme={null} GET /v1/global/analytics/currency?currencies=EUR,GBP,JPY&period=30d ``` **Response:** ```json theme={null} { "period": "30_days", "base_currency": "USDC", "currencies": [ { "currency": "EUR", "volume": "2847293.45", "avg_rate": 1.0847, "volatility": 0.023, "hedge_ratio": 0.85, "saved_fees": "14236.47" }, { "currency": "GBP", "volume": "1456789.01", "avg_rate": 0.7934, "volatility": 0.031, "hedge_ratio": 0.78, "saved_fees": "7283.95" } ], "hedging_performance": { "total_hedged_volume": "3847293.45", "average_savings": 0.0037, "hedging_cost": "14211.58", "net_benefit": "7308.84" } } ``` ## 🌐 Regional Compliance Modules ### EU GDPR Compliance ```typescript theme={null} // GDPR-compliant data handling const gdprCompliance = await client.global.compliance.gdpr({ data_subject: 'did:stateset:person:eu456', processing_purpose: 'trade_finance_kyc', lawful_basis: 'legitimate_interest', retention_period: '7_years', data_minimization: true, consent_required: false }); // Right to be forgotten await client.global.compliance.deletePersonalData({ subject_id: 'did:stateset:person:eu456', scope: 'all_data', retain_legal_obligations: true }); ``` ### US Export Administration Regulations (EAR) ```typescript theme={null} // EAR compliance checking const earCompliance = await client.global.compliance.ear({ items: [{ eccn: '3A001.a.1', description: 'High-performance processors' }], destination: 'CN', end_user: 'commercial_entity', license_exception: 'TSR' }); if (earCompliance.license_required) { const application = await client.global.compliance.applyExportLicense({ item_details: earCompliance.items, justification: 'Commercial use in non-sensitive application' }); } ``` ## 🔍 Advanced Features ### Blockchain Supply Chain Tracking ```typescript theme={null} // Track goods movement on blockchain const tracking = await client.global.tracking.create({ shipment_id: 'ship_9k5mNx2oQ6', checkpoints: [ 'manufacturing_complete', 'quality_inspection', 'customs_departure', 'in_transit', 'customs_arrival', 'final_delivery' ], iot_sensors: { temperature: true, humidity: true, shock: true, location: true }, notifications: { webhook_url: 'https://api.company.com/tracking', email_alerts: ['ops@company.com'], sms_alerts: ['+15551234567'] } }); // Real-time updates via IoT tracking.on('checkpoint_reached', (data) => { console.log(`Shipment reached ${data.checkpoint} at ${data.timestamp}`); console.log(`Condition: Temp ${data.temperature}°C, Humidity ${data.humidity}%`); }); ``` ### AI-Powered Trade Insights ```typescript theme={null} // Machine learning trade optimization const insights = await client.global.ai.analyzeTradeOpportunities({ company_profile: 'did:stateset:company:abc123', product_categories: ['electronics', 'automotive_parts'], target_regions: ['EU', 'ASEAN'], analysis_depth: 'comprehensive' }); // Response includes ML-generated recommendations { "opportunities": [ { "market": "Germany", "product": "Electronics Components", "potential_revenue": "2400000.00", "confidence": 0.87, "entry_barriers": ["CE_certification", "WEEE_compliance"], "recommended_strategy": "Partner with local distributor" } ], "risk_factors": [ { "type": "regulatory_change", "probability": 0.23, "impact": "medium", "mitigation": "Monitor EU Digital Services Act implementation" } ] } ``` ## 📱 Mobile & Integration SDKs ### React Native Integration ```javascript theme={null} import { StateSetGlobal } from '@stateset/react-native'; const GlobalCommerceScreen = () => { const [orders, setOrders] = useState([]); const createInternationalOrder = async () => { try { const order = await StateSetGlobal.createOrder({ buyer_country: 'US', seller_country: 'DE', items: [...items], auto_compliance: true }); setOrders([...orders, order]); } catch (error) { console.error('Order creation failed:', error); } }; return ( ); }; ``` ### Enterprise ERP Integration ```java theme={null} // SAP Integration public class StateSetGlobalSAPConnector { private StateSetGlobalClient client; public void syncInternationalOrders() { // Fetch orders from SAP List sapOrders = sapService.getNewOrders(); for (SAPOrder sapOrder : sapOrders) { // Convert to StateSet format GlobalOrder stateSetOrder = convertSAPToStateSet(sapOrder); // Create with compliance stateSetOrder.setComplianceEnabled(true); stateSetOrder.setAutoDocuments(true); // Submit to StateSet client.global().createOrder(stateSetOrder); // Update SAP with StateSet order ID sapService.updateOrderReference( sapOrder.getId(), stateSetOrder.getId() ); } } } ``` ## 🎯 Success Metrics ### Global Reach Impact | Metric | Before StateSet | With StateSet | Improvement | | -------------------- | --------------- | ------------- | --------------- | | Countries Accessible | 12 | 195+ | 1,525% | | Compliance Time | 2-6 weeks | 2 minutes | 99.9% faster | | Documentation Cost | \$500-2000 | \$5-20 | 99% cheaper | | Settlement Time | 5-30 days | 1 hour | 99.8% faster | | Error Rate | 15-25% | 0.1% | 99.6% reduction | ### Customer Success Stories **Mid-Market Manufacturer (Germany → USA)** * Monthly volume: \$2.3M * Compliance time reduced from 3 weeks to 2 minutes * Documentation costs cut by 95% * Cash flow improved by \$450K/month **E-commerce Platform (Multi-Country)** * Enabled sales to 47 new countries * Reduced cart abandonment by 23% * Automated tax calculation for 100% of orders * Increased cross-border revenue by 340% ## 🔗 Related APIs * [Orders API](/stateset-commerce-api-reference/orders) - Core order management * [Finance API](/stateset-commerce-api-reference/finance) - Trade finance solutions * [USDC Integration](/stateset-commerce-api-reference/usdc) - Native USDC payments * [Invoices API](/stateset-commerce-api-reference/invoices) - Invoice management * [Purchase Orders API](/stateset-commerce-api-reference/purchaseorders) - PO financing *** *Ready to go global? [Start your international expansion →](https://app.stateset.network/global)* # Governance Module Source: https://docs.stateset.com/stateset-commerce-api-reference/governance Comprehensive overview of the StateSet Commerce Network Governance Module and Tokenomics # StateSet Commerce Network: Governance Model and Tokenomics ## Table of Contents 1. [Introduction](#introduction) 2. [Governance Model](#governance-model) 3. [STATE Token Overview](#state-token-overview) 4. [Tokenomics](#tokenomics) 5. [Staking and Validation](#staking-and-validation) 6. [Community Treasury](#community-treasury) 7. [Upgrade Mechanisms](#upgrade-mechanisms) 8. [Interchain Governance](#interchain-governance) 9. [Future Developments](#future-developments) 10. [Conclusion](#conclusion) ## Introduction The StateSet Commerce Network is built on a robust governance model and tokenomics framework designed to ensure the network's long-term sustainability, foster active community participation, and drive continuous innovation. This document provides a detailed overview of how governance operates within the network and how the STATE token powers the ecosystem. ## Governance Model StateSet operates under a decentralized governance model that empowers its community, allowing stakeholders to shape the network's future. Key components of this model include: * **Proposal System**: Any STATE token holder can submit proposals for network changes, upgrades, or parameter adjustments, ensuring inclusivity in the decision-making process. * **Voting Mechanism**: Voting power is proportional to the number of staked STATE tokens, allowing stakeholders to influence decisions based on their investment in the network. * **Quorum and Threshold**: Proposals must achieve a minimum participation quorum and reach a defined approval threshold to pass, ensuring that changes are both broadly supported and significant. * **Delegation**: Token holders can delegate their voting power to trusted validators or other participants, enabling representation without direct involvement. * **Governance Parameters**: Critical network parameters, such as inflation rate and transaction fees, can be modified through governance, providing flexibility to adapt to changing needs. ## STATE Token Overview The STATE token is the cornerstone of the StateSet Commerce Network, serving multiple critical functions within the ecosystem: * **Utility**: STATE tokens are used for transaction fees, staking, governance participation, and as a medium of exchange within the network. * **Supply Cap**: The total supply of STATE tokens is capped at 28,000,000, creating scarcity and potential value appreciation. * **Distribution**: The network allocates 15% of newly minted tokens to inflation and 80% to transaction fees, ensuring continuous rewards for active participants. * **Burning Mechanism**: To control inflation, 10% of newly minted tokens are burned, gradually reducing the circulating supply and enhancing token value. ## Tokenomics StateSet’s tokenomics are meticulously designed to foster a balanced, sustainable, and growth-oriented ecosystem: * **Inflation Model**: The network operates with a controlled inflation rate of 15% annually, balancing reward incentives with long-term token value. * **Fee Structure**: Transaction fees are set at a flat rate of 0.001 STATE per transaction, ensuring affordability while sustaining network operations. * **Incentive Alignment**: 80% of transaction fees and 15% of inflation rewards are distributed to active participants, aligning incentives across the network. * **Token Velocity**: The ecosystem includes mechanisms to encourage holding and using STATE tokens, promoting a healthy circulation within the network. ## Staking and Validation The security and governance of the StateSet network rely on its proof-of-stake consensus mechanism: * **Validator Selection**: Validators are chosen based on their stake and performance, playing a crucial role in maintaining network integrity. * **Staking Rewards**: Validators and delegators earn rewards from 80% of transaction fees and 15% of inflation, incentivizing active participation. * **Slashing Conditions**: To ensure reliability, validators face a 50% slashing penalty if they misbehave or remain offline for more than 12 hours. * **Delegation**: Stakeholders can delegate 100% of their tokens to validators, sharing in the rewards without running their own nodes. ## Community Treasury The Community Treasury is a vital component of StateSet, funded by network fees and newly minted tokens: * **Funding Sources**: The treasury receives 10% of newly minted tokens, ensuring continuous funding for community-driven initiatives. * **Usage**: Treasury funds are used for development grants, marketing, and liquidity provision, fostering network growth and adoption. * **Proposal Process**: Community members can submit proposals for treasury fund allocation via GitHub, with decisions made through collective voting. ## Upgrade Mechanisms StateSet employs a well-structured system for implementing network upgrades, ensuring stability and security: * **Software Upgrades**: Core protocol changes are proposed, tested, and implemented through a rigorous governance process, ensuring network integrity. * **Parameter Changes**: Governance allows for the adjustment of network parameters, enabling the network to adapt to evolving requirements. * **Emergency Procedures**: The network has safeguards in place to address critical issues or vulnerabilities promptly, protecting the network from unforeseen threats. ## Interchain Governance StateSet is an active participant in the broader Cosmos ecosystem, engaging in interchain governance: * **IBC Governance**: StateSet interacts with other chains within the Cosmos ecosystem, contributing to cross-chain governance decisions. * **Cross-Chain Proposals**: Mechanisms are in place for proposing and voting on initiatives that affect multiple chains, promoting ecosystem-wide collaboration. * **Interchain Security**: StateSet participates in shared security models across the Cosmos network, enhancing the security of its own network and contributing to the broader ecosystem. ## Future Developments StateSet is committed to continuous innovation in governance and tokenomics, with several exciting developments on the horizon: * **DAO Integration**: Plans to further decentralize network control through the integration of Decentralized Autonomous Organizations (DAOs), empowering community-led governance. * **Quadratic Voting**: Exploration of quadratic voting mechanisms to enhance fairness and reduce the influence of large stakeholders in governance decisions. * **Token Economics 2.0**: Ongoing research into advanced token models aimed at increasing stability, utility, and value retention within the network. * **AI Governance**: Potential integration of artificial intelligence for analyzing proposals and optimizing governance parameters, leveraging cutting-edge technology for better decision-making. ## Conclusion The governance model and tokenomics of the StateSet Commerce Network are designed to create a dynamic, resilient, and community-driven ecosystem. By aligning incentives, empowering stakeholders, and establishing transparent processes for decision-making, StateSet is well-positioned to adapt, thrive, and continue delivering value to its users in an ever-evolving global commerce landscape. We encourage all stakeholders to engage actively in the governance processes, helping to shape the future of the StateSet Commerce Network. # Interoperability and IBC Source: https://docs.stateset.com/stateset-commerce-api-reference/ibc Overview of the StateSet Commerce Network Interoperability and IBC # StateSet Commerce Network: Interoperability and IBC Overview ## Table of Contents 1. [Introduction](#introduction) 2. [Inter-Blockchain Communication (IBC) Protocol](#inter-blockchain-communication-ibc-protocol) 3. [Cross-Chain Asset Transfers](#cross-chain-asset-transfers) 4. [Interchain Accounts](#interchain-accounts) 5. [Interchain Security](#interchain-security) 6. [Peg Zones and Bridges](#peg-zones-and-bridges) 7. [Cross-Chain Smart Contract Calls](#cross-chain-smart-contract-calls) 8. [Interoperability with Non-Cosmos Chains](#interoperability-with-non-cosmos-chains) 9. [Use Cases in Commerce](#use-cases-in-commerce) 10. [Future Developments in Interoperability](#future-developments-in-interoperability) ## Introduction Interoperability is a cornerstone of the StateSet Commerce Network, enabling seamless interaction with other blockchain networks and expanding the possibilities for global commerce. This overview explores how Stateset leverages the Inter-Blockchain Communication (IBC) protocol and other interoperability solutions to create a connected ecosystem. ## Inter-Blockchain Communication (IBC) Protocol * **Core Concept**: IBC allows independent blockchains to exchange data and assets securely. * **Key Components**: * Light Clients: Verify state transitions of other chains * Relayers: Facilitate communication between chains * Handlers: Process IBC packets on each chain * **Security Model**: Trustless verification without relying on centralized intermediaries ## Cross-Chain Asset Transfers * **Token Transfers**: Move STATE tokens and other assets between IBC-enabled chains * **Fungible Token Standard**: ICS-20 for seamless transfer of fungible tokens * **Non-Fungible Token Standard**: ICS-721 for NFT transfers across chains * **Atomic Swaps**: Execute cross-chain trades without counterparty risk ## Interchain Accounts * **Concept**: Control accounts on remote chains through IBC * **Use Cases**: * Cross-chain DeFi interactions * Multi-chain governance participation * Unified identity across multiple networks * **Security Considerations**: Permissioning and access control mechanisms ## Interchain Security * **Shared Security Model**: Leverage the security of the Cosmos Hub * **Validator Set Replication**: Use the same validator set across multiple chains * **Benefits**: Enhanced security for new or smaller chains in the ecosystem ## Peg Zones and Bridges * **Peg Zones**: Specialized bridges to non-Cosmos chains * Examples: Gravity Bridge (Ethereum), Nomic (Bitcoin) * **Asset Pegging**: Create IBC-compatible representations of external assets * **Two-Way Transfers**: Enable bidirectional movement of assets ## Cross-Chain Smart Contract Calls * **Inter-Chain Contract Calls**: Execute functions on contracts deployed on different chains * **CosmWasm Integration**: Leverage CosmWasm's multi-chain capabilities * **Cross-Chain Oracles**: Access data and trigger events across multiple networks ## Interoperability with Non-Cosmos Chains * **Ethereum Compatibility**: Interact with Ethereum and EVM-compatible chains * **Bitcoin Interoperability**: Schemes for Bitcoin asset representation and transfer * **Polkadot Integration**: Explore interoperability with Polkadot parachains ## Use Cases in Commerce * **Global Supply Chain Management**: Track products across multiple blockchain networks * **Cross-Border Payments**: Seamless international transactions using multiple currencies * **Decentralized Marketplaces**: Access products and services from various blockchain ecosystems * **Multi-Chain Loyalty Programs**: Unified reward systems across different platforms * **Interoperable Identity Solutions**: Portable KYC/AML credentials across networks ## Future Developments in Interoperability * **Universal Interoperability Standards**: Collaboration on cross-ecosystem standards * **AI-Driven Interoperability**: Intelligent routing and optimization of cross-chain interactions * **Quantum-Resistant IBC**: Preparing for post-quantum cryptographic needs * **Layer-2 Interoperability**: Extending IBC to layer-2 scaling solutions * **Internet of Blockchains**: Vision for a seamlessly connected multi-chain universe ## Conclusion The StateSet Commerce Network's robust interoperability features, powered by IBC and complementary technologies, position it as a key player in the emerging interconnected blockchain ecosystem. By enabling seamless cross-chain interactions, Stateset opens up new possibilities for global commerce, financial innovation, and collaborative business models. As we continue to advance our interoperability capabilities, we invite developers, businesses, and blockchain networks to join us in creating a more connected, efficient, and inclusive global commerce landscape. # Create Invoice Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/create POST https://api.stateset.network/v1/invoice This endpoint creates a new invoice ### Body This is the ID of the deployment to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/invoice' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Factor Invoice Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/factor Factor an invoice. # Factor Invoice Use this endpoint to factor an invoice. # Get Invoice Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/get Retrieve an invoice by ID. # Get Invoice Use this endpoint to retrieve an invoice by ID. # List Invoices Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/list List invoices. # List Invoices Use this endpoint to list invoices. # Pay Invoice Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/pay POST https://api.stateset.network/v1/invoice/pay Pay an invoice using ssUSD stablecoin on the StateSet Commerce Network ### Overview This endpoint processes ssUSD (StateSet USD) stablecoin payments for invoices. Supports instant settlement, partial payments, and automated reconciliation. ### Body The unique identifier of the invoice to be paid Payment method details Payment type. Supported values: "ssusd", "usdc" (legacy) The payer's wallet address Payment amount Amount to pay (can be partial payment) Denomination: "ssusd" or "usdc" (legacy) Blockchain for payment: "stateset" (default), "base", "solana", "cosmos" Additional payment details Whether this is intended as full payment (true) or partial (false) Apply early payment discount if eligible Payment reference number Additional metadata Payment memo Unique key to prevent duplicate payments Accounting code for reconciliation ### Response Whether the payment was successful Blockchain transaction details Transaction hash Block height Transaction timestamp Gas consumed Payment details Unique payment identifier Invoice that was paid Amount paid in this transaction Any discounts applied Payment status Updated invoice details Invoice identifier Invoice status: "paid", "partially\_paid", "unpaid" Total invoice amount Total amount paid to date Remaining balance List of all payments made ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/invoice/pay' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --data-raw '{ "invoice_id": "inv_1234567890", "payment_method": { "type": "ssusd", "wallet_address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "value": "5000.00", "denom": "ssusd" }, "chain": "stateset" }, "payment_details": { "full_payment": true, "early_payment_discount": true, "reference": "PMT-2024-001" }, "metadata": { "memo": "Invoice payment for January services", "idempotency_key": "pay_inv_1234567890_001", "accounting_code": "REV-001" } }' ``` ```javascript Node.js theme={null} const axios = require('axios'); async function payInvoiceWithSSUSD(invoiceId, amount, walletAddress, isFullPayment = true) { try { const response = await axios.post( 'https://api.stateset.network/v1/invoice/pay', { invoice_id: invoiceId, payment_method: { type: 'ssusd', wallet_address: walletAddress, amount: { value: amount, denom: 'ssusd' }, chain: 'stateset' }, payment_details: { full_payment: isFullPayment, early_payment_discount: true, reference: `PMT-${Date.now()}` }, metadata: { memo: `Payment for invoice ${invoiceId}`, idempotency_key: `pay_inv_${invoiceId}_${Date.now()}` } }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); console.log('Invoice payment successful:', response.data); // Check if invoice is fully paid if (response.data.invoice.status === 'paid') { console.log('Invoice fully paid!'); } else if (response.data.invoice.status === 'partially_paid') { console.log(`Partial payment applied. Balance due: ${response.data.invoice.balance_due.value} ${response.data.invoice.balance_due.denom}`); } return response.data; } catch (error) { console.error('Invoice payment failed:', error.response?.data || error.message); throw error; } } // Example: Partial payment async function makePartialPayment(invoiceId, partialAmount, walletAddress) { return payInvoiceWithSSUSD(invoiceId, partialAmount, walletAddress, false); } ``` ```python Python theme={null} import requests from datetime import datetime def pay_invoice_with_ssusd(invoice_id, amount, wallet_address, full_payment=True): """Pay an invoice using ssUSD stablecoin""" url = "https://api.stateset.network/v1/invoice/pay" headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } payload = { "invoice_id": invoice_id, "payment_method": { "type": "ssusd", "wallet_address": wallet_address, "amount": { "value": str(amount), "denom": "ssusd" }, "chain": "stateset" }, "payment_details": { "full_payment": full_payment, "early_payment_discount": True, "reference": f"PMT-{datetime.now().strftime('%Y%m%d%H%M%S')}" }, "metadata": { "memo": f"Payment for invoice {invoice_id}", "idempotency_key": f"pay_inv_{invoice_id}_{int(datetime.now().timestamp())}" } } try: response = requests.post(url, json=payload, headers=headers) response.raise_for_status() result = response.json() print(f"Payment successful! Transaction: {result['transaction']['tx_hash']}") # Check payment status invoice_status = result['invoice']['status'] if invoice_status == 'paid': print("Invoice fully paid!") elif invoice_status == 'partially_paid': balance = result['invoice']['balance_due'] print(f"Partial payment applied. Balance due: {balance['value']} {balance['denom']}") return result except requests.exceptions.RequestException as e: print(f"Invoice payment failed: {e}") if hasattr(e, 'response') and e.response: print(f"Error details: {e.response.json()}") raise # Example: Apply early payment discount def pay_invoice_with_discount(invoice_id, wallet_address): """Pay invoice in full to get early payment discount""" # First, get invoice details to see discount terms # Then pay the discounted amount return pay_invoice_with_ssusd( invoice_id=invoice_id, amount="4750.00", # Example: 5% discount on $5000 wallet_address=wallet_address, full_payment=True ) ``` ```json Full Payment Response theme={null} { "success": true, "transaction": { "tx_hash": "E8F1B4C7D0A3E6F9C2B5E8F1D4C7A0B3E6F9C2B5", "block_height": 1234568, "timestamp": "2024-01-15T11:00:00Z", "gas_used": "80000" }, "payment": { "payment_id": "pmt_abc123def456", "invoice_id": "inv_1234567890", "amount_paid": { "value": "4750.00", "denom": "ssusd", "usd_value": "4750.00" }, "discount_applied": { "type": "early_payment", "amount": "250.00", "percentage": "5.0" }, "status": "completed" }, "invoice": { "invoice_id": "inv_1234567890", "status": "paid", "total_amount": { "value": "5000.00", "denom": "ssusd" }, "amount_paid": { "value": "4750.00", "denom": "ssusd" }, "balance_due": { "value": "0.00", "denom": "ssusd" }, "payments": [ { "payment_id": "pmt_abc123def456", "amount": "4750.00", "paid_at": "2024-01-15T11:00:00Z", "discount": "250.00" } ] } } ``` ```json Partial Payment Response theme={null} { "success": true, "transaction": { "tx_hash": "F9G2C5D8E1B4F7A0D3F6G9C2E5B8F1D4", "block_height": 1234569, "timestamp": "2024-01-15T11:05:00Z", "gas_used": "75000" }, "payment": { "payment_id": "pmt_xyz789uvw012", "invoice_id": "inv_1234567890", "amount_paid": { "value": "2000.00", "denom": "ssusd", "usd_value": "2000.00" }, "discount_applied": null, "status": "completed" }, "invoice": { "invoice_id": "inv_1234567890", "status": "partially_paid", "total_amount": { "value": "5000.00", "denom": "ssusd" }, "amount_paid": { "value": "2000.00", "denom": "ssusd" }, "balance_due": { "value": "3000.00", "denom": "ssusd" }, "payments": [ { "payment_id": "pmt_xyz789uvw012", "amount": "2000.00", "paid_at": "2024-01-15T11:05:00Z", "discount": "0.00" } ] } } ``` # Update Invoice Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/update Update an invoice. # Update Invoice Use this endpoint to update an invoice. # Void Invoice Source: https://docs.stateset.com/stateset-commerce-api-reference/invoices/void POST https://api.stateset.network/v1/invoice/void This endpoint voids an invoice ### Body This is the ID of the invoice to be voided. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/invoice/void' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Approve Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/approve POST https://api.stateset.network/v1/loan/approve This endpoint approves a new loan ### Body This is the ID of the loan to be approved. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/loan' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Cancel Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/cancel POST https://api.stateset.network/v1/loan/cancel This endpoint cancels a new loan ### Body This is the ID of the loan to be cancelled. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/loan/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Create Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/create POST https://api.stateset.network/v1/loan This endpoint creates a new loan ### Body This is the ID of the deployment to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/loan' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Get Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/get Retrieve a loan by ID. # Get Loan Use this endpoint to retrieve a loan by ID. # Liquidate Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/liquidate POST https://api.stateset.network/v1/loan/liquidate This endpoint liquidates a loan ### Body This is the ID of the loan to be liquidated. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/loan/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # List Loans Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/list List loans. # List Loans Use this endpoint to list loans. # RePay Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/repay POST https://api.stateset.network/v1/loan/repay This endpoint repay a new loan ### Body This is the ID of the loan to be cancelled. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/loan/repay' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Request Loan Source: https://docs.stateset.com/stateset-commerce-api-reference/loans/request Request a new loan. # Request Loan Use this endpoint to request a new loan. # Orders API Source: https://docs.stateset.com/stateset-commerce-api-reference/orders Complete order lifecycle management with native USDC payments and real-time tracking # Orders API: The Foundation of Digital Commerce The Orders API is the core of StateSet Commerce Network, providing comprehensive order lifecycle management from creation to fulfillment. With native USDC integration, real-time tracking, and enterprise-grade automation, it's designed to handle millions of orders with sub-second latency. ## 🚀 Quick Start ```typescript theme={null} import { StateSetClient } from '@stateset/commerce-sdk'; const client = new StateSetClient({ endpoint: 'https://api.stateset.network', apiKey: process.env.STATESET_API_KEY }); // Create and pay for order in one transaction const order = await client.orders.createAndPay({ items: [{ sku: 'LAPTOP-001', quantity: 1, price: '999.99' }], customer: { id: 'cust_123', email: 'customer@example.com' }, payment: { method: 'usdc', amount: '999.99' }, shipping: { address: '123 Main St, San Francisco, CA 94105', method: 'standard' } }); console.log(`Order ${order.id} created and paid!`); ``` ## 🎯 Key Features ### Native USDC Payments * Pay fees in USDC (no gas token required) * Instant settlement with Circle integration * Built-in refund and partial payment support * Cross-chain transfers via IBC ### Enterprise Automation * Smart contract workflows * Automated fraud detection * Inventory management integration * Real-time webhook notifications ### Global Scale * 10,000+ orders per second * Sub-second transaction finality * 99.99% uptime SLA * Multi-region data replication ## 📊 Order Lifecycle ```mermaid theme={null} graph TD A[Create Order] --> B[Payment Processing] B --> C{Payment Success?} C -->|Yes| D[Order Confirmed] C -->|No| E[Payment Failed] D --> F[Inventory Allocation] F --> G[Fulfillment Queue] G --> H[Shipping] H --> I[Delivered] I --> J[Order Complete] E --> K[Cancel Order] D --> L[Hold Order] L --> M[Release Order] M --> G I --> N[Return Request] N --> O[Refund Process] ``` ### Order States | State | Description | Next States | | ----------- | ------------------------------- | ------------------------------- | | `CREATED` | Order created, awaiting payment | `PAID`, `CANCELLED` | | `PAID` | Payment confirmed | `FULFILLED`, `HELD`, `REFUNDED` | | `FULFILLED` | Items prepared for shipping | `SHIPPED`, `CANCELLED` | | `SHIPPED` | Order in transit | `DELIVERED`, `RETURNED` | | `DELIVERED` | Order completed successfully | `RETURNED` | | `HELD` | Order temporarily paused | `RELEASED`, `CANCELLED` | | `CANCELLED` | Order cancelled | Terminal state | | `RETURNED` | Order returned by customer | `REFUNDED` | | `REFUNDED` | Refund processed | Terminal state | | `DISPUTED` | Order under dispute | `RESOLVED` | ## 💻 API Reference ### Create Order ```http theme={null} POST /v1/orders ``` **Request Body:** ```json theme={null} { "customer_id": "cust_123", "items": [ { "sku": "LAPTOP-001", "quantity": 1, "unit_price": "999.99", "description": "MacBook Pro 16-inch" } ], "shipping_address": { "name": "John Doe", "address_line_1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "metadata": { "channel": "web", "campaign_id": "summer_sale_2024" } } ``` **Response:** ```json theme={null} { "id": "ord_7x9kPm2nQ1", "customer_id": "cust_123", "status": "CREATED", "items": [ { "sku": "LAPTOP-001", "quantity": 1, "unit_price": "999.99", "total_price": "999.99" } ], "subtotal": "999.99", "tax": "87.49", "shipping": "9.99", "total": "1096.47", "currency": "USDC", "created_at": "2024-06-25T12:00:00Z", "payment_url": "https://pay.stateset.network/ord_7x9kPm2nQ1" } ``` ### Pay Order ```http theme={null} POST /v1/orders/{order_id}/pay ``` **Request Body:** ```json theme={null} { "payment_method": { "type": "usdc", "wallet_address": "stateset1abc123...", "amount": "1096.47" }, "billing_address": { "name": "John Doe", "address_line_1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } } ``` **Response:** ```json theme={null} { "payment_id": "pay_8y4mQr5oP2", "order_id": "ord_7x9kPm2nQ1", "status": "PAID", "amount": "1096.47", "currency": "USDC", "transaction_hash": "0x742d35Cc6634C0532925a3b8D097C00D4dfece08", "paid_at": "2024-06-25T12:05:00Z", "fees": { "network_fee": "0.01", "processing_fee": "0.00" } } ``` ### Get Order ```http theme={null} GET /v1/orders/{order_id} ``` **Response:** ```json theme={null} { "id": "ord_7x9kPm2nQ1", "customer_id": "cust_123", "status": "SHIPPED", "items": [ { "sku": "LAPTOP-001", "quantity": 1, "unit_price": "999.99", "total_price": "999.99", "status": "SHIPPED" } ], "payment": { "id": "pay_8y4mQr5oP2", "status": "PAID", "amount": "1096.47", "method": "USDC", "paid_at": "2024-06-25T12:05:00Z" }, "shipping": { "carrier": "FedEx", "tracking_number": "1234567890", "estimated_delivery": "2024-06-27T17:00:00Z", "shipped_at": "2024-06-26T09:00:00Z" }, "timeline": [ { "status": "CREATED", "timestamp": "2024-06-25T12:00:00Z" }, { "status": "PAID", "timestamp": "2024-06-25T12:05:00Z" }, { "status": "FULFILLED", "timestamp": "2024-06-26T08:00:00Z" }, { "status": "SHIPPED", "timestamp": "2024-06-26T09:00:00Z" } ] } ``` ### List Orders ```http theme={null} GET /v1/orders?customer_id=cust_123&status=PAID&limit=50&offset=0 ``` **Query Parameters:** | Parameter | Type | Description | | ---------------- | ------- | ------------------------------------------ | | `customer_id` | string | Filter by customer ID | | `status` | string | Filter by order status | | `created_after` | string | Orders created after this date (ISO 8601) | | `created_before` | string | Orders created before this date (ISO 8601) | | `amount_min` | string | Minimum order amount | | `amount_max` | string | Maximum order amount | | `limit` | integer | Number of orders to return (max 100) | | `offset` | integer | Number of orders to skip | **Response:** ```json theme={null} { "orders": [ { "id": "ord_7x9kPm2nQ1", "customer_id": "cust_123", "status": "PAID", "total": "1096.47", "currency": "USDC", "created_at": "2024-06-25T12:00:00Z" } ], "total_count": 1, "has_more": false } ``` ## 🔄 Advanced Features ### Bulk Order Operations ```typescript theme={null} // Create multiple orders atomically const bulkOrders = await client.orders.createBulk([ { customer_id: 'cust_123', items: [{ sku: 'WIDGET-001', quantity: 10 }] }, { customer_id: 'cust_456', items: [{ sku: 'GADGET-002', quantity: 5 }] } ]); // Process bulk payments const payments = await client.orders.payBulk([ { order_id: 'ord_1', amount: '100.00' }, { order_id: 'ord_2', amount: '50.00' } ]); ``` ### Subscription Orders ```typescript theme={null} // Create recurring subscription orders const subscription = await client.orders.createSubscription({ customer_id: 'cust_123', items: [{ sku: 'COFFEE-MONTHLY', quantity: 1 }], schedule: { interval: 'monthly', start_date: '2024-07-01', end_date: '2025-07-01' }, payment_method: { type: 'usdc', wallet_address: 'stateset1abc123...' } }); // Manage subscription await client.orders.pauseSubscription(subscription.id); await client.orders.resumeSubscription(subscription.id); ``` ### Smart Contract Integration ```typescript theme={null} // Create order with smart contract conditions const conditionalOrder = await client.orders.createConditional({ customer_id: 'cust_123', items: [{ sku: 'PRESALE-ITEM', quantity: 1 }], conditions: { contract_address: 'stateset1contract...', method: 'checkInventory', params: ['PRESALE-ITEM'], expected_result: true }, auto_execute: true }); ``` ### Multi-Party Orders ```typescript theme={null} // Create order with multiple parties (dropshipping) const multiPartyOrder = await client.orders.createMultiParty({ customer_id: 'cust_123', merchant_id: 'merch_456', supplier_id: 'supp_789', items: [{ sku: 'DROP-SHIP-001', quantity: 1 }], revenue_split: { merchant: 70, supplier: 25, platform: 5 }, fulfillment_by: 'supplier' }); ``` ## 📡 Webhooks & Events ### Event Types | Event | Description | Payload | | ----------------- | ----------------- | --------------------- | | `order.created` | New order created | `{ order, customer }` | | `order.paid` | Payment completed | `{ order, payment }` | | `order.fulfilled` | Order fulfilled | `{ order, items }` | | `order.shipped` | Order shipped | `{ order, tracking }` | | `order.delivered` | Order delivered | `{ order, delivery }` | | `order.cancelled` | Order cancelled | `{ order, reason }` | | `order.refunded` | Refund processed | `{ order, refund }` | | `order.disputed` | Dispute opened | `{ order, dispute }` | ### Webhook Configuration ```typescript theme={null} // Configure webhook endpoints const webhook = await client.webhooks.create({ url: 'https://your-api.com/webhooks/stateset', events: ['order.paid', 'order.shipped'], secret: 'your-webhook-secret', headers: { 'Authorization': 'Bearer your-api-token' } }); // Webhook payload example { "event": "order.paid", "data": { "order": { "id": "ord_7x9kPm2nQ1", "status": "PAID", "total": "1096.47" }, "payment": { "id": "pay_8y4mQr5oP2", "amount": "1096.47", "method": "USDC" } }, "timestamp": "2024-06-25T12:05:00Z" } ``` ## 🔍 Analytics & Reporting ### Order Analytics ```typescript theme={null} // Get order analytics const analytics = await client.analytics.orders({ start_date: '2024-06-01', end_date: '2024-06-30', group_by: 'day', metrics: ['count', 'revenue', 'avg_order_value'] }); // Response { "data": [ { "date": "2024-06-25", "order_count": 1247, "revenue": "125847.32", "avg_order_value": "100.92" } ], "summary": { "total_orders": 38562, "total_revenue": "3856892.45", "avg_order_value": "100.04" } } ``` ### Custom Reports ```typescript theme={null} // Generate custom reports const report = await client.reports.generate({ type: 'order_performance', filters: { status: ['DELIVERED'], created_after: '2024-01-01' }, dimensions: ['customer_segment', 'product_category'], metrics: ['count', 'revenue', 'fulfillment_time'], format: 'csv' }); // Download report const downloadUrl = await client.reports.download(report.id); ``` ## 🛡️ Security & Compliance ### Fraud Detection ```typescript theme={null} // Built-in fraud detection const order = await client.orders.create({ // ... order details fraud_check: { enabled: true, rules: ['velocity', 'geolocation', 'device_fingerprint'], threshold: 'medium' } }); // Fraud check result if (order.fraud_score > 0.7) { await client.orders.hold(order.id, 'fraud_review'); } ``` ### PCI DSS Compliance ```typescript theme={null} // Tokenized payment data const payment = await client.orders.createPayment({ order_id: 'ord_123', payment_method: { type: 'card', token: 'tok_secure_token', // PCI-compliant tokenization last4: '4242', brand: 'visa' } }); // Sensitive data is never stored // All card data is tokenized via PCI DSS compliant processor ``` ### GDPR Compliance ```typescript theme={null} // Data subject rights const dataExport = await client.compliance.exportCustomerData('cust_123'); const dataDeleted = await client.compliance.deleteCustomerData('cust_123'); // Privacy-preserving analytics const analytics = await client.analytics.orders({ anonymized: true, retention_policy: '7_years' }); ``` ## 🌍 Global Commerce Features ### Multi-Currency Support ```typescript theme={null} // Orders in different currencies const euroOrder = await client.orders.create({ items: [{ sku: 'EU-PRODUCT', quantity: 1 }], currency: 'EUR', exchange_rate: { from: 'EUR', to: 'USDC', rate: '1.09', source: 'coinbase' } }); // Automatic currency conversion on payment const payment = await client.orders.pay(euroOrder.id, { amount: '100.00', currency: 'USDC', // Auto-converted from EUR exchange_rate_locked: true }); ``` ### Cross-Border Tax Calculation ```typescript theme={null} // Automatic tax calculation for international orders const order = await client.orders.create({ items: [{ sku: 'INT-PRODUCT', quantity: 1, price: '100.00' }], shipping_address: { country: 'DE', // Germany postal_code: '10115' }, tax_calculation: { enabled: true, provider: 'avalara', include_duties: true } }); // Automatic tax and duty calculation // VAT: 19% (Germany) // Import duty: 5.2% // Total tax: €24.20 ``` ### Regulatory Compliance ```typescript theme={null} // Automatic compliance checks const order = await client.orders.create({ // ... order details compliance: { export_control: true, // Check export restrictions sanctions_screening: true, // OFAC sanctions list restricted_products: true, // Country-specific restrictions aml_check: true // Anti-money laundering } }); // Compliance result if (order.compliance_status === 'RESTRICTED') { throw new Error('Order violates export controls'); } ``` ## 🔧 SDK Examples ### Node.js / TypeScript ```typescript theme={null} import { StateSetClient } from '@stateset/commerce-sdk'; const client = new StateSetClient({ endpoint: 'https://api.stateset.network', apiKey: process.env.STATESET_API_KEY, network: 'mainnet' }); // Complete e-commerce flow async function processOrder() { // 1. Create order const order = await client.orders.create({ customer_id: 'cust_123', items: [{ sku: 'PRODUCT-001', quantity: 2, price: '29.99' }] }); // 2. Process payment const payment = await client.orders.pay(order.id, { payment_method: { type: 'usdc', amount: order.total } }); // 3. Fulfill order await client.orders.fulfill(order.id, { tracking_number: 'FEDEX123456', carrier: 'fedex', items: order.items }); // 4. Mark as shipped await client.orders.ship(order.id); return order; } ``` ### Python ```python theme={null} from stateset import StateSetClient client = StateSetClient( endpoint='https://api.stateset.network', api_key=os.environ['STATESET_API_KEY'] ) # Create and process order order = client.orders.create({ 'customer_id': 'cust_123', 'items': [{ 'sku': 'PYTHON-COURSE', 'quantity': 1, 'price': '199.99' }] }) # Pay with USDC payment = client.orders.pay(order['id'], { 'payment_method': { 'type': 'usdc', 'amount': order['total'] } }) print(f"Order {order['id']} paid successfully!") ``` ### Go ```go theme={null} package main import ( "github.com/stateset/stateset-go" ) func main() { client := stateset.NewClient(&stateset.Config{ Endpoint: "https://api.stateset.network", APIKey: os.Getenv("STATESET_API_KEY"), }) // Create order order, err := client.Orders.Create(&stateset.CreateOrderRequest{ CustomerID: "cust_123", Items: []stateset.Item{ { SKU: "GO-WORKSHOP", Quantity: 1, Price: "299.99", }, }, }) if err != nil { log.Fatal(err) } // Process payment payment, err := client.Orders.Pay(order.ID, &stateset.PayOrderRequest{ PaymentMethod: stateset.PaymentMethod{ Type: "usdc", Amount: order.Total, }, }) if err != nil { log.Fatal(err) } fmt.Printf("Order %s paid: %s\n", order.ID, payment.ID) } ``` ### Rust ```rust theme={null} use stateset_sdk::{StateSetClient, CreateOrderRequest, PayOrderRequest}; #[tokio::main] async fn main() -> Result<(), Box> { let client = StateSetClient::new( "https://api.stateset.network", &std::env::var("STATESET_API_KEY")? ); // Create order let order = client.orders().create(CreateOrderRequest { customer_id: "cust_123".to_string(), items: vec![Item { sku: "RUST-BOOTCAMP".to_string(), quantity: 1, price: "399.99".to_string(), }], ..Default::default() }).await?; // Process payment let payment = client.orders().pay(&order.id, PayOrderRequest { payment_method: PaymentMethod { r#type: "usdc".to_string(), amount: order.total.clone(), }, ..Default::default() }).await?; println!("Order {} paid: {}", order.id, payment.id); Ok(()) } ``` ## 🚀 Performance & Scale ### Benchmarks | Operation | Throughput | Latency (p95) | Cost | | ------------- | -------------- | ------------- | -------- | | Create Order | 10,000 ops/sec | 45ms | \$0.001 | | Pay Order | 8,000 ops/sec | 65ms | \$0.01 | | Update Status | 15,000 ops/sec | 25ms | \$0.0005 | | Query Order | 50,000 ops/sec | 5ms | Free | ### Scaling Patterns ```typescript theme={null} // Horizontal scaling with sharding const client = new StateSetClient({ endpoint: 'https://api.stateset.network', shard_key: 'customer_id', // Distribute by customer read_replicas: 3, // Read from nearest replica write_concern: 'majority' // Ensure consistency }); // Batch operations for high throughput const orders = await client.orders.createBatch(orderRequests, { batch_size: 100, parallel: true, timeout: 30000 }); ``` ### Caching Strategy ```typescript theme={null} // Multi-level caching const client = new StateSetClient({ cache: { // L1: In-memory cache memory: { ttl: 60, // 1 minute max_size: 1000 }, // L2: Redis cache redis: { url: 'redis://localhost:6379', ttl: 300, // 5 minutes key_prefix: 'stateset:' }, // L3: CDN cache cdn: { enabled: true, ttl: 3600, // 1 hour regions: ['us-east-1', 'eu-west-1', 'ap-southeast-1'] } } }); // Cache-aware queries const order = await client.orders.get('ord_123', { cache: 'prefer', // Try cache first max_age: 300 // Accept cached data up to 5 minutes old }); ``` ## 📈 Monitoring & Observability ### Metrics ```typescript theme={null} // Built-in metrics collection const client = new StateSetClient({ metrics: { enabled: true, endpoint: 'https://metrics.stateset.network', tags: { environment: 'production', service: 'order-service' } } }); // Custom metrics client.metrics.increment('orders.created', 1, { customer_segment: 'enterprise', product_category: 'software' }); client.metrics.histogram('order.processing_time', processingTime); client.metrics.gauge('orders.pending', pendingOrderCount); ``` ### Health Checks ```typescript theme={null} // Built-in health monitoring const healthCheck = await client.health.check(); // Response { "status": "healthy", "checks": { "database": { "status": "healthy", "response_time": "2ms" }, "blockchain": { "status": "healthy", "block_height": 1542389, "sync_status": "synced" }, "cache": { "status": "healthy", "hit_rate": 0.94 }, "external_apis": { "status": "degraded", "details": "Tax service responding slowly" } }, "timestamp": "2024-06-25T12:00:00Z" } ``` ## 🔗 Related APIs * [Orders Create](/stateset-commerce-api-reference/orders/create) - Create new orders * [Orders Pay](/stateset-commerce-api-reference/orders/pay) - Process payments * [Orders Ship](/stateset-commerce-api-reference/orders/ship) - Handle shipping * [Orders Refund](/stateset-commerce-api-reference/orders/refund) - Process refunds * [Finance API](/stateset-commerce-api-reference/finance) - Financial instruments * [USDC Guide](/stateset-commerce-api-reference/usdc) - Native USDC integration ## Cross-Chain Payment Integration StateSet Orders module natively integrates with the CCTP module to enable seamless cross-chain USDC payments. Customers can pay for orders on any supported chain, and the funds are automatically transferred to StateSet for settlement. ### Accepting Cross-Chain Payments ```go theme={null} // Process order payment from any supported chain func (k Keeper) ProcessCrossChainPayment( ctx sdk.Context, orderID string, sourceChain uint32, messageHash []byte, ) error { // Verify the CCTP message has been received cctpMsg, found := k.cctpKeeper.GetReceivedMessage(ctx, messageHash) if !found { return ErrCCTPMessageNotFound } // Extract payment details from message body payment := DecodeCCTPPayment(cctpMsg.MessageBody) if payment.OrderID != orderID { return ErrPaymentOrderMismatch } // Update order with payment order, found := k.GetOrder(ctx, orderID) if !found { return ErrOrderNotFound } order.PaymentInfo = PaymentInfo{ Type: "cross_chain_usdc", SourceChain: sourceChain, Amount: payment.Amount, TransactionID: hex.EncodeToString(messageHash), Timestamp: ctx.BlockTime(), } order.Status = StatusPaid return k.SetOrder(ctx, order) } ``` ### Automated Cross-Chain Settlement ```go theme={null} // Automatically process incoming CCTP payments for orders func (k Keeper) OnCCTPMessageReceived( ctx sdk.Context, message types.CCTPMessage, ) error { // Check if this is an order payment if !IsOrderPayment(message.MessageBody) { return nil // Not an order payment } payment := DecodeOrderPayment(message.MessageBody) // Process the payment return k.ProcessCrossChainPayment( ctx, payment.OrderID, message.SourceDomain, message.Hash(), ) } ``` ### Cross-Chain Refunds ```go theme={null} // Refund order payment to original chain func (k Keeper) RefundCrossChain( ctx sdk.Context, orderID string, ) error { order, found := k.GetOrder(ctx, orderID) if !found { return ErrOrderNotFound } if order.PaymentInfo.Type != "cross_chain_usdc" { return ErrNotCrossChainPayment } // Initiate CCTP refund to source chain msg := &cctp.MsgDepositForBurn{ From: k.GetModuleAddress(), Amount: order.PaymentInfo.Amount, DestinationDomain: order.PaymentInfo.SourceChain, MintRecipient: order.Customer.GetCCTPAddress(), BurnToken: "usdc", } _, err := k.cctpKeeper.DepositForBurn(ctx, msg) if err != nil { return err } // Update order status order.Status = StatusRefunded return k.SetOrder(ctx, order) } ``` ### Events Additional events for cross-chain payments: ```protobuf theme={null} // Emitted when a cross-chain payment is received message EventCrossChainPaymentReceived { string order_id = 1; uint32 source_chain = 2; string amount = 3; string message_hash = 4; } // Emitted when a cross-chain refund is initiated message EventCrossChainRefundInitiated { string order_id = 1; uint32 destination_chain = 2; string amount = 3; string message_hash = 4; } ``` For detailed CCTP integration, see the [CCTP Module documentation](/stateset-commerce-api-reference/cctp-module) and [Integration Guide](/guides/cctp-module-integration). *** *Ready to get started? [Create your first order →](https://app.stateset.network/orders/new)* # Cancel Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/cancel POST https://api.stateset.network/v1/orders/{order_id}/cancel Cancel an order before fulfillment with automatic refund processing Orders can only be cancelled if they haven't been shipped. Once shipped, use the return flow instead. ## Overview The cancel order endpoint allows you to cancel an existing order and automatically process refunds. This is useful for customer-requested cancellations, inventory issues, or fraud prevention. ### Cancellation Rules * Status: `pending`, `processing`, `paid` * No shipments created * Within cancellation window * Status: `shipped`, `delivered` * Partial fulfillment started * Past cancellation deadline ## Request ### Path Parameters The unique identifier of the order to cancel **Example**: `ord_1a2b3c4d5e6f` ### Body Parameters Reason for cancellation **Options**: * `customer_request` - Customer initiated cancellation * `out_of_stock` - Item(s) no longer available * `pricing_error` - Incorrect pricing * `fraud_suspected` - Potential fraudulent order * `duplicate_order` - Duplicate order placed * `other` - Other reason (use notes) Amount to refund. If not specified, full refund is processed **Example**: `99.99` Additional notes about the cancellation **Example**: `"Customer changed mind about purchase"` Whether to send cancellation email to customer Whether to return items to inventory ## Response The cancelled order object Order ID New status: `cancelled` ISO 8601 timestamp of cancellation Reason for cancellation Refund details if payment was processed Refund ID Amount refunded Currency of refund Refund status: `pending`, `succeeded`, `failed` When customer will receive refund List of inventory adjustments made ```bash cURL theme={null} curl -X POST https://api.stateset.network/v1/orders/ord_1a2b3c4d5e6f/cancel \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "reason": "customer_request", "notes": "Customer found a better price elsewhere", "notify_customer": true, "restock_items": true }' ``` ```javascript Node.js theme={null} const cancellation = await stateset.orders.cancel('ord_1a2b3c4d5e6f', { reason: 'customer_request', notes: 'Customer found a better price elsewhere', notify_customer: true, restock_items: true }); console.log('Order cancelled:', cancellation.order.id); console.log('Refund status:', cancellation.refund.status); ``` ```python Python theme={null} cancellation = stateset.orders.cancel( 'ord_1a2b3c4d5e6f', reason='customer_request', notes='Customer found a better price elsewhere', notify_customer=True, restock_items=True ) print(f"Order cancelled: {cancellation.order.id}") print(f"Refund amount: {cancellation.refund.amount}") ``` ```php PHP theme={null} $cancellation = $stateset->orders->cancel('ord_1a2b3c4d5e6f', [ 'reason' => 'customer_request', 'notes' => 'Customer found a better price elsewhere', 'notify_customer' => true, 'restock_items' => true ]); echo "Order status: " . $cancellation->order->status; ``` ```json Success Response theme={null} { "order": { "id": "ord_1a2b3c4d5e6f", "status": "cancelled", "amount": 149.99, "currency": "ssusd", "cancelled_at": "2024-01-15T10:30:00Z", "cancellation_reason": "customer_request", "cancellation_notes": "Customer found a better price elsewhere", "items": [ { "id": "item_abc123", "product_id": "prod_widget_001", "quantity": 2, "price": 74.99 } ] }, "refund": { "id": "ref_xyz789", "amount": 149.99, "currency": "ssusd", "status": "succeeded", "payment_method": "original_payment_method", "estimated_arrival": "2024-01-17T10:30:00Z", "transaction_hash": "0xabc..." }, "inventory_updates": [ { "product_id": "prod_widget_001", "quantity_returned": 2, "new_available": 152 } ], "notifications_sent": { "customer_email": true, "admin_alert": true, "webhook": true } } ``` ```json Error Response theme={null} { "error": { "type": "invalid_request_error", "code": "order_not_cancellable", "message": "Order cannot be cancelled because it has already been shipped", "order_status": "shipped", "shipped_at": "2024-01-14T15:00:00Z" } } ``` ## Webhooks This endpoint triggers the following webhook events: * `order.cancelled` - When order is successfully cancelled * `refund.created` - When refund is initiated * `inventory.updated` - When items are restocked ## Best Practices Set clear cancellation deadlines based on your fulfillment process: ```javascript theme={null} // Check if order can be cancelled const canCancel = (order) => { const hoursSinceOrder = (Date.now() - order.created_at) / (1000 * 60 * 60); return order.status !== 'shipped' && hoursSinceOrder < 24; }; ``` For orders with multiple payment methods or partial payments: ```javascript theme={null} // Calculate refund for partial payments const calculateRefund = (order, cancellationFees = 0) => { const paidAmount = order.payments .filter(p => p.status === 'succeeded') .reduce((sum, p) => sum + p.amount, 0); return Math.max(0, paidAmount - cancellationFees); }; ``` Always provide clear communication about cancellations: ```javascript theme={null} // Custom cancellation email await stateset.emails.send({ to: order.customer.email, template: 'order_cancelled', data: { order_number: order.number, refund_amount: refund.amount, refund_timeline: '3-5 business days', reason: cancellation.reason } }); ``` ## Related Endpoints Process partial refunds without cancelling Handle returns for delivered orders Modify order details before fulfillment Query orders by status or customer # Create Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/create POST https://api.stateset.network/v1/order This endpoint creates a new order. ### Body This is the ID of the order to be created. This is the name of the order. This is the number of the order. This is the source of the order. This is the ID of the customer who placed the order. This is the list of items in the order. The total amount of the order The numeric amount (e.g., "150.00") The denomination: "ssusd" (default), "usdc" (legacy), or "usd" This is the payment status of the order. Options: "unpaid", "pending", "paid", "partially\_paid", "failed" The preferred payment method for this order. Payment method type. Options: "ssusd" (default), "usdc" (legacy), "card", "bank\_transfer" Customer's wallet address for stablecoin payments Preferred blockchain: "stateset" (default), "base", "solana", "cosmos" This is the shipping status of the order. This is additional metadata related to the order. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. The created order object Unique order identifier Order total with denomination Configured payment method Order status ### Notes * Orders are created with `paymentStatus: "unpaid"` by default * To pay for an order after creation, use the [Pay Order endpoint](/stateset-commerce-api-reference/orders/pay) * All monetary amounts should be specified in USDC * StateSet Commerce Network uses native USDC - no bridging required ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data-raw '{ "name": "Premium Subscription Order", "number": "ORD-2024-001", "source": "web_checkout", "customerID": "cust_123456", "items": [ { "product_id": "prod_premium_annual", "quantity": 1, "price": "150.00", "name": "Premium Annual Subscription" } ], "totalAmount": { "value": "150.00", "denom": "ssusd" }, "paymentStatus": "unpaid", "paymentMethod": { "type": "ssusd", "wallet_address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "chain": "stateset" } }' ``` ```javascript Node.js theme={null} const axios = require('axios'); async function createOrderWithSSUSD(customerData) { try { const orderData = { name: `Order for ${customerData.name}`, number: `ORD-${Date.now()}`, source: 'api', customerID: customerData.id, items: customerData.items, totalAmount: { value: calculateTotal(customerData.items), denom: 'ssusd' }, paymentStatus: 'unpaid', paymentMethod: { type: 'ssusd', wallet_address: customerData.wallet_address, chain: customerData.preferred_chain || 'stateset' } }; const response = await axios.post( 'https://api.stateset.network/v1/order', orderData, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); console.log('Order created:', response.data.order); return response.data; } catch (error) { console.error('Failed to create order:', error.response?.data || error.message); throw error; } } function calculateTotal(items) { return items.reduce((total, item) => { return total + (parseFloat(item.price) * item.quantity); }, 0).toFixed(2); } ``` ```python Python theme={null} import requests from typing import List, Dict def create_order_with_ssusd(customer_data: Dict) -> Dict: """Create an order with ssUSD payment method""" url = "https://api.stateset.network/v1/order" headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } # Calculate total total = sum(float(item['price']) * item['quantity'] for item in customer_data['items']) order_data = { "name": f"Order for {customer_data['name']}", "number": f"ORD-{int(time.time())}", "source": "api", "customerID": customer_data['id'], "items": customer_data['items'], "totalAmount": { "value": f"{total:.2f}", "denom": "ssusd" }, "paymentStatus": "unpaid", "paymentMethod": { "type": "ssusd", "wallet_address": customer_data['wallet_address'], "chain": customer_data.get('preferred_chain', 'stateset') } } try: response = requests.post(url, json=order_data, headers=headers) response.raise_for_status() result = response.json() print(f"Order created: {result['order']['id']}") return result except requests.exceptions.RequestException as e: print(f"Failed to create order: {e}") if hasattr(e, 'response') and e.response: print(f"Error details: {e.response.json()}") raise # Example usage customer = { "id": "cust_123456", "name": "John Doe", "wallet_address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "preferred_chain": "stateset", "items": [ { "product_id": "prod_001", "name": "Premium Widget", "price": "99.99", "quantity": 2 } ] } order = create_order_with_ssusd(customer) ``` ```json theme={null} { "success": 1, "order": { "id": "order_1a2b3c4d5e6f", "name": "Premium Subscription Order", "number": "ORD-2024-001", "source": "web_checkout", "customerID": "cust_123456", "items": [ { "product_id": "prod_premium_annual", "quantity": 1, "price": "150.00", "name": "Premium Annual Subscription" } ], "totalAmount": { "value": "150.00", "denom": "ssusd" }, "paymentStatus": "unpaid", "paymentMethod": { "type": "ssusd", "wallet_address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "chain": "stateset" }, "status": "pending", "created_at": "2024-01-15T12:00:00Z" } } ``` # Deliver Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/deliver POST https://api.stateset.network/v1/order/deliver This endpoint marks an order as delivered. ### Body This is the ID of the order to be delivered. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/deliver' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Dispute Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/dispute POST https://api.stateset.network/v1/order/dispute This endpoint initiates a dispute for an order. ### Body This is the ID of the order to be disputed. This is the reason for the dispute. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/dispute' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "", "reason": "Item not as described" }' ``` # Fulfill Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/fulfill POST https://api.stateset.network/v1/order/fulfill This endpoint fulfills a new order ### Body This is the ID of the deployment to be fulfilled. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/fulfill' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Get Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/get GET https://api.stateset.com/v1/orders/:id This endpoint gets an order. ### Body This is the id of the order. ### Response This is the id of the order. This is the name of the order. This is the number of the order. This is the source of the order. This is the state of the order. This is the customerID of the order. This is the list of items in the order. This is the total amount of the order. This is the payment status of the order. This is the shipping status of the order. This is the creation timestamp of the order. This is the last updated timestamp of the order. This is additional metadata related to the order. ```bash cURL theme={null} curl --location --request GET 'https://api.stateset.network/v1/order' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "1" }' ``` # Orders Orders describes the general data about the orders in StateSet Commerce Network. ## The order object #### Attributes | Name | Type | Description | | -------------- | -------- | ---------------------------------------- | | id | Text | Unique identifier for the order | | name | Text | Name of the order | | number | Text | Number of the order | | state | Text | State of the order | | customerID | Text | Customer ID of the order | | items | Array | List of items in the order | | totalAmount | Text | Total amount of the order | | paymentStatus | Text | Payment status of the order | | shippingStatus | Text | Shipping status of the order | | createdAt | DateTime | Creation timestamp of the order | | updatedAt | DateTime | Last updated timestamp of the order | | metadata | Object | Additional metadata related to the order | # Hold Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/hold POST https://api.stateset.network/v1/order/hold This endpoint places an order on hold. ### Body This is the ID of the order to be placed on hold. This is the reason for placing the order on hold. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/hold' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "", "reason": "Payment issue" }' ``` # List Orders Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/list List orders. # List Orders Use this endpoint to list orders. # Pay Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/pay POST https://api.stateset.network/v1/order/pay Pay for an order using ssUSD on the StateSet Commerce Network ### Overview This endpoint processes ssUSD (StateSet USD) stablecoin payments for orders on the StateSet Commerce Network. The payment is executed through smart contracts, ensuring secure and transparent transactions with instant settlement. ### Body The unique identifier of the order to be paid Payment method details for stablecoin payment Payment method type. Supported values: "ssusd", "usdc" (legacy) The customer's wallet address from which stablecoins will be debited The payment amount details The amount in stablecoin units (e.g., "100.50") The denomination. Supported values: "ssusd", "usdc" (legacy) The blockchain for payment. Options: "stateset" (default), "base", "solana", "cosmos" Optional array for splitting payments between multiple recipients Recipient wallet address Amount to send to this recipient Recipient type: "merchant", "platform\_fee", "affiliate" Additional metadata for the payment Optional memo or note for the payment External reference number for reconciliation Unique key to prevent duplicate payments ### Response Indicates whether the payment was successful Transaction details The blockchain transaction hash The block height where the transaction was included ISO 8601 timestamp of the transaction The amount of gas used for the transaction The blockchain where the transaction occurred Payment details Unique identifier for the payment The order ID that was paid The amount paid The stablecoin amount The denomination used (ssusd or usdc) USD equivalent value Payment status: "completed", "pending", "failed" Payment split details if applicable Updated order details The order identifier New order status after payment Payment status: "paid", "partially\_paid", "unpaid" ISO 8601 timestamp of payment ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/pay' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --header 'Content-Type: application/json' \ --data-raw '{ "order_id": "order_1234567890", "payment_method": { "type": "ssusd", "wallet_address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "value": "150.00", "denom": "ssusd" }, "chain": "stateset" }, "split_payments": [ { "recipient": "stateset1merchantaddress123", "amount": "135.00", "type": "merchant" }, { "recipient": "stateset1platformfeeaddress456", "amount": "15.00", "type": "platform_fee" } ], "metadata": { "memo": "Payment for Order #1234567890", "reference_number": "INV-2024-001", "idempotency_key": "pay_order_1234567890_001" } }' ``` ```javascript Node.js theme={null} const axios = require('axios'); async function payOrderWithSSUSD(orderId, amount, walletAddress) { try { const response = await axios.post( 'https://api.stateset.network/v1/order/pay', { order_id: orderId, payment_method: { type: 'ssusd', wallet_address: walletAddress, amount: { value: amount, denom: 'ssusd' }, chain: 'stateset' }, metadata: { memo: `Payment for Order #${orderId}`, idempotency_key: `pay_order_${orderId}_${Date.now()}` } }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); console.log('Payment successful:', response.data); return response.data; } catch (error) { console.error('Payment failed:', error.response?.data || error.message); throw error; } } // Example with payment splits async function payOrderWithSplits(orderId, totalAmount, customerWallet, splits) { try { const response = await axios.post( 'https://api.stateset.network/v1/order/pay', { order_id: orderId, payment_method: { type: 'ssusd', wallet_address: customerWallet, amount: { value: totalAmount, denom: 'ssusd' } }, split_payments: splits, metadata: { memo: `Split payment for Order #${orderId}`, idempotency_key: `pay_order_${orderId}_${Date.now()}` } }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); return response.data; } catch (error) { console.error('Split payment failed:', error.response?.data || error.message); throw error; } } ``` ```python Python theme={null} import requests def pay_order_with_ssusd(order_id, amount, wallet_address): """Pay for an order using ssUSD stablecoin""" url = "https://api.stateset.network/v1/order/pay" headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } payload = { "order_id": order_id, "payment_method": { "type": "ssusd", "wallet_address": wallet_address, "amount": { "value": str(amount), "denom": "ssusd" }, "chain": "stateset" }, "metadata": { "memo": f"Payment for Order #{order_id}", "idempotency_key": f"pay_order_{order_id}_{int(time.time())}" } } try: response = requests.post(url, json=payload, headers=headers) response.raise_for_status() result = response.json() print(f"Payment successful! Transaction: {result['transaction']['tx_hash']}") return result except requests.exceptions.RequestException as e: print(f"Payment failed: {e}") if hasattr(e, 'response') and e.response: print(f"Error details: {e.response.json()}") raise # Example with payment splits def pay_order_with_splits(order_id, total_amount, customer_wallet, merchant_wallet, platform_fee_percent=10): """Pay for an order with automatic platform fee split""" platform_fee = total_amount * (platform_fee_percent / 100) merchant_amount = total_amount - platform_fee url = "https://api.stateset.network/v1/order/pay" headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } payload = { "order_id": order_id, "payment_method": { "type": "ssusd", "wallet_address": customer_wallet, "amount": { "value": f"{total_amount:.2f}", "denom": "ssusd" } }, "split_payments": [ { "recipient": merchant_wallet, "amount": f"{merchant_amount:.2f}", "type": "merchant" }, { "recipient": "stateset1platformfeeaddress", "amount": f"{platform_fee:.2f}", "type": "platform_fee" } ], "metadata": { "memo": f"Split payment for Order #{order_id}", "idempotency_key": f"pay_order_{order_id}_{int(time.time())}" } } try: response = requests.post(url, json=payload, headers=headers) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: print(f"Split payment failed: {e}") raise ``` ```json theme={null} { "success": true, "transaction": { "tx_hash": "B5E7A2D9F3C8E1A4D6B9C3F7E2A5D8B1E4C7F9A2D5B8E1C4F7A9D2E5B8C1F4A7", "block_height": 1234567, "timestamp": "2024-01-15T10:30:05Z", "gas_used": "75000", "chain": "stateset" }, "payment": { "payment_id": "pay_9h8g7f6e5d4c3b2a", "order_id": "order_1234567890", "amount": { "value": "150.00", "denom": "ssusd", "usd_value": "150.00" }, "status": "completed", "splits": [ { "recipient": "stateset1merchantaddress123", "amount": "135.00", "type": "merchant", "tx_hash": "C6F8B3E0A6D9F4B7E3A6E9D4B7F0C3E8" }, { "recipient": "stateset1platformfeeaddress456", "amount": "15.00", "type": "platform_fee", "tx_hash": "D7G9C4F1B7E0A5C8F4B7F0E5C8G1D4F9" } ] }, "order": { "order_id": "order_1234567890", "status": "processing", "payment_status": "paid", "paid_at": "2024-01-15T10:30:05Z" } } ``` ### Error Codes | Code | Description | | ------------------------ | ------------------------------------------------------------ | | `INSUFFICIENT_FUNDS` | The wallet does not have enough USDC to complete the payment | | `ORDER_NOT_FOUND` | The specified order ID does not exist | | `ORDER_ALREADY_PAID` | The order has already been paid | | `INVALID_WALLET_ADDRESS` | The provided wallet address is invalid | | `PAYMENT_EXPIRED` | The payment window for this order has expired | | `NETWORK_ERROR` | There was an error communicating with the blockchain | | `SMART_CONTRACT_ERROR` | The smart contract execution failed | ### Notes * All payments are processed on the StateSet Commerce Network blockchain * USDC amounts must be specified as strings to avoid floating-point precision issues * The payment is atomic - either the entire payment succeeds or it fails completely * Gas fees are paid in STATE tokens, not USDC * Payments are final and cannot be reversed through the API (refunds must be processed separately) # Refund Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/refund POST https://api.stateset.network/v1/order/refund This endpoint processes a refund for an order. ### Body This is the ID of the order to be refunded. This is the amount to be refunded. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/refund' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "", "amount": "100.00" }' ``` # Release Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/release POST https://api.stateset.network/v1/order/release This endpoint releases an order from hold. ### Body This is the ID of the order to be released from hold. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/release' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Resolve Dispute Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/resolve POST https://api.stateset.network/v1/order/resolve This endpoint resolves a dispute for an order. ### Body This is the ID of the order dispute to be resolved. This is the resolution for the dispute. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/resolve' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "", "resolution": "Refund issued" }' ``` # Return Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/return POST https://api.stateset.network/v1/order/return This endpoint returns an order. ### Body This is the ID of the order to be returned. This is the reason for returning the order. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/return' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "", "reason": "Incorrect item received" }' ``` # Ship Order Source: https://docs.stateset.com/stateset-commerce-api-reference/orders/ship POST https://api.stateset.network/v1/order/ship This endpoint marks an order as shipped. ### Body This is the ID of the order to be shipped. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/order/ship' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # StateSet Commerce Network API Source: https://docs.stateset.com/stateset-commerce-api-reference/overview Enterprise blockchain infrastructure for instant global commerce with native stablecoins **New to StateSet?** Start with our [Quick Start Guide](#quick-start) to make your first API call in under 5 minutes. # StateSet Commerce Network: The Operating System for Global Commerce ## 🚀 Why StateSet? StateSet Commerce Network is the blockchain infrastructure that makes global commerce instant, programmable, and accessible. We're building the financial rails for the \$100+ trillion global economy. Sub-second transaction finality with 10,000+ TPS capacity ssUSD and USDC built-in, no bridging or wrapping needed SOC2 Type II compliant with built-in KYC/AML and audit trails ## 📊 By the Numbers

\$5B+

Total Value Processed

\< 1 sec

Transaction Finality

\$0.01

Average Transaction Cost

99.99%

Network Uptime

## 🏗️ What Can You Build? ### Global Payment Processing * Accept stablecoins from customers worldwide * Instant settlement to your account * Automated currency conversion * Built-in fraud protection ```javascript theme={null} // Accept payment in 3 lines const payment = await stateset.payments.create({ amount: 100.00, currency: 'ssusd', customer: 'cust_123' }); ``` ### Decentralized Finance * Liquidity pools with automated market making * Yield farming and staking rewards * Collateralized lending protocols * Synthetic asset creation ```javascript theme={null} // Create a liquidity pool const pool = await stateset.pools.create({ tokenA: 'ssusd', tokenB: 'atom', initialLiquidity: 10000 }); ``` ### Supply Chain Finance * Invoice factoring with instant funding * Purchase order financing * Letter of credit automation * Real-time settlement ```javascript theme={null} // Factor an invoice const factoring = await stateset.invoices.factor({ invoiceId: 'inv_123', discount: 2.5, immediate: true }); ``` ### Autonomous Commerce * Deploy AI agents with spending limits * Automated procurement and payments * Smart contract execution * Multi-signature controls ```javascript theme={null} // Deploy an AI agent const agent = await stateset.agents.create({ name: 'ProcurementBot', spendingLimit: 10000, permissions: ['purchase', 'negotiate'] }); ``` ## 🚀 Quick Start Get up and running with StateSet in minutes: Choose your preferred language: ```bash npm theme={null} npm install @stateset/sdk ``` ```bash yarn theme={null} yarn add @stateset/sdk ``` ```bash pip theme={null} pip install stateset ``` ```bash go theme={null} go get github.com/stateset/stateset-go ``` 1. Sign up at [dashboard.stateset.com](https://dashboard.stateset.com) 2. Complete KYC verification (takes \< 5 minutes) 3. Generate your API keys Keep your secret key secure and never expose it in client-side code! ```javascript theme={null} import { StateSet } from '@stateset/sdk'; // Initialize the client const stateset = new StateSet({ apiKey: 'sk_test_...' }); // Check your balance const balance = await stateset.account.balance(); console.log(`Balance: ${balance.ssusd} ssUSD`); // Send a payment const payment = await stateset.payments.send({ to: 'stateset1abc...', amount: 100.00, currency: 'ssusd', memo: 'First payment!' }); ``` ## 📚 Core APIs Issue, redeem, and transfer ssUSD with full GENIUS Act compliance Process payments, handle refunds, and manage payment methods Create and manage e-commerce orders with automated fulfillment Generate, send, and collect on invoices with instant settlement Access trade finance, factoring, and lending protocols Deploy and manage autonomous AI agents for commerce ## 🔐 Authentication All API requests require authentication using API keys: ```bash theme={null} curl https://api.stateset.com/v1/account/balance \ -H "Authorization: Bearer sk_test_..." ``` Use test mode keys (prefixed with `sk_test_`) for development and live mode keys (prefixed with `sk_live_`) for production. ## 🌐 Network Architecture ### Production Network * **Chain ID**: `stateset-1` * **RPC**: `https://rpc.stateset.com` * **API**: `https://api.stateset.com` * **Explorer**: `https://explorer.stateset.com` * **Status**: [status.stateset.com](https://status.stateset.com) ### Test Network * **Chain ID**: `stateset-testnet-1` * **RPC**: `https://rpc-testnet.stateset.com` * **API**: `https://api-testnet.stateset.com` * **Explorer**: `https://explorer-testnet.stateset.com` * **Faucet**: [faucet.stateset.com](https://faucet.stateset.com) ## 💡 Best Practices * Never expose API keys in client-side code * Use webhook signatures to verify events * Implement idempotency keys for critical operations * Enable 2FA on your dashboard account * Use pagination for large result sets * Implement exponential backoff for retries * Cache frequently accessed data * Use webhooks instead of polling * Always check the `error` field in responses * Log all errors with request IDs for debugging * Implement proper retry logic for transient errors * Monitor your rate limits ## 🆘 Need Help? Comprehensive guides and API references Chat with developers and get instant help Priority support for enterprise customers ## 🚀 Ready to Build? Sign up for a free account and get \$100 in test credits # Cancel Purchase Order Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/cancel POST https://api.stateset.network/v1/purchaseorder/cancel This endpoint cancels a new purchase order ### Body This is the ID of the purchase order to be cancelled ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/purchaseorder/cancel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Complete Purchase Order Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/complete POST https://api.stateset.network/v1/purchaseorder/complete This endpoint completes a new purchase order ### Body This is the ID of the purchase order to be completed. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/purchaseorder/complete' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Create Purchase Order Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/create POST https://api.stateset.network/v1/purchaseorder This endpoint creates a new purchase order ### Body This is the ID of the purchase order to be created. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/purchaseorder' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Finance Purchase Order Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/finance POST https://api.stateset.network/v1/purchaseorder/finance This endpoint finances a new purchase order ### Body This is the ID of the purchase order to be financed. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/purchaseorder/finance' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # Get Purchase Order Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/get Retrieve a purchase order by ID. # Get Purchase Order Use this endpoint to retrieve a purchase order by ID. # List Purchase Orders Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/list List purchase orders. # List Purchase Orders Use this endpoint to list purchase orders. # Request Purchase Order Source: https://docs.stateset.com/stateset-commerce-api-reference/purchaseorders/request POST https://api.stateset.network/v1/purchaseorder/request This endpoint creates a new purchase order ### Body This is the ID of the purchase order to be requested. ### Response Indicates whether the call was successful. 1 if successful, 0 if not. ```bash cURL theme={null} curl --location --request POST 'https://api.stateset.network/v1/purchaseorder/requested' \ --header 'Content-Type: application/json' \ --header 'Authorization: Token ' \ --data-raw '{ "id": "" }' ``` # SDKs & Libraries Source: https://docs.stateset.com/stateset-commerce-api-reference/sdks Official SDKs for integrating with StateSet Commerce Network **Latest Versions**: All SDKs are kept in sync with our API. Check [GitHub](https://github.com/stateset) for the latest releases. # Official StateSet SDKs Build on StateSet with our official SDKs available in multiple languages. Each SDK provides type-safe access to all StateSet APIs with built-in best practices. ## 🚀 Quick Install ```bash npm theme={null} npm install @stateset/sdk ``` ```bash yarn theme={null} yarn add @stateset/sdk ``` ```bash pip theme={null} pip install stateset ``` ```bash go theme={null} go get github.com/stateset/stateset-go ``` ```bash cargo theme={null} cargo add stateset ``` ```bash gem theme={null} gem install stateset ``` ## 📦 Available SDKs Full TypeScript support with async/await Pythonic API with type hints High-performance native Go client Memory-safe Rust implementation Idiomatic Ruby with Rails integration Enterprise Java with Spring support ## JavaScript/TypeScript ### Installation & Setup ```bash theme={null} npm install @stateset/sdk ``` ### Basic Configuration ```typescript theme={null} import { StateSet } from '@stateset/sdk'; // Initialize client const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY, network: 'mainnet', // 'mainnet' | 'testnet' options: { timeout: 30000, // 30 seconds retries: 3, webhookSecret: process.env.WEBHOOK_SECRET } }); ``` ### Core Features ```typescript theme={null} // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; // Create a payment const payment = await stateset.payments.create({ amount: 100.00, currency: 'ssusd', recipient: 'stateset1abc...', memo: 'Invoice #1234' }); // List payments with pagination const payments = await stateset.payments.list({ limit: 20, starting_after: 'pay_xyz789' }); // Subscribe to payment events stateset.payments.on('payment.succeeded', async (payment) => { logger.info('Payment completed', { paymentId: payment.id }); }); ``` ```typescript theme={null} // Create an order const order = await stateset.orders.create({ items: [ { sku: 'PROD-001', quantity: 2, price: 50.00 } ], customer: 'cust_123', shipping: { address: { /* ... */ }, method: 'express' } }); // Update order status await stateset.orders.update(order.id, { status: 'processing', tracking_number: '1Z999AA1234567890' }); ``` ```typescript theme={null} // Transfer ssUSD const transfer = await stateset.stablecoin.transfer({ to: 'stateset1xyz...', amount: '1000.00', memo: 'Supplier payment' }); // Check balance const balance = await stateset.stablecoin.balance({ address: 'stateset1abc...' }); // Batch transfers const batch = await stateset.stablecoin.batchTransfer({ transfers: [ { to: 'addr1', amount: '100.00' }, { to: 'addr2', amount: '200.00' } ] }); ``` ### Advanced Features #### Webhook Handling ```typescript theme={null} import { verifyWebhookSignature } from '@stateset/sdk'; app.post('/webhooks/stateset', express.raw({type: 'application/json'}), (req, res) => { const sig = req.headers['x-stateset-signature']; try { const event = verifyWebhookSignature( req.body, sig, process.env.WEBHOOK_SECRET ); // Handle event switch(event.type) { case 'payment.succeeded': handlePaymentSuccess(event.data); break; // ... other events } res.status(200).send('OK'); } catch (err) { res.status(400).send('Webhook Error'); } }); ``` #### Error Handling ```typescript theme={null} import { StateSetError } from '@stateset/sdk'; // Replace with a structured logger (Winston, Pino, etc) in production const logger = console; try { const payment = await stateset.payments.create({...}); } catch (error) { if (error instanceof StateSetError) { switch(error.type) { case 'invalid_request_error': logger.error('Invalid parameters', { param: error.param }); break; case 'authentication_error': logger.error('Authentication failed: check your API key'); break; case 'rate_limit_error': await sleep(error.retryAfter); // Retry request break; } } } ``` ## Python ### Installation ```bash theme={null} pip install stateset ``` ### Configuration ```python theme={null} from stateset import StateSet import os # Initialize client stateset = StateSet( api_key=os.getenv('STATESET_API_KEY'), network='mainnet', # 'mainnet' or 'testnet' timeout=30, max_retries=3 ) ``` ### Usage Examples ```python theme={null} import asyncio from stateset import AsyncStateSet async def main(): # Async client for high-performance applications async with AsyncStateSet(api_key=api_key) as client: # Concurrent operations tasks = [ client.payments.create(amount=100, currency='ssusd'), client.orders.list(limit=10), client.stablecoin.balance(address='stateset1...') ] results = await asyncio.gather(*tasks) print(f"Created {len(results)} operations concurrently") asyncio.run(main()) ``` ```python theme={null} import pandas as pd # Export data to pandas DataFrame payments = stateset.payments.list(limit=1000) df = pd.DataFrame([p.to_dict() for p in payments]) # Analyze payment data summary = df.groupby('status').agg({ 'amount': ['sum', 'mean', 'count'], 'created': 'min' }) print(summary) ``` ### Type Hints ```python theme={null} from typing import List, Optional from stateset.types import Payment, Order, Transfer def process_payments(payments: List[Payment]) -> None: """Process a list of payments with full type safety.""" for payment in payments: if payment.status == 'succeeded': send_receipt(payment.recipient, payment.amount) def create_order( items: List[dict], customer_id: str, shipping_method: Optional[str] = 'standard' ) -> Order: """Create an order with type-checked parameters.""" return stateset.orders.create( items=items, customer=customer_id, shipping={'method': shipping_method} ) ``` ## Go ### Installation ```bash theme={null} go get github.com/stateset/stateset-go ``` ### Configuration ```go theme={null} package main import ( "github.com/stateset/stateset-go" "github.com/stateset/stateset-go/payment" ) func main() { // Initialize client client := stateset.NewClient( os.Getenv("STATESET_API_KEY"), stateset.WithNetwork("mainnet"), stateset.WithTimeout(30 * time.Second), stateset.WithRetries(3), ) } ``` ### Usage Examples ```go theme={null} // Create payment payment, err := client.Payments.Create(&payment.CreateParams{ Amount: stateset.Float64(100.00), Currency: stateset.String("ssusd"), Recipient: stateset.String("stateset1abc..."), }) if err != nil { // Handle error if statesetErr, ok := err.(*stateset.Error); ok { log.Printf("StateSet error: %s (code: %s)", statesetErr.Message, statesetErr.Code) } } // Concurrent operations with goroutines var wg sync.WaitGroup payments := make([]*payment.Payment, 10) for i := 0; i < 10; i++ { wg.Add(1) go func(index int) { defer wg.Done() p, _ := client.Payments.Create(&payment.CreateParams{ Amount: stateset.Float64(100.00), }) payments[index] = p }(i) } wg.Wait() ``` ## Framework Integrations ### Next.js ```typescript theme={null} // pages/api/create-payment.ts import { StateSet } from '@stateset/sdk'; import type { NextApiRequest, NextApiResponse } from 'next'; const stateset = new StateSet({ apiKey: process.env.STATESET_SECRET_KEY }); export default async function handler( req: NextApiRequest, res: NextApiResponse ) { try { const payment = await stateset.payments.create({ amount: req.body.amount, currency: 'ssusd' }); res.status(200).json(payment); } catch (error) { res.status(400).json({ error: error.message }); } } ``` ### Django ```python theme={null} # views.py from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from stateset import StateSet import json stateset = StateSet(api_key=settings.STATESET_API_KEY) @csrf_exempt def create_payment(request): if request.method == 'POST': data = json.loads(request.body) try: payment = stateset.payments.create( amount=data['amount'], currency='ssusd', recipient=data['recipient'] ) return JsonResponse(payment.to_dict()) except Exception as e: return JsonResponse({'error': str(e)}, status=400) ``` ### Express.js ```javascript theme={null} const express = require('express'); const { StateSet } = require('@stateset/sdk'); const app = express(); const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY }); app.post('/api/payments', async (req, res) => { try { const payment = await stateset.payments.create({ amount: req.body.amount, currency: 'ssusd' }); res.json(payment); } catch (error) { res.status(400).json({ error: error.message }); } }); ``` ## 🧪 Testing ### Mock Mode ```typescript theme={null} import { StateSet, MockStateSet } from '@stateset/sdk'; // Use mock client in tests const stateset = process.env.NODE_ENV === 'test' ? new MockStateSet() : new StateSet({ apiKey: process.env.STATESET_API_KEY }); // Mock client returns predictable responses const payment = await stateset.payments.create({ amount: 100.00, currency: 'ssusd' }); // payment.id will look like 'pay_test_123' ``` ### Test Helpers ```typescript theme={null} import { createTestPayment, createTestOrder } from '@stateset/sdk/test'; describe('Payment Processing', () => { it('should process payment successfully', async () => { // Create test data const payment = createTestPayment({ amount: 100.00, status: 'succeeded' }); // Test your logic const result = await processPayment(payment); expect(result.success).toBe(true); }); }); ``` ## 📚 Resources Complete API documentation Sample applications and code Get help from developers Latest updates and releases # ssUSD Analytics API Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/analytics GET https://api.stateset.com/v1/stablecoin/analytics Real-time analytics and insights for StateSet USD (ssUSD) **Premium Feature**: Advanced analytics requires a Growth or Enterprise plan. [Upgrade →](https://stateset.com/pricing) # ssUSD Analytics API Get comprehensive insights into ssUSD supply, velocity, usage patterns, and market dynamics with our Analytics API. ## 🎯 Overview The Analytics API provides real-time and historical data about ssUSD, including: * Supply metrics and growth * Transaction velocity and patterns * User adoption and retention * Cross-chain activity * Market dynamics and liquidity ## 📊 Real-Time Metrics ### GET /v1/stablecoin/analytics/realtime Returns current ssUSD metrics updated every second. ```bash cURL theme={null} curl https://api.stateset.com/v1/stablecoin/analytics/realtime \ -H "Authorization: Bearer sk_test_..." ``` ```javascript JavaScript theme={null} const metrics = await stateset.stablecoin.analytics.realtime(); console.log('Current supply:', metrics.total_supply); console.log('24h volume:', metrics.volume_24h); ``` ```python Python theme={null} metrics = stateset.stablecoin.analytics.realtime() print(f"Current supply: ${metrics['total_supply']:,.2f}") print(f"Active wallets: {metrics['active_wallets_24h']:,}") ``` **Response:** ```json theme={null} { "timestamp": "2024-06-25T12:00:00Z", "total_supply": 1234567890.50, "total_supply_formatted": "$1,234,567,890.50", "circulation": { "circulating_supply": 1200000000.00, "locked_supply": 34567890.50, "burned_supply": 0.00 }, "volume": { "volume_24h": 89012345.67, "volume_7d": 623456789.12, "volume_30d": 2345678901.23, "avg_transaction_size": 2345.67 }, "velocity": { "velocity_24h": 0.072, "velocity_7d": 0.519, "velocity_30d": 1.954 }, "activity": { "transactions_24h": 37984, "active_wallets_24h": 12567, "new_wallets_24h": 892, "unique_receivers_24h": 8934 }, "distribution": { "top_10_concentration": 0.234, "top_100_concentration": 0.567, "gini_coefficient": 0.72 }, "chains": { "stateset": 987654321.00, "base": 123456789.00, "solana": 98765432.00, "cosmos_ibc": 24691358.50 } } ``` ## 📈 Historical Data ### GET /v1/stablecoin/analytics/historical Query historical ssUSD metrics with customizable time ranges and granularity. **Query Parameters:** Start date in ISO 8601 format Example: `2024-01-01T00:00:00Z` End date in ISO 8601 format Example: `2024-06-25T23:59:59Z` Data point frequency Options: `hourly`, `daily`, `weekly`, `monthly` Specific metrics to include Default: All available metrics **Example Request:** ```javascript theme={null} const historical = await stateset.stablecoin.analytics.historical({ start_date: '2024-01-01', end_date: '2024-06-25', granularity: 'daily', metrics: ['supply', 'volume', 'velocity', 'active_wallets'] }); // Plot supply growth const supplyChart = historical.data.map(d => ({ date: d.date, supply: d.metrics.supply })); ``` ## 🔍 Transaction Analytics ### GET /v1/stablecoin/analytics/transactions Analyze transaction patterns and behaviors. **Query Parameters:** Analysis period Options: `1h`, `24h`, `7d`, `30d`, `90d`, `1y` Group transactions by category Options: `size`, `type`, `chain`, `hour_of_day`, `day_of_week` **Response Example:** ```json theme={null} { "period": "24h", "transaction_count": 37984, "total_volume": 89012345.67, "size_distribution": [ { "range": "$0-100", "count": 12567, "percentage": 33.1 }, { "range": "$100-1000", "count": 18934, "percentage": 49.8 }, { "range": "$1000-10000", "count": 5892, "percentage": 15.5 }, { "range": "$10000+", "count": 591, "percentage": 1.6 } ], "type_breakdown": { "transfers": { "count": 25678, "volume": 45678901.23 }, "payments": { "count": 8901, "volume": 23456789.01 }, "defi": { "count": 3405, "volume": 19876655.43 } }, "peak_hours": [ { "hour": 14, "timezone": "UTC", "transactions": 2134 }, { "hour": 15, "timezone": "UTC", "transactions": 2098 }, { "hour": 16, "timezone": "UTC", "transactions": 1987 } ], "average_confirmation_time": 0.8, "failed_transaction_rate": 0.0012 } ``` ## 👥 User Analytics ### GET /v1/stablecoin/analytics/users Understand user behavior and adoption patterns. ```javascript theme={null} const userAnalytics = await stateset.stablecoin.analytics.users({ period: '30d', cohort_analysis: true }); // Cohort retention data console.log('30-day retention:', userAnalytics.cohort_retention.day_30); ``` **Response:** ```json theme={null} { "total_users": 156789, "new_users_period": 12567, "active_users_period": 45678, "user_segments": { "retail": { "count": 145678, "percentage": 92.9 }, "institutional": { "count": 8901, "percentage": 5.7 }, "merchant": { "count": 2210, "percentage": 1.4 } }, "balance_distribution": [ { "range": "$0-100", "users": 78901, "percentage": 50.3 }, { "range": "$100-1000", "users": 45678, "percentage": 29.1 }, { "range": "$1000-10000", "users": 23456, "percentage": 15.0 }, { "range": "$10000+", "users": 8754, "percentage": 5.6 } ], "cohort_retention": { "day_1": 0.85, "day_7": 0.67, "day_30": 0.52, "day_90": 0.41 }, "user_lifetime_value": { "average": 2345.67, "median": 567.89, "top_10_percent": 23456.78 } } ``` ## 🌊 Liquidity Analytics ### GET /v1/stablecoin/analytics/liquidity Monitor ssUSD liquidity across venues and chains. ```javascript theme={null} const liquidity = await stateset.stablecoin.analytics.liquidity(); // Find best liquidity sources const bestVenues = liquidity.venues .sort((a, b) => b.depth_2_percent - a.depth_2_percent) .slice(0, 5); ``` **Response:** ```json theme={null} { "total_liquidity": 456789012.34, "venues": [ { "name": "StateSet Native", "chain": "stateset", "liquidity": 234567890.12, "depth_2_percent": 12345678.90, "spread": 0.0001, "volume_24h": 34567890.12 }, { "name": "Uniswap V3", "chain": "base", "liquidity": 123456789.01, "depth_2_percent": 6789012.34, "spread": 0.0003, "volume_24h": 23456789.01 } ], "liquidity_score": 94.5, "market_depth": { "buy_1m": 0.0002, "sell_1m": 0.0002, "buy_10m": 0.0012, "sell_10m": 0.0013 } } ``` ## 📊 Custom Reports ### POST /v1/stablecoin/analytics/reports Generate custom analytics reports with specific parameters. ```javascript theme={null} // Create monthly treasury report const report = await stateset.stablecoin.analytics.createReport({ type: 'treasury_report', period: { start: '2024-06-01', end: '2024-06-30' }, sections: [ 'balance_summary', 'transaction_analysis', 'yield_performance', 'risk_metrics' ], format: 'pdf', email_to: 'cfo@company.com' }); console.log('Report URL:', report.download_url); ``` ## 🔔 Analytics Webhooks Subscribe to analytics events and thresholds. ```javascript theme={null} // Alert when supply changes significantly const webhook = await stateset.webhooks.create({ url: 'https://yourapp.com/webhooks/analytics', events: ['analytics.supply_change'], filters: { change_percentage: 5, // Alert on 5% changes time_window: '1h' } }); // Alert on unusual activity const activityWebhook = await stateset.webhooks.create({ url: 'https://yourapp.com/webhooks/activity', events: ['analytics.unusual_activity'], config: { volume_spike: 3, // 3x normal volume wallet_concentration: 0.7 // 70% concentration } }); ``` ## 📈 Visualization Examples ### Supply Growth Chart ```javascript theme={null} // Fetch data for chart const supplyData = await stateset.stablecoin.analytics.historical({ start_date: '2024-01-01', end_date: new Date().toISOString(), granularity: 'daily', metrics: ['supply'] }); // Format for Chart.js const chartData = { labels: supplyData.data.map(d => d.date), datasets: [{ label: 'ssUSD Supply', data: supplyData.data.map(d => d.metrics.supply), borderColor: 'rgb(75, 192, 192)', tension: 0.1 }] }; ``` ### Transaction Heatmap ```javascript theme={null} // Get hourly transaction data const heatmapData = await stateset.stablecoin.analytics.transactions({ period: '7d', breakdown_by: 'hour_and_day' }); // Format for heatmap visualization const heatmap = heatmapData.hourly_pattern.map(h => ({ day: h.day_of_week, hour: h.hour, value: h.transaction_count, intensity: h.transaction_count / heatmapData.max_hourly })); ``` ## 🎯 Use Cases ### Risk Management Dashboard ```javascript theme={null} class RiskDashboard { async getMetrics() { const [realtime, liquidity, users] = await Promise.all([ stateset.stablecoin.analytics.realtime(), stateset.stablecoin.analytics.liquidity(), stateset.stablecoin.analytics.users({ period: '24h' }) ]); return { concentration_risk: this.calculateConcentrationRisk(realtime), liquidity_risk: this.calculateLiquidityRisk(liquidity), velocity_risk: this.calculateVelocityRisk(realtime), overall_score: this.calculateOverallRisk(realtime, liquidity, users) }; } calculateConcentrationRisk(data) { const gini = data.distribution.gini_coefficient; return { score: (1 - gini) * 100, level: gini > 0.8 ? 'high' : gini > 0.6 ? 'medium' : 'low', recommendation: gini > 0.8 ? 'Monitor large holder activities' : 'Healthy distribution' }; } } ``` ### Market Making Analytics ```javascript theme={null} // Analyze spread and volume for market making const marketAnalytics = await stateset.stablecoin.analytics.liquidity({ include_orderbook: true, depth_levels: [100000, 1000000, 10000000] }); const opportunities = marketAnalytics.venues .filter(v => v.spread > 0.0005 && v.volume_24h > 1000000) .map(v => ({ venue: v.name, potential_profit: v.volume_24h * v.spread * 0.5, required_capital: v.depth_2_percent * 2 })); ``` ## 🔗 Related Endpoints Real-time reserve composition Detailed transaction data Monthly audit reports Real-time notifications # Upload Reserve Attestation Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/attestation POST https://api.stateset.com/v1/stablecoin/attestation/upload Upload monthly reserve attestation reports signed by CPA and officers This endpoint is restricted to authorized administrators for uploading monthly reserve attestation reports as required by the GENIUS Act of 2025. ## Authentication This endpoint requires admin-level authentication with attestation upload permissions. ```bash theme={null} Authorization: Bearer YOUR_ADMIN_TOKEN X-HMAC-Signature: YOUR_HMAC_SIGNATURE X-Admin-Certificate: YOUR_ADMIN_CERT ``` ## Request Body The month/year of the attestation (YYYY-MM-DD format, must be last day of month) Example: `2025-07-31` Base64 encoded PDF of the signed attestation report SHA-256 hash of the report file for integrity verification CPA firm information Registered public accounting firm name CPA license number Name of lead auditor Date auditor signed the report Array of C-suite officer signatures Officer's full legal name Officer title (CEO, CFO, etc.) Digital signature (base64 encoded) Date of signature Summary of reserve composition Total value of reserves in USD Total ssUSD supply at attestation date Reserves / Supply ratio (must be >= 1.0) Breakdown by asset type with amounts and percentages Additional metadata Any additional notes or observations Whether there were material changes from previous month ## Response Unique attestation record ID Upload status: "pending\_verification", "verified", "published" Public URL where the attestation will be accessible Verification details Whether file hash matches provided hash Whether all digital signatures are valid Compliance validation status When the attestation will be publicly available ISO 8601 timestamp of upload ```json Example Request theme={null} { "attestation_date": "2025-07-31", "report_file": "JVBERi0xLjQKJeLjz9MKNCAwIG9iago8PC9GaWx0ZXI...", "report_hash": "3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5", "auditor": { "firm_name": "Ernst & Young LLP", "license_number": "CPA-123456", "lead_auditor_name": "Sarah Johnson", "signature_date": "2025-08-05" }, "officer_signatures": [ { "name": "John Smith", "title": "Chief Executive Officer", "signature": "MGUCMQCrhPgP3VxqFqFwf+6n...", "signature_date": "2025-08-05" }, { "name": "Jane Doe", "title": "Chief Financial Officer", "signature": "MGUCMQDKhPbB4WyqGqGxg+7o...", "signature_date": "2025-08-05" } ], "reserve_summary": { "total_reserves_usd": "1234567890.00", "total_supply_susd": "1234567890.00", "reserve_ratio": 1.0, "composition": { "cash": { "amount": "123456789.00", "percentage": 10.0 }, "treasury_bills": { "amount": "864197523.00", "percentage": 70.0 }, "money_market_funds": { "amount": "185185183.50", "percentage": 15.0 }, "repo_agreements": { "amount": "61728394.50", "percentage": 5.0 } } }, "metadata": { "notes": "No material changes from previous month", "material_changes": false } } ``` ```json Example Response theme={null} { "id": "att_2025_07_abc123", "status": "verified", "public_url": "https://reserves.stateset.com/attestations/2025-07-31.pdf", "verification": { "hash_verified": true, "signatures_verified": true, "compliance_check": "passed" }, "publication_date": "2025-08-06T00:00:00Z", "created_at": "2025-08-05T14:30:00Z" } ``` ## Error Codes | Code | Description | | ----- | ---------------------------------------------------- | | `400` | Invalid request format or missing required fields | | `401` | Unauthorized - Invalid admin credentials | | `403` | Forbidden - Insufficient permissions | | `409` | Conflict - Attestation for this month already exists | | `422` | Validation failed - Invalid signatures or data | | `500` | Internal server error | ## Compliance Notes * Attestations must be uploaded within 5 business days of month end * All signatures must be from authorized officers on file * Criminal penalties apply for false or misleading attestations * Reports are immutable once published ## Code Examples ```javascript Node.js theme={null} const axios = require('axios'); const fs = require('fs'); const crypto = require('crypto'); async function uploadAttestation(pdfPath, attestationData) { // Read and encode PDF const pdfBuffer = fs.readFileSync(pdfPath); const pdfBase64 = pdfBuffer.toString('base64'); // Calculate hash const hash = crypto.createHash('sha256'); hash.update(pdfBuffer); const pdfHash = hash.digest('hex'); // Prepare request const requestData = { attestation_date: attestationData.date, report_file: pdfBase64, report_hash: pdfHash, auditor: attestationData.auditor, officer_signatures: attestationData.signatures, reserve_summary: attestationData.summary }; try { const response = await axios.post( 'https://api.stateset.com/v1/stablecoin/attestation/upload', requestData, { headers: { 'Authorization': 'Bearer YOUR_ADMIN_TOKEN', 'X-HMAC-Signature': generateHMAC(requestData), 'X-Admin-Certificate': 'YOUR_ADMIN_CERT', 'Content-Type': 'application/json' } } ); console.log('Attestation uploaded:', response.data); console.log('Public URL:', response.data.public_url); return response.data; } catch (error) { console.error('Upload failed:', error.response.data); throw error; } } ``` ```python Python theme={null} import requests import base64 import hashlib import json from datetime import datetime class AttestationUploader: def __init__(self, admin_token, admin_cert): self.admin_token = admin_token self.admin_cert = admin_cert self.base_url = "https://api.stateset.com/v1/stablecoin" def upload_attestation(self, pdf_path, attestation_data): """Upload monthly reserve attestation""" # Read and encode PDF with open(pdf_path, 'rb') as f: pdf_content = f.read() pdf_base64 = base64.b64encode(pdf_content).decode('utf-8') # Calculate hash pdf_hash = hashlib.sha256(pdf_content).hexdigest() # Validate attestation date is last day of month date = datetime.strptime(attestation_data['date'], '%Y-%m-%d') next_month = date.replace(day=28) + datetime.timedelta(days=4) last_day = next_month - datetime.timedelta(days=next_month.day) if date.date() != last_day.date(): raise ValueError("Attestation date must be last day of month") # Prepare request request_data = { "attestation_date": attestation_data['date'], "report_file": pdf_base64, "report_hash": pdf_hash, "auditor": attestation_data['auditor'], "officer_signatures": attestation_data['signatures'], "reserve_summary": attestation_data['summary'], "metadata": attestation_data.get('metadata', {}) } # Generate HMAC signature hmac_signature = self.generate_hmac(request_data) headers = { "Authorization": f"Bearer {self.admin_token}", "X-HMAC-Signature": hmac_signature, "X-Admin-Certificate": self.admin_cert, "Content-Type": "application/json" } try: response = requests.post( f"{self.base_url}/attestation/upload", json=request_data, headers=headers ) response.raise_for_status() result = response.json() print(f"Attestation uploaded successfully!") print(f"ID: {result['id']}") print(f"Status: {result['status']}") print(f"Public URL: {result['public_url']}") return result except requests.exceptions.RequestException as e: print(f"Upload failed: {e}") if hasattr(e, 'response') and e.response: print(f"Error details: {e.response.json()}") raise # Example usage uploader = AttestationUploader("YOUR_ADMIN_TOKEN", "YOUR_ADMIN_CERT") attestation_data = { "date": "2025-07-31", "auditor": { "firm_name": "Ernst & Young LLP", "license_number": "CPA-123456", "lead_auditor_name": "Sarah Johnson", "signature_date": "2025-08-05" }, "signatures": [ { "name": "John Smith", "title": "Chief Executive Officer", "signature": "MGUCMQCrhPgP3VxqFqFwf+6n...", "signature_date": "2025-08-05" }, { "name": "Jane Doe", "title": "Chief Financial Officer", "signature": "MGUCMQDKhPbB4WyqGqGxg+7o...", "signature_date": "2025-08-05" } ], "summary": { "total_reserves_usd": "1234567890.00", "total_supply_susd": "1234567890.00", "reserve_ratio": 1.0, "composition": { "cash": {"amount": "123456789.00", "percentage": 10.0}, "treasury_bills": {"amount": "864197523.00", "percentage": 70.0}, "money_market_funds": {"amount": "185185183.50", "percentage": 15.0}, "repo_agreements": {"amount": "61728394.50", "percentage": 5.0} } } } uploader.upload_attestation("july_2025_attestation.pdf", attestation_data) ``` # Get ssUSD Balance Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/balance GET https://api.stateset.com/v1/stablecoin/balance/:address Query ssUSD balance and detailed holdings information across all supported chains This endpoint provides real-time balance information with multi-chain support and historical querying capabilities. # ssUSD Balance API Query StateSet USD (ssUSD) balances with comprehensive filtering, multi-chain aggregation, and real-time updates. ## 🔑 Authentication ```bash cURL theme={null} curl https://api.stateset.com/v1/stablecoin/balance/stateset1abc... \ -H "Authorization: Bearer sk_test_..." ``` ```javascript JavaScript theme={null} const balance = await stateset.stablecoin.balance({ address: 'stateset1abc...' }); ``` ```python Python theme={null} balance = stateset.stablecoin.balance( address='stateset1abc...' ) ``` ## 📋 Path Parameters The blockchain address to query. Supports multiple formats: * **StateSet**: `stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu` * **Ethereum/Base**: `0x742d35Cc6634C0532925a3b844Bc9e7595f6E321` * **Solana**: `DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263` ## 🔍 Query Parameters Filter by specific chains or query all chains Options: `["stateset", "base", "solana", "cosmos"]` Default: All chains where address has balance Include pending transactions in balance calculation Useful for showing "available" vs "total" balance Include locked/vesting balances in response Query historical balance at specific block height Example: `1542389` Query historical balance at specific time Format: ISO 8601 (e.g., `2024-06-25T12:00:00Z`) Convert balance to another currency Options: `USD`, `EUR`, `GBP`, `JPY`, etc. ## 📤 Response The queried blockchain address Balance breakdown by type and chain Spendable balance (excluding pending and locked) Balance in pending transactions Locked or vesting balance Total balance (available + pending + locked) Balance breakdown by blockchain Chain identifier Balance on this chain Pending balance on this chain Last transaction timestamp Balance in other currencies (if requested) Additional account information Timestamp of first ssUSD transaction Total number of transactions Account classification: `retail`, `institutional`, `merchant` ```bash Basic Balance Query theme={null} curl https://api.stateset.com/v1/stablecoin/balance/stateset1abc... \ -H "Authorization: Bearer sk_test_..." ``` ```javascript Multi-Chain Balance theme={null} // Get balance across all chains const balance = await stateset.stablecoin.balance({ address: 'stateset1abc...', chains: ['stateset', 'base', 'solana'], include_pending: true, include_locked: true }); console.log('Total balance:', balance.balances.total); console.log('Available:', balance.balances.available); // Check balance by chain balance.chains.forEach(chain => { console.log(`${chain.chain}: ${chain.balance} ssUSD`); }); ``` ```python Historical Balance theme={null} # Query balance at specific time from datetime import datetime, timedelta # Balance 30 days ago past_date = datetime.now() - timedelta(days=30) historical = stateset.stablecoin.balance( address='stateset1abc...', at_timestamp=past_date.isoformat() ) print(f"Balance 30 days ago: {historical['balances']['total']}") # Calculate balance change current = stateset.stablecoin.balance(address='stateset1abc...') change = float(current['balances']['total']) - float(historical['balances']['total']) print(f"30-day change: ${change:,.2f}") ``` ```javascript Batch Balance Query theme={null} // Check multiple addresses efficiently const addresses = [ 'stateset1abc...', 'stateset1def...', 'stateset1ghi...' ]; const balances = await Promise.all( addresses.map(addr => stateset.stablecoin.balance({ address: addr }) ) ); // Calculate total holdings const totalHoldings = balances.reduce((sum, b) => sum + parseFloat(b.balances.total), 0 ); console.log(`Total ssUSD across all addresses: $${totalHoldings.toFixed(2)}`); ``` ```json Standard Response theme={null} { "address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "balances": { "available": "10500.50", "pending": "250.00", "locked": "5000.00", "total": "15750.50" }, "chains": [ { "chain": "stateset", "balance": "12500.50", "pending": "150.00", "last_activity": "2024-06-25T11:45:00Z" }, { "chain": "base", "balance": "2000.00", "pending": "100.00", "last_activity": "2024-06-25T10:30:00Z" }, { "chain": "solana", "balance": "1250.00", "pending": "0.00", "last_activity": "2024-06-24T18:00:00Z" } ], "conversions": { "USD": "15750.50", "EUR": "14525.67", "GBP": "12456.89" }, "metadata": { "first_transaction": "2024-01-15T08:00:00Z", "transaction_count": 342, "account_type": "retail", "risk_score": "low" } } ``` ```json Empty Balance Response theme={null} { "address": "stateset1newuser...", "balances": { "available": "0.00", "pending": "0.00", "locked": "0.00", "total": "0.00" }, "chains": [], "metadata": { "first_transaction": null, "transaction_count": 0, "account_type": "new" } } ``` ## 💡 Common Use Cases ### Treasury Dashboard ```javascript theme={null} // Real-time treasury monitoring class TreasuryDashboard { async getSnapshot() { const balance = await stateset.stablecoin.balance({ address: this.treasuryAddress, include_pending: true, convert_to: ['USD', 'EUR'] }); return { total_assets: balance.balances.total, liquid_assets: balance.balances.available, pending_settlements: balance.balances.pending, chain_distribution: this.analyzeChainDistribution(balance.chains), fx_exposure: balance.conversions }; } analyzeChainDistribution(chains) { const total = chains.reduce((sum, c) => sum + parseFloat(c.balance), 0 ); return chains.map(c => ({ chain: c.chain, balance: c.balance, percentage: (parseFloat(c.balance) / total * 100).toFixed(2) })); } } ``` ### Payment Processing ```javascript theme={null} // Check balance before processing payment async function processPayment(amount, recipient) { // Get current balance const balance = await stateset.stablecoin.balance({ address: merchantWallet, include_pending: true }); const available = parseFloat(balance.balances.available); if (available < amount) { throw new Error(`Insufficient funds. Available: ${available}`); } // Process payment const payment = await stateset.stablecoin.transfer({ to: recipient, amount: amount.toString(), memo: 'Payment processed' }); return payment; } ``` ### Multi-Signature Wallet ```javascript theme={null} // Monitor multi-sig wallet balance const multiSig = { address: 'stateset1multisig...', signers: ['addr1', 'addr2', 'addr3'], threshold: 2 }; // Get balance and pending transactions const balance = await stateset.stablecoin.balance({ address: multiSig.address, include_pending: true }); // Alert if large pending transaction if (parseFloat(balance.balances.pending) > 100000) { await notifySigners({ message: 'Large pending transaction requires approval', amount: balance.balances.pending, signers: multiSig.signers }); } ``` ## 🔔 Webhooks Subscribe to balance change events: ```javascript theme={null} // Get notified of balance changes const webhook = await stateset.webhooks.create({ url: 'https://yourapp.com/webhooks/balance', events: ['balance.changed'], filters: { address: 'stateset1abc...', minimum_change: 100 // Only notify for changes > $100 } }); // Webhook payload { "event": "balance.changed", "data": { "address": "stateset1abc...", "previous_balance": "10000.00", "new_balance": "11500.00", "change": "1500.00", "transaction_id": "tx_123", "chain": "stateset" } } ``` ## 🚨 Error Handling ```javascript theme={null} try { const balance = await stateset.stablecoin.balance({ address: userAddress }); } catch (error) { switch(error.code) { case 'invalid_address': console.error('Invalid address format'); break; case 'rate_limit': console.error('Too many requests, retry after:', error.retry_after); break; case 'network_error': console.error('Network issue, retrying...'); // Implement retry logic break; default: console.error('Unexpected error:', error); } } ``` ## 📊 Related Endpoints Send ssUSD to another address View transaction history Balance analytics and insights View backing reserves # ssUSD Compliance & Regulatory Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/compliance Complete guide to StateSet USD compliance, KYC/AML requirements, and regulatory framework # ssUSD Compliance & Regulatory Guide StateSet USD (ssUSD) will be issued under the GENIUS Act, making it a federally-regulated stablecoin with comprehensive compliance requirements. All ssUSD operations are subject to regulatory compliance. Failure to meet requirements may result in transaction blocks or account restrictions. ## 🏛️ Regulatory Framework ### GENIUS Act Compliance Regulated by the Office of the Comptroller of the Currency (OCC) C-suite executives face criminal liability for misreporting reserves CPA-signed reserve reports published on-chain monthly Customer funds held separately from corporate assets ### Jurisdictional Coverage | Region | Status | Requirements | | -------------- | -------------------- | -------------------------- | | United States | ✅ Fully Compliant | KYC/AML required | | European Union | ✅ MiCA Compliant | KYC/AML required | | United Kingdom | ✅ FCA Registered | Enhanced due diligence | | Singapore | ✅ MAS Licensed | KYC/AML required | | Japan | ✅ FSA Approved | Strict wallet requirements | | Canada | ✅ FINTRAC Registered | KYC/AML required | ## 👤 KYC Requirements ### Individual Accounts ```javascript theme={null} // KYC verification for individuals const kycResult = await stateset.compliance.verifyIndividual({ personal_info: { first_name: 'John', last_name: 'Smith', date_of_birth: '1985-06-15', ssn_last4: '1234' // US only }, address: { street: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94105', country: 'US' }, documents: { id_front: 'base64_encoded_image', id_back: 'base64_encoded_image', proof_of_address: 'base64_encoded_pdf' } }); if (kycResult.status === 'approved') { // Enable ssUSD transactions await stateset.accounts.enableStablecoin({ account_id: kycResult.account_id, limits: kycResult.approved_limits }); } ``` ### Business Accounts ```javascript theme={null} // Enhanced KYC for businesses const businessKYC = await stateset.compliance.verifyBusiness({ business_info: { legal_name: 'Acme Corporation', dba_name: 'Acme', tax_id: '12-3456789', formation_date: '2015-01-01', business_type: 'corporation' }, beneficial_owners: [ { name: 'Jane Doe', ownership_percentage: 51, date_of_birth: '1980-01-01', ssn_last4: '5678' } ], documents: { formation_docs: 'base64_encoded_pdf', tax_certificate: 'base64_encoded_pdf', bank_statement: 'base64_encoded_pdf' } }); ``` ## 🛡️ AML Monitoring ### Transaction Screening ```javascript theme={null} // Real-time transaction monitoring const screening = await stateset.compliance.screenTransaction({ from: 'stateset1sender...', to: 'stateset1recipient...', amount: '50000.00', purpose: 'B2B payment' }); if (screening.risk_level === 'high') { // Enhanced review required await stateset.compliance.requestEnhancedReview({ transaction_id: screening.transaction_id, reason: screening.risk_factors }); } // Risk levels and actions switch(screening.risk_level) { case 'low': // Proceed with transaction break; case 'medium': // May require additional information break; case 'high': // Manual review required break; case 'blocked': // Transaction cannot proceed throw new Error('Transaction blocked for compliance'); } ``` ### Sanctions Screening ```javascript theme={null} // Check against sanctions lists const sanctionsCheck = await stateset.compliance.checkSanctions({ entities: [ { type: 'individual', name: 'John Smith', date_of_birth: '1985-06-15', nationality: 'US' } ], lists: ['OFAC', 'EU', 'UN', 'UK'] }); // Response { "screening_id": "scr_123", "status": "clear", "matches": [], "lists_checked": ["OFAC_SDN", "EU_SANCTIONS", "UN_SANCTIONS", "UK_SANCTIONS"], "timestamp": "2024-06-25T12:00:00Z" } ``` ## 📊 Transaction Limits ### Individual Limits | Transaction Type | Daily Limit | Monthly Limit | Per Transaction | | ---------------- | ----------- | ------------- | --------------- | | Standard | \$10,000 | \$50,000 | \$5,000 | | Verified | \$100,000 | \$500,000 | \$50,000 | | Premium | \$1,000,000 | \$10,000,000 | \$500,000 | ### Business Limits | Business Type | Daily Limit | Monthly Limit | Per Transaction | | ------------- | ----------- | ------------- | --------------- | | Startup | \$50,000 | \$250,000 | \$25,000 | | SMB | \$500,000 | \$5,000,000 | \$250,000 | | Enterprise | Custom | Custom | Custom | ### Limit Management ```javascript theme={null} // Check current limits const limits = await stateset.compliance.getLimits({ account_id: 'acc_123' }); // Request limit increase const increaseRequest = await stateset.compliance.requestLimitIncrease({ account_id: 'acc_123', requested_limits: { daily: '500000.00', monthly: '5000000.00' }, justification: 'Business growth requiring higher payment volumes', supporting_docs: ['bank_statements.pdf', 'financial_projections.pdf'] }); ``` ## 🚨 Suspicious Activity Reporting ### Automatic SAR Filing ```javascript theme={null} // System automatically files SARs for suspicious patterns const sarTriggers = { rapid_movement: { threshold: '$10000_in_1_hour', action: 'auto_file_sar' }, structuring: { pattern: 'multiple_9999_transactions', action: 'auto_file_sar' }, unusual_pattern: { detection: 'ml_anomaly_detection', action: 'manual_review' } }; // Manual SAR filing const sar = await stateset.compliance.fileSAR({ account_id: 'acc_123', transaction_ids: ['tx_456', 'tx_789'], suspicious_activity: 'Unusual transaction pattern', narrative: 'Customer made 50 transactions of $9,999 each within 24 hours' }); ``` ## 🌍 Cross-Border Compliance ### FATF Travel Rule ```javascript theme={null} // Include required information for cross-border transfers const crossBorderTransfer = await stateset.stablecoin.transfer({ amount: '15000.00', to: 'stateset1recipient...', travel_rule_info: { originator: { name: 'John Smith', account: 'stateset1sender...', address: '123 Main St, San Francisco, CA 94105', national_id: 'US123456789' }, beneficiary: { name: 'Acme Corp', account: 'stateset1recipient...', address: '456 Business Ave, London, UK' } } }); ``` ### Currency Controls ```javascript theme={null} // Check country-specific restrictions const restrictions = await stateset.compliance.checkRestrictions({ from_country: 'US', to_country: 'CN', amount: '50000.00', purpose: 'trade_payment' }); if (restrictions.requires_declaration) { await stateset.compliance.fileDeclaration({ type: restrictions.declaration_type, amount: '50000.00', purpose: 'Import payment for electronics' }); } ``` ## 📋 Compliance Dashboard ### Real-Time Monitoring ```javascript theme={null} // Get compliance overview const dashboard = await stateset.compliance.getDashboard({ period: '30d' }); // Response { "compliance_score": 98.5, "total_transactions": 15234, "flagged_transactions": 23, "resolved_flags": 20, "pending_reviews": 3, "sar_filed": 1, "sanctions_hits": 0, "kyc_verifications": { "total": 234, "approved": 225, "rejected": 5, "pending": 4 }, "risk_distribution": { "low": 14890, "medium": 321, "high": 23 } } ``` ### Audit Trail ```javascript theme={null} // Export compliance audit trail const auditTrail = await stateset.compliance.exportAuditTrail({ start_date: '2024-01-01', end_date: '2024-06-30', include: ['kyc_decisions', 'transaction_reviews', 'sar_filings'], format: 'csv' }); // Immutable on-chain record const proof = await stateset.compliance.recordAuditProof({ period: 'Q2_2024', hash: auditTrail.hash, attestor: 'chief_compliance_officer' }); ``` ## 🔐 Data Privacy ### GDPR Compliance ```javascript theme={null} // Handle data subject requests const gdprRequest = await stateset.compliance.processGDPR({ type: 'access_request', subject_id: 'user_123', verify_identity: true }); // Right to be forgotten (with regulatory retention) const deletion = await stateset.compliance.deletePersonalData({ subject_id: 'user_123', retain_for_compliance: true, retention_period: '7_years' }); ``` ## 🔗 Resources Detailed compliance procedures Latest regulatory changes Compliance training materials Compliance API documentation # ssUSD FAQ & Troubleshooting Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/faq-troubleshooting Frequently asked questions and troubleshooting guide for StateSet USD # ssUSD FAQ & Troubleshooting Find answers to common questions and solutions to typical issues when working with StateSet USD. ## ❓ Frequently Asked Questions ### General Questions **StateSet USD (ssUSD)** is a fully-backed, regulatory-compliant stablecoin pegged 1:1 to the US Dollar. It's a stablecoin issued under the GENIUS Act, featuring: * 1:1 USD backing with audited reserves * Monthly CPA attestations published on-chain * Criminal penalties for reserve misreporting * Instant settlement on StateSet Network * Multi-chain support (Base, Solana, Cosmos) * Full KYC/AML compliance **Yes, ssUSD has multiple safety layers:** 1. **Regulatory Safety**: Federal oversight by OCC 2. **Reserve Safety**: 100% backed by US Dollars and T-Bills 3. **Legal Safety**: Criminal penalties for misreporting 4. **Technical Safety**: Audited smart contracts 5. **Operational Safety**: Segregated customer assets See our [security audits](/security/audits) and [reserve reports](/stablecoin/reserves). **ssUSD Use Cases:** * **Payments**: Instant, low-cost transactions globally * **E-commerce**: Accept payments without chargebacks * **Payroll**: Pay employees instantly worldwide * **Treasury**: Hold stable, liquid reserves * **Cross-border**: Send money internationally ### Technical Questions **Supported Chains:** 1. **StateSet** (Native): Instant, \$0.01 fees 2. **Base**: Coinbase's L2, low fees 3. **Solana**: High-speed DeFi 4. **Cosmos IBC**: 50+ connected chains 5. **Ethereum** (Coming Q2 2024) 6. **Polygon** (Coming Q2 2024) Use our [bridge](/stablecoin/bridge) to move between chains. **Limits by Account Type:** | Account Type | Daily | Monthly | Per Transaction | | ------------ | ----------- | ------------ | --------------- | | Basic | \$10,000 | \$50,000 | \$5,000 | | Verified | \$100,000 | \$500,000 | \$50,000 | | Premium | \$1,000,000 | \$10,000,000 | \$500,000 | | Business | Custom | Custom | Custom | [Request limit increase →](/compliance/limits) **Transfer Speeds:** * **On StateSet**: \< 1 second finality * **To Base**: \~2 seconds * **To Solana**: \~3 seconds * **Cross-chain**: 1-5 minutes (via bridge) * **Bank redemption**: T+1 business day **Fee Structure:** * **Transfers on StateSet**: \$0.01 flat * **Cross-chain bridge**: 0.1% (min $1, max $100) * **Issuance**: 0% (no fees) * **Redemption**: 0% (no fees) * **Inactive account**: \$0/month No hidden fees, no minimum balance requirements. ### Compliance Questions **KYC Requirements:** * **Required for**: Issuance, redemption, > \$1,000 daily volume * **Not required for**: Transfers between verified users \< \$1,000 * **Process time**: 5-10 minutes automated * **Documents needed**: Government ID, proof of address * **Business accounts**: Additional docs (formation, tax ID) [Start KYC →](/kyc/start) **Supported Regions:** ✅ **Fully Supported**: USA, Canada, UK, EU, Singapore, Japan, Australia ⚠️ **Limited Support**: China, India, Brazil (transfers only) ❌ **Not Supported**: North Korea, Iran, Syria, Cuba, Russia (sanctioned) See [full country list](/compliance/countries) **Tax Reporting:** * **US Persons**: 1099 forms for > \$600 annual volume * **Non-US**: Comply with local regulations * **API Access**: Download transaction history anytime * **Export Formats**: CSV, PDF, JSON ssUSD transactions may be taxable events. Consult your tax advisor. ## 🔧 Troubleshooting Guide ### Common Errors **Problem**: Transaction fails with insufficient funds error **Solutions:** 1. Check your balance including pending transactions: ```javascript theme={null} const balance = await stateset.stablecoin.balance({ address: yourAddress, include_pending: true }); ``` 2. Ensure you're accounting for fees (\$0.01 per transaction) 3. Check if funds are locked or vesting: ```javascript theme={null} console.log('Available:', balance.balances.available); console.log('Locked:', balance.balances.locked); ``` **Problem**: Address validation fails **Solutions:** 1. Verify address format for the chain: * StateSet: `stateset1...` (45 chars) * Ethereum/Base: `0x...` (42 chars) * Solana: `base58...` (44 chars) 2. Use address validation: ```javascript theme={null} const isValid = stateset.utils.validateAddress( address, 'stateset' // or 'ethereum', 'solana' ); ``` 3. Check for typos or extra spaces **Problem**: Transaction blocked due to KYC requirements **Solutions:** 1. Complete KYC verification: ```javascript theme={null} const kycUrl = await stateset.compliance.getKYCUrl({ redirect_url: 'https://yourapp.com/kyc-complete' }); window.location.href = kycUrl; ``` 2. Check KYC status: ```javascript theme={null} const status = await stateset.compliance.getKYCStatus(); console.log('KYC Status:', status); // pending, approved, rejected ``` 3. For business accounts, ensure all beneficial owners are verified **Problem**: Too many API requests **Solutions:** 1. Check rate limit headers: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1640995200 ``` 2. Implement exponential backoff: ```javascript theme={null} async function retryWithBackoff(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (error.code === 'rate_limit' && i < maxRetries - 1) { await sleep(Math.pow(2, i) * 1000); } else { throw error; } } } } ``` 3. Use batch operations when possible 4. Upgrade to higher tier for increased limits **Problem**: Transaction blocked for compliance reasons **Solutions:** 1. Check transaction details for flags: ```javascript theme={null} const screening = await stateset.compliance.getScreening(transactionId); console.log('Risk factors:', screening.risk_factors); ``` 2. Common causes: * Sanctioned entity involvement * Unusual transaction pattern * Missing Travel Rule info (> \$3,000) * Exceeding velocity limits 3. Contact compliance team: * Email: [compliance@stateset.com](mailto:compliance@stateset.com) * Include transaction ID and context ### Integration Issues **Problem**: Webhook endpoint not receiving events **Solutions:** 1. Verify webhook signature: ```javascript theme={null} const isValid = stateset.webhooks.verifySignature( payload, headers['x-stateset-signature'], webhookSecret ); ``` 2. Check webhook status: ```javascript theme={null} const webhooks = await stateset.webhooks.list(); webhooks.forEach(w => { console.log(`${w.url}: ${w.status}, last error: ${w.last_error}`); }); ``` 3. Common issues: * Firewall blocking StateSet IPs * SSL certificate problems * Timeout (must respond in 20s) * Wrong content-type (expects JSON) **Problem**: Balance appears incorrect or not updating **Solutions:** 1. Check if including pending transactions: ```javascript theme={null} const balance = await stateset.stablecoin.balance({ address: yourAddress, include_pending: true, chains: ['stateset', 'base', 'solana'] // Check all chains }); ``` 2. Subscribe to real-time updates: ```javascript theme={null} const ws = stateset.subscriptions.connect(); ws.subscribe('balance.updated', (event) => { console.log('New balance:', event.balance); }); ``` 3. Clear cache if using one 4. Verify transaction actually completed on-chain ## 🎯 Best Practices ### Security * Never expose secret keys in client code * Use environment variables * Rotate keys regularly * Use restricted keys with minimal permissions * Always verify recipient addresses * Use idempotency keys for retries * Implement transaction limits * Monitor for unusual patterns ### Performance * Use batch operations when possible * Implement caching for read operations * Use webhooks instead of polling * Parallelize independent operations * Implement proper retry logic * Log all errors with context * Have fallback mechanisms * Monitor error rates ## 🆘 Getting Help ### Support Channels Real-time help from community and team Report bugs and request features For sensitive or account-specific issues ### Emergency Contacts * **Compliance Issues**: [compliance@stateset.com](mailto:compliance@stateset.com) * **Security Issues**: [security@stateset.com](mailto:security@stateset.com) (PGP available) * **API Emergencies**: +1-888-STATESET (24/7) ### Debug Information When contacting support, include: ```javascript theme={null} const debugInfo = { sdk_version: stateset.version, api_endpoint: stateset.apiEndpoint, timestamp: new Date().toISOString(), request_id: response.headers['x-request-id'], error_code: error.code, error_message: error.message, stack_trace: error.stack }; ``` ## 📚 Additional Resources Step-by-step video guides Full example applications Real-time system status Updates and best practices # ssUSD Integration Guide Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/integration-guide Complete guide to integrating StateSet USD into your application # ssUSD Integration Guide This guide walks you through integrating StateSet USD (ssUSD) into your application, from basic setup to advanced features. ## 🚀 Quick Start ### 1. Get Your API Keys Sign up at [dashboard.stateset.com](https://dashboard.stateset.com) Submit required documents for compliance (takes \~5 minutes) Navigate to Settings → API Keys → Create New Key ### 2. Install SDK ```bash npm theme={null} npm install @stateset/sdk ``` ```bash yarn theme={null} yarn add @stateset/sdk ``` ```bash pip theme={null} pip install stateset ``` ### 3. Initialize Client ```javascript theme={null} import { StateSet } from '@stateset/sdk'; const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY, network: 'mainnet' // or 'testnet' for development }); // Test connection const balance = await stateset.stablecoin.balance({ address: 'your_wallet_address' }); console.log('ssUSD Balance:', balance.amount); ``` ## 💳 Common Use Cases ### E-Commerce Payments Accept ssUSD payments with instant settlement and no chargebacks: ```javascript theme={null} // Create payment request async function createPayment(amount, orderId) { const payment = await stateset.payments.create({ amount: amount, currency: 'ssusd', metadata: { order_id: orderId, customer_email: 'customer@example.com' }, webhook_url: 'https://yoursite.com/webhooks/payment' }); return payment.payment_address; } // Verify payment received async function verifyPayment(paymentId) { const payment = await stateset.payments.get(paymentId); if (payment.status === 'completed') { // Process order fulfillment await fulfillOrder(payment.metadata.order_id); } } ``` ### Payroll & Disbursements Send bulk payments efficiently: ```javascript theme={null} // Batch payroll payments async function processPayroll(employees) { const transfers = employees.map(emp => ({ to: emp.wallet_address, amount: emp.salary_ssusd, memo: `Payroll ${new Date().toISOString().slice(0, 7)}` })); const batch = await stateset.stablecoin.batchTransfer({ transfers, idempotency_key: `payroll_${Date.now()}` }); // Send notifications for (const result of batch.results) { if (result.success) { await notifyEmployee(result.to, result.transaction_hash); } } return batch; } ``` ### Treasury Management Hold and manage corporate ssUSD reserves: ```javascript theme={null} // Corporate treasury dashboard class TreasuryManager { async getOverview() { const [balance, reserves, transactions] = await Promise.all([ stateset.stablecoin.balance({ address: this.treasuryAddress }), stateset.stablecoin.reserves(), stateset.stablecoin.transactions({ address: this.treasuryAddress, limit: 100 }) ]); return { current_balance: balance.amount, reserve_backing: reserves.total_usd, recent_activity: transactions, health_score: this.calculateHealthScore(balance, transactions) }; } async optimizeYield(amount) { // Check available yield opportunities const opportunities = await stateset.finance.yieldOpportunities({ asset: 'ssusd', amount: amount, risk_level: 'low' }); // Deploy to best opportunity if (opportunities[0].apy > 0.03) { // 3% APY threshold return await stateset.finance.deployCapital({ opportunity_id: opportunities[0].id, amount: amount }); } } } ``` ## 🔐 Security Best Practices ### API Key Management Never expose your secret API key in client-side code or public repositories! ```javascript theme={null} // ❌ WRONG - Never do this const stateset = new StateSet({ apiKey: 'sk_live_your_actual_key_here' // Hardcoded key (never do this) }); // ✅ CORRECT - Use environment variables const stateset = new StateSet({ apiKey: process.env.STATESET_API_KEY }); // ✅ CORRECT - Use restricted keys for client-side const publicClient = new StateSet({ apiKey: process.env.STATESET_PUBLIC_KEY // pk_ prefix }); ``` ### Transaction Security Implement proper validation and limits: ```javascript theme={null} class SecureTransferService { constructor() { this.dailyLimit = 100000; // $100k daily limit this.perTxLimit = 10000; // $10k per transaction } async transfer(to, amount, memo) { // Validate amount if (amount > this.perTxLimit) { throw new Error('Transaction exceeds limit'); } // Check daily volume const dailyVolume = await this.getDailyVolume(); if (dailyVolume + amount > this.dailyLimit) { throw new Error('Daily limit exceeded'); } // Validate recipient if (!this.isValidAddress(to)) { throw new Error('Invalid recipient address'); } // Execute with idempotency return await stateset.stablecoin.transfer({ to, amount, memo, idempotency_key: `transfer_${Date.now()}_${to}` }); } } ``` ## 📊 Monitoring & Analytics ### Real-Time Balance Monitoring ```javascript theme={null} // WebSocket subscription for balance updates const ws = stateset.subscriptions.connect(); ws.subscribe('balance.updated', async (event) => { console.log('New balance:', event.balance); // Alert on large changes if (Math.abs(event.change) > 10000) { await sendAlert({ type: 'large_balance_change', amount: event.change, new_balance: event.balance }); } }); // Historical balance tracking async function getBalanceHistory(days = 30) { const history = []; const now = Date.now(); for (let i = 0; i < days; i++) { const timestamp = now - (i * 24 * 60 * 60 * 1000); const balance = await stateset.stablecoin.balance({ address: treasuryAddress, at_timestamp: timestamp }); history.push({ date: new Date(timestamp).toISOString().slice(0, 10), balance: balance.amount }); } return history; } ``` ### Transaction Analytics ```javascript theme={null} // Analyze transaction patterns async function analyzeTransactions(address, period = '30d') { const transactions = await stateset.stablecoin.transactions({ address, period, limit: 1000 }); const analytics = { total_volume: 0, transaction_count: transactions.length, average_size: 0, largest_transaction: 0, counterparties: new Set(), daily_pattern: {} }; transactions.forEach(tx => { analytics.total_volume += tx.amount; analytics.largest_transaction = Math.max( analytics.largest_transaction, tx.amount ); analytics.counterparties.add( tx.from === address ? tx.to : tx.from ); const date = new Date(tx.timestamp).toISOString().slice(0, 10); analytics.daily_pattern[date] = (analytics.daily_pattern[date] || 0) + tx.amount; }); analytics.average_size = analytics.total_volume / analytics.transaction_count; analytics.unique_counterparties = analytics.counterparties.size; return analytics; } ``` ## 🌐 Multi-Chain Integration ### Bridge to Other Chains ```javascript theme={null} // Bridge ssUSD to Base async function bridgeToBase(amount) { const bridge = await stateset.bridge.create({ from_chain: 'stateset', to_chain: 'base', asset: 'ssusd', amount: amount, recipient: baseAddress }); // Monitor bridge progress const status = await stateset.bridge.track(bridge.id); console.log('Bridge status:', status); return bridge; } // Cross-chain balance aggregation async function getTotalBalance(addresses) { const balances = await Promise.all([ stateset.stablecoin.balance({ address: addresses.stateset, chain: 'stateset' }), stateset.stablecoin.balance({ address: addresses.base, chain: 'base' }), stateset.stablecoin.balance({ address: addresses.solana, chain: 'solana' }) ]); return balances.reduce((sum, b) => sum + b.amount, 0); } ``` ## 🧪 Testing ### Test Mode Use test mode for development: ```javascript theme={null} const testClient = new StateSet({ apiKey: process.env.STATESET_TEST_KEY, network: 'testnet' }); // Get test ssUSD async function getTestFunds() { const faucet = await testClient.faucet.request({ asset: 'ssusd', amount: 10000, // $10k test ssUSD address: testAddress }); return faucet; } ``` ### Integration Tests ```javascript theme={null} describe('ssUSD Integration', () => { it('should transfer funds successfully', async () => { const initialBalance = await getBalance(senderAddress); const transfer = await stateset.stablecoin.transfer({ to: recipientAddress, amount: '100.00' }); expect(transfer.status).toBe('completed'); const finalBalance = await getBalance(senderAddress); expect(finalBalance).toBe(initialBalance - 100); }); it('should handle insufficient funds', async () => { await expect( stateset.stablecoin.transfer({ to: recipientAddress, amount: '1000000.00' // More than balance }) ).rejects.toThrow('Insufficient funds'); }); }); ``` ## 🚨 Error Handling ### Common Errors and Solutions ```javascript theme={null} try { const transfer = await stateset.stablecoin.transfer({...}); } catch (error) { switch(error.code) { case 'insufficient_funds': // Handle low balance console.error('Not enough ssUSD'); break; case 'invalid_address': // Handle bad recipient console.error('Check recipient address format'); break; case 'compliance_block': // Handle compliance issues console.error('Transaction blocked for compliance'); await handleComplianceBlock(error.details); break; case 'rate_limit': // Handle rate limiting console.error('Too many requests'); await sleep(error.retry_after * 1000); break; default: console.error('Unknown error:', error); } } ``` ## 📚 Next Steps Complete API documentation Sample applications Real-time event handling Get help from our team # Issue ssUSD Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/issue POST https://api.stateset.com/v1/stablecoin/issue Mint new StateSet USD (ssUSD) stablecoins upon receipt of USD reserves **Issuer Access Only**: This endpoint requires verified issuer status under the GENIUS Act. Contact [sales@stateset.com](mailto:sales@stateset.com) for issuer onboarding. ## Overview The issue endpoint allows authorized entities to mint new ssUSD tokens when USD funds are received and verified. Every ssUSD issued is backed 1:1 by USD reserves held in segregated accounts. ### Key Requirements Must be approved as a Federal Qualified Nonbank Payment Stablecoin Issuer All issuances require completed KYC and passed AML checks USD funds must be received and verified before issuance API key must have `stablecoin:issue` scope ## Authentication ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/stablecoin/issue \ -H "Authorization: Bearer sk_live_issuer_..." \ -H "X-Issuer-Certificate: cert_..." ``` ```javascript Node.js theme={null} const headers = { 'Authorization': 'Bearer sk_live_issuer_...', 'X-Issuer-Certificate': 'cert_...' }; ``` ### Required Headers | Header | Description | | ---------------------- | ---------------------------------------------- | | `Authorization` | Bearer token with issuer permissions | | `X-Issuer-Certificate` | Issuer certificate for additional verification | ## Request Parameters The StateSet address to receive the issued ssUSD **Format**: `stateset1` followed by 39 characters **Example**: `stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu` Amount of ssUSD to issue in standard units (not micro units) **Format**: Decimal string with up to 2 decimal places **Examples**: * `"1000.00"` - Issue 1,000 ssUSD * `"50000.50"` - Issue 50,000.50 ssUSD **Limits**: * Minimum: \$100.00 * Maximum: \$10,000,000.00 per transaction Unique identifier for this issuance. Used for idempotency. **Format**: Any unique string up to 64 characters **Example**: `"ISS-2024-001234"` Reusing a reference\_id will return the original transaction instead of creating a new one. Details about the USD funds backing this issuance How the USD was received **Options**: * `bank_wire` - Fedwire transfer * `ach` - ACH transfer * `swift` - International SWIFT wire * `check` - Cashier's check Reference number from the payment system **Examples**: * Wire: `"FEDREF20240115ABC123"` * ACH: `"ACH-TRACE-123456"` * SWIFT: `"SWIFT-MT103-REF"` USD amount received (must match issuance amount) Name of the bank/institution that sent the funds ISO 8601 timestamp when funds were received Whether the funds have been verified by operations team Compliance verification details KYC verification status **Options**: `verified`, `pending`, `rejected` KYC provider used **Options**: `jumio`, `onfido`, `trulioo` KYC verification ID from provider AML screening status **Options**: `clear`, `pending_review`, `flagged` AML provider used **Options**: `chainalysis`, `elliptic`, `coinfirm` Recipient's jurisdiction (ISO 3166-1 alpha-2) **Example**: `"US"`, `"GB"`, `"CA"` Whether OFAC/sanctions screening passed Purpose code for the issuance **Options**: * `general` - General business operations * `merchant_settlement` - E-commerce merchant payouts * `payroll` - Employee salary payments * `vendor_payment` - B2B vendor payments * `treasury` - Corporate treasury operations Additional metadata for record keeping **Example**: ```json theme={null} { "customer_id": "cust_123", "internal_ref": "MINT-2024-001", "notes": "Monthly merchant settlement" } ``` ## Response The issuance details Unique issuance identifier **Example**: `"iss_1a2b3c4d5e6f7g8h"` Current status of the issuance **Values**: `pending`, `processing`, `completed`, `failed` The address that received ssUSD Amount details Amount in ssUSD Always `"ssusd"` USD equivalent (always matches value for ssUSD) Your provided reference ID ISO 8601 creation timestamp Blockchain transaction details Transaction hash on StateSet **Example**: `"B5E7A2D9F3C8E1A4D6B9C3F7E2A5D8B1E4C7F9A2"` Block number containing the transaction Gas consumed by the transaction Link to view on block explorer Reserve balance update details New total ssUSD supply Total USD reserves after update Should always be "1.0000" or higher ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/stablecoin/issue \ -H "Authorization: Bearer sk_live_issuer_..." \ -H "X-Issuer-Certificate: cert_..." \ -H "Content-Type: application/json" \ -d '{ "recipient": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": "50000.00", "reference_id": "ISS-2024-001234", "source_funds": { "type": "bank_wire", "reference": "FEDREF20240115ABC123", "amount_usd": "50000.00", "sending_institution": "Chase Bank", "received_at": "2024-01-15T09:30:00Z", "verified": true }, "compliance": { "kyc_status": "verified", "kyc_provider": "jumio", "kyc_id": "KYC-ABC-123456", "aml_status": "clear", "aml_provider": "chainalysis", "jurisdiction": "US", "sanctions_check": true }, "purpose": "merchant_settlement", "metadata": { "customer_id": "cust_123456", "batch": "SETTLE-2024-01-15" } }' ``` ```javascript Node.js theme={null} import { StateSet } from '@stateset/sdk'; const stateset = new StateSet({ apiKey: process.env.STATESET_ISSUER_KEY, issuerCert: process.env.ISSUER_CERTIFICATE }); async function issueSSUSD() { try { const issuance = await stateset.stablecoin.issue({ recipient: 'stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu', amount: '50000.00', reference_id: 'ISS-2024-001234', source_funds: { type: 'bank_wire', reference: 'FEDREF20240115ABC123', amount_usd: '50000.00', sending_institution: 'Chase Bank', received_at: '2024-01-15T09:30:00Z', verified: true }, compliance: { kyc_status: 'verified', kyc_provider: 'jumio', kyc_id: 'KYC-ABC-123456', aml_status: 'clear', aml_provider: 'chainalysis', jurisdiction: 'US', sanctions_check: true }, purpose: 'merchant_settlement', metadata: { customer_id: 'cust_123456', batch: 'SETTLE-2024-01-15' } }); console.log('Issuance completed:', issuance.id); console.log('Transaction hash:', issuance.transaction.hash); console.log('New total supply:', issuance.reserve_update.total_supply); } catch (error) { console.error('Issuance failed:', error.message); if (error.code === 'insufficient_reserve_verification') { console.error('USD funds not verified. Check with operations team.'); } } } ``` ```python Python theme={null} from stateset import StateSet from datetime import datetime stateset = StateSet( api_key=os.getenv('STATESET_ISSUER_KEY'), issuer_cert=os.getenv('ISSUER_CERTIFICATE') ) def issue_ssusd(): try: issuance = stateset.stablecoin.issue( recipient='stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu', amount='50000.00', reference_id='ISS-2024-001234', source_funds={ 'type': 'bank_wire', 'reference': 'FEDREF20240115ABC123', 'amount_usd': '50000.00', 'sending_institution': 'Chase Bank', 'received_at': '2024-01-15T09:30:00Z', 'verified': True }, compliance={ 'kyc_status': 'verified', 'kyc_provider': 'jumio', 'kyc_id': 'KYC-ABC-123456', 'aml_status': 'clear', 'aml_provider': 'chainalysis', 'jurisdiction': 'US', 'sanctions_check': True }, purpose='merchant_settlement', metadata={ 'customer_id': 'cust_123456', 'batch': 'SETTLE-2024-01-15' } ) print(f'Issuance completed: {issuance.id}') print(f'Transaction hash: {issuance.transaction.hash}') print(f'New total supply: {issuance.reserve_update.total_supply}') except Exception as e: print(f'Issuance failed: {str(e)}') ``` ```json Success Response theme={null} { "issuance": { "id": "iss_1a2b3c4d5e6f7g8h", "status": "completed", "recipient": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "value": "50000.00", "denom": "ssusd", "usd_value": "50000.00" }, "reference_id": "ISS-2024-001234", "created_at": "2024-01-15T10:30:05Z" }, "transaction": { "hash": "B5E7A2D9F3C8E1A4D6B9C3F7E2A5D8B1E4C7F9A2", "block_height": 1234567, "gas_used": "125000", "explorer_url": "https://explorer.stateset.com/tx/B5E7A2D9F3C8E1A4D6B9C3F7E2A5D8B1E4C7F9A2" }, "reserve_update": { "total_supply": "125000000.00", "total_reserves": "125500000.00", "reserve_ratio": "1.0040" } } ``` ```json Error Response theme={null} { "error": { "type": "invalid_request_error", "code": "insufficient_reserve_verification", "message": "Source funds have not been verified. Please contact operations team.", "param": "source_funds.verified", "details": { "wire_reference": "FEDREF20240115ABC123", "expected_amount": "50000.00", "verification_status": "pending" } } } ``` ## Error Codes | Code | Description | Resolution | | ----------------------------------- | --------------------------------- | ----------------------------------- | | `unauthorized_issuer` | Not authorized to issue ssUSD | Contact sales for issuer onboarding | | `insufficient_permissions` | API key lacks issue permissions | Use an issuer API key | | `duplicate_reference` | Reference ID already used | Use a unique reference ID | | `insufficient_reserve_verification` | USD funds not verified | Wait for operations to verify wire | | `compliance_check_failed` | KYC/AML check failed | Resolve compliance issues | | `invalid_recipient` | Invalid StateSet address | Check address format | | `amount_mismatch` | Source funds don't match issuance | Ensure amounts match exactly | | `rate_limit_exceeded` | Too many requests | Implement exponential backoff | ## Compliance & Regulations All issuances must comply with GENIUS Act requirements. Failure to maintain proper reserves or accurate reporting may result in criminal penalties. ### Monthly Attestation Impact Each issuance updates the reserve balance that must be attested monthly: * Increases total ssUSD supply * Must be backed by verified USD reserves * Included in monthly CPA audit * Subject to regulatory review ### Record Keeping All issuance records are maintained for 7 years including: * Source fund documentation * KYC/AML verification records * Transaction details * Reserve balance updates ## Best Practices Always ensure USD funds are received and verified before attempting issuance. The API will reject issuances without verified backing funds. Always provide a unique `reference_id`. This prevents accidental duplicate issuances and allows safe retries. After each issuance, verify the `reserve_ratio` remains at or above 1.0000. This ensures full backing. Set up webhooks to receive real-time notifications about issuance status, especially for large amounts. ## Related Endpoints Burn ssUSD and withdraw USD reserves Check current reserve composition Transfer between addresses View monthly reserve reports # StateSet USD (ssUSD) API Overview Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/overview Complete API reference for StateSet USD stablecoin - GENIUS Act compliant stablecoin for instant global commerce **Quick Access**: [Issue ssUSD](/stablecoin/issue) | [Redeem for USD](/stablecoin/redeem) | [Check Reserves](/stablecoin/reserves) | [View Attestations](/stablecoin/attestation) ## 🪙 What is StateSet USD (ssUSD)? StateSet USD (ssUSD) will be a fully-backed, regulatory-compliant stablecoin designed for instant global commerce. ssUSD combines the stability of the US dollar with the efficiency of blockchain technology. Every ssUSD is backed by \$1 in secure, audited reserves Sub-second finality on StateSet, instant bridging to other chains GENIUS Act compliance with monthly attestations and criminal penalties for misreporting ## 💰 Reserve Composition Our conservative reserve structure ensures ssUSD stability and liquidity:
Asset Type Allocation Description Risk Level
U.S. Dollar Cash 10% FDIC-insured deposits at regulated banks Minimal
Treasury Bills 70% U.S. T-Bills with ≤93 days maturity Minimal
Government MMFs 15% Government-only money market funds Minimal
Overnight Repos 5% Tri-party repo agreements Low
## 🔑 Key Features * **Monthly Attestations**: CPA-signed reserve reports published on-chain * **Criminal Penalties**: C-suite officers face criminal liability for misreporting * **Segregated Accounts**: Customer assets held separately from corporate funds * **Native on StateSet**: Instant, low-cost transactions * **Base Integration**: Bridge to Coinbase's L2 network * **Solana Support**: High-speed DeFi integration * **Cosmos IBC**: Connect to 50+ IBC-enabled chains * **Bulk Operations**: Issue/redeem millions in a single transaction * **Automated Compliance**: Built-in KYC/AML checks * **Audit Trail**: Complete transaction history and reporting * **White-Label API**: Custom branding for partners ## 📊 API Capabilities ### Core Operations Mint new ssUSD tokens upon receipt of USD. Requires issuer permissions. ```bash theme={null} POST /v1/stablecoin/issue ``` Burn ssUSD and receive USD via ACH/wire. T+1 settlement. ```bash theme={null} POST /v1/stablecoin/redeem ``` Send ssUSD between addresses. Supports single and batch transfers. ```bash theme={null} POST /v1/stablecoin/transfer ``` Query ssUSD balance for any address across all supported chains. ```bash theme={null} GET /v1/stablecoin/balance/{address} ``` ### Analytics & Compliance Real-time reserve composition and historical data ```bash theme={null} GET /v1/stablecoin/reserves ``` Access monthly CPA-signed reserve reports ```bash theme={null} GET /v1/stablecoin/attestations ``` Query transaction history with advanced filtering ```bash theme={null} GET /v1/stablecoin/transactions ``` Supply metrics, velocity, and usage statistics ```bash theme={null} GET /v1/stablecoin/analytics ``` ## 🚀 Quick Start Example ```javascript Node.js theme={null} import { StateSet } from '@stateset/sdk'; const stateset = new StateSet({ apiKey: 'sk_test_...' }); // Check ssUSD balance const balance = await stateset.stablecoin.balance({ address: 'stateset1abc...' }); // Transfer ssUSD const transfer = await stateset.stablecoin.transfer({ to: 'stateset1xyz...', amount: '100.00', memo: 'Payment for invoice #123' }); // View current reserves const reserves = await stateset.stablecoin.reserves(); console.log(`Total reserves: $${reserves.total_usd}`); ``` ```python Python theme={null} from stateset import StateSet stateset = StateSet(api_key='sk_test_...') # Check ssUSD balance balance = stateset.stablecoin.balance( address='stateset1abc...' ) # Transfer ssUSD transfer = stateset.stablecoin.transfer( to='stateset1xyz...', amount='100.00', memo='Payment for invoice #123' ) # View current reserves reserves = stateset.stablecoin.reserves() print(f"Total reserves: ${reserves['total_usd']}") ``` ```bash cURL theme={null} # Check balance curl https://api.stateset.com/v1/stablecoin/balance/stateset1abc... \ -H "Authorization: Bearer sk_test_..." # Transfer ssUSD curl -X POST https://api.stateset.com/v1/stablecoin/transfer \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "to": "stateset1xyz...", "amount": "100.00", "memo": "Payment for invoice #123" }' ``` ## 💡 Use Cases ### Online Payments * Accept ssUSD for instant settlement * No chargebacks or payment reversals * Lower fees than credit cards * Global reach without currency conversion ```javascript theme={null} // Accept payment const payment = await stateset.payments.create({ amount: 99.99, currency: 'ssusd', description: 'Premium subscription' }); ``` ### Instant Payroll * Pay employees instantly in ssUSD * Automated tax withholding * Multi-currency support * Detailed payment records ```javascript theme={null} // Batch payroll const payroll = await stateset.stablecoin.batchTransfer({ transfers: employees.map(emp => ({ to: emp.address, amount: emp.salary, memo: `Payroll ${month}` })) }); ``` ### Corporate Treasury * Hold reserves in stable, liquid assets * Earn yield on idle balances * Instant liquidity when needed * Full audit trail ```javascript theme={null} // Check reserves and yield const treasury = await stateset.stablecoin.treasuryStats({ address: 'corporate_wallet' }); ``` ## 🔒 Security & Compliance All ssUSD operations require proper authentication and may be subject to compliance checks based on amount and jurisdiction. ### Security Features * **Multi-signature wallets** for large transactions * **Hardware security module (HSM)** key storage * **Rate limiting** and fraud detection * **Webhook signatures** for secure notifications ### Compliance Requirements * **KYC/AML** verification for issuance/redemption * **Transaction monitoring** for suspicious activity * **Sanctions screening** via Chainalysis * **Tax reporting** (1099 forms for US entities) ## 📈 Performance

\< 1 second

Transaction finality

10,000+ TPS

Network capacity

\$0.01

Average tx cost

## 🆘 Support & Resources Step-by-step guide to integrate ssUSD Sample code and reference implementations Real-time API status and uptime Enterprise support and custom solutions # Redeem Stablecoin Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/redeem POST https://api.stateset.com/v1/stablecoin/redeem Redeem stablecoins for fiat currency This endpoint allows verified users to redeem their stablecoins for fiat currency. Redemptions are subject to KYC/AML verification and minimum/maximum limits. ## Authentication This endpoint requires a valid API key with `stablecoin:redeem` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body The blockchain address holding the stablecoins to redeem Example: `stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu` The amount and denomination of stablecoins to redeem The denomination of the stablecoin (e.g., "ssusd") The amount to redeem in the smallest unit (e.g., "1000000" for 1 ssUSD with 6 decimals) Destination for the fiat funds Type of destination: "bank\_wire", "ach", "swift", "sepa" Destination account number Routing number (required for ACH) SWIFT/BIC code (required for SWIFT transfers) IBAN (required for SEPA transfers) Name of the receiving bank Name of the account holder Unique reference ID for this redemption transaction Compliance information Purpose of redemption Source of the stablecoins being redeemed Additional metadata for the redemption ## Response Unique identifier for the redemption transaction Object type, always "stablecoin\_redemption" The sender address The redeemed amount The denomination of the stablecoin The amount redeemed Human-readable amount (e.g., "1000.00 ssUSD") Equivalent fiat amount Fiat currency code (e.g., "USD") Blockchain transaction hash for the burn Status: "pending", "processing", "completed", "failed", "cancelled" Estimated arrival date for fiat funds Fee breakdown Blockchain network fee Processing fee Total fees ISO 8601 timestamp of creation ISO 8601 timestamp of completion ```json Example Request theme={null} { "sender": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "denom": "ssusd", "amount": "1000000000" }, "destination": { "type": "ach", "account_number": "123456789", "routing_number": "021000021", "bank_name": "JPMorgan Chase", "beneficiary_name": "John Doe" }, "reference_id": "RED-2024-001234", "compliance": { "purpose": "business_operations", "source_of_funds": "sales_revenue" } } ``` ```json Example Response theme={null} { "id": "red_9h8g7f6e5d4c3b2a", "object": "stablecoin_redemption", "sender": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "denom": "ssusd", "amount": "1000000000", "display_amount": "1000.00 ssUSD", "fiat_amount": "1000.00", "fiat_currency": "USD" }, "transaction_hash": "A7F4C1B8E5D2A9F7C3B1E8D5A2F9C7E1B4A7D2F5E8B1C4A7F9D2E5B8C1F4A7D2", "status": "processing", "estimated_arrival": "2024-01-17T16:00:00Z", "fees": { "network_fee": "0.50", "processing_fee": "5.00", "total_fee": "5.50" }, "created_at": "2024-01-15T10:45:00Z", "completed_at": null } ``` ## Error Codes | Code | Description | | ----- | ------------------------------------------------ | | `400` | Invalid request parameters | | `401` | Unauthorized - Invalid API key | | `403` | Forbidden - Account not verified for redemptions | | `404` | Sender address not found | | `409` | Conflict - Duplicate reference\_id | | `422` | Insufficient balance or invalid amount | | `429` | Rate limit exceeded | | `500` | Internal server error | ## Redemption Limits * **Minimum**: \$100 USD equivalent * **Maximum**: \$1,000,000 USD per transaction * **Daily Limit**: \$5,000,000 USD per account * **Monthly Limit**: Based on account tier ## Processing Times | Method | Estimated Time | | ------ | ------------------------- | | ACH | 1-3 business days | | Wire | Same day - 1 business day | | SWIFT | 1-5 business days | | SEPA | 1-2 business days | ## Webhooks Configure webhooks to receive real-time updates: ```json theme={null} { "event": "stablecoin.redeemed", "data": { "id": "red_9h8g7f6e5d4c3b2a", "status": "completed", "amount": { "denom": "ssusd", "amount": "1000000000" } } } ``` ## Code Examples ```javascript Node.js theme={null} const axios = require('axios'); async function redeemStablecoin() { try { const response = await axios.post( 'https://api.stateset.com/v1/stablecoin/redeem', { sender: 'stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu', amount: { denom: 'ssusd', amount: '1000000000' }, destination: { type: 'ach', account_number: '123456789', routing_number: '021000021', bank_name: 'JPMorgan Chase', beneficiary_name: 'John Doe' }, reference_id: 'RED-2024-001234', compliance: { purpose: 'business_operations', source_of_funds: 'sales_revenue' } }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); console.log('Redemption initiated:', response.data); } catch (error) { console.error('Redemption failed:', error.response.data); } } ``` ```python Python theme={null} import requests def redeem_stablecoin(): url = "https://api.stateset.com/v1/stablecoin/redeem" headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" } data = { "sender": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "denom": "ssusd", "amount": "1000000000" }, "destination": { "type": "ach", "account_number": "123456789", "routing_number": "021000021", "bank_name": "JPMorgan Chase", "beneficiary_name": "John Doe" }, "reference_id": "RED-2024-001234", "compliance": { "purpose": "business_operations", "source_of_funds": "sales_revenue" } } try: response = requests.post(url, json=data, headers=headers) response.raise_for_status() print("Redemption initiated:", response.json()) except requests.exceptions.RequestException as e: print("Redemption failed:", e) ``` ```curl cURL theme={null} curl -X POST https://api.stateset.com/v1/stablecoin/redeem \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sender": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "denom": "ssusd", "amount": "1000000000" }, "destination": { "type": "ach", "account_number": "123456789", "routing_number": "021000021", "bank_name": "JPMorgan Chase", "beneficiary_name": "John Doe" }, "reference_id": "RED-2024-001234" }' ``` # Get Stablecoin Reserves Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/reserves GET https://api.stateset.com/v1/stablecoin/reserves Retrieve real-time reserve composition and monthly attestation data for StateSet USD (ssUSD) This endpoint provides transparent access to ssUSD reserve data, including real-time composition and monthly attestations as required by the GENIUS Act of 2025. ## Authentication This endpoint is publicly accessible. Optional authentication provides additional data. ```bash theme={null} Authorization: Bearer YOUR_API_KEY (optional) ``` ## Query Parameters Specific attestation date (YYYY-MM-DD format) Default: Latest available attestation Include historical attestation data Default: `false` Response format: "summary", "detailed", "regulatory" Default: "summary" ## Response Latest monthly attestation data Attestation date Link to signed PDF attestation report CPA firm details Registered public accounting firm name CPA license number Date of auditor signature C-suite officer signatures Officer name Officer title (CEO, CFO, etc.) Date of signature Current reserve composition Total reserve value in USD ISO 8601 timestamp of last update Detailed breakdown by asset type U.S. Dollar bank deposits (10%) Total USD in bank accounts Percentage of total reserves List of custodian banks U.S. Treasury Bills (70%) Total value of T-Bills Percentage of total reserves Weighted average maturity (max 93 days) List of CUSIP identifiers Government-only Money Market Funds (15%) Total MMF holdings Percentage of total reserves List of fund names and tickers Overnight tri-party repos (5%) Total repo value Percentage of total reserves OCC-approved counterparties ssUSD supply metrics Total ssUSD in circulation Cumulative ssUSD issued Cumulative ssUSD redeemed Reserves / Supply ratio (should be >= 1.0) Supply breakdown by blockchain ssUSD on StateSet network ssUSD bridged to Base ssUSD bridged to Solana ssUSD on Cosmos chains via IBC Regulatory compliance status OCC approval details Approval status Date of OCC approval Federal license number Date of next required attestation Date of last quarterly audit ```json Example Response theme={null} { "attestation": { "date": "2025-07-31", "report_url": "https://reserves.stateset.com/attestations/2025-07-31.pdf", "auditor": { "name": "Ernst & Young LLP", "license_number": "CPA-123456", "signature_date": "2025-08-05" }, "officer_signatures": [ { "name": "John Smith", "title": "Chief Executive Officer", "signature_date": "2025-08-05" }, { "name": "Jane Doe", "title": "Chief Financial Officer", "signature_date": "2025-08-05" } ] }, "reserves": { "total_value_usd": "1,234,567,890.00", "last_updated": "2025-08-15T14:30:00Z", "composition": { "cash": { "amount": "123,456,789.00", "percentage": 10.0, "banks": [ { "name": "JPMorgan Chase Bank", "amount": "61,728,394.50" }, { "name": "Bank of New York Mellon", "amount": "61,728,394.50" } ] }, "treasury_bills": { "amount": "864,197,523.00", "percentage": 70.0, "average_maturity_days": 45, "cusips": [ "912796YG7", "912796YH5", "912796YJ1" ] }, "money_market_funds": { "amount": "185,185,183.50", "percentage": 15.0, "funds": [ { "name": "Vanguard Federal Money Market Fund", "ticker": "VMFXX", "amount": "92,592,591.75" }, { "name": "Fidelity Government Money Market Fund", "ticker": "SPAXX", "amount": "92,592,591.75" } ] }, "repo_agreements": { "amount": "61,728,394.50", "percentage": 5.0, "counterparties": [ "Federal Reserve Bank of New York", "Bank of New York Mellon" ] } } }, "supply": { "total_supply": "1,234,567,890.00", "total_issued": "1,500,000,000.00", "total_redeemed": "265,432,110.00", "reserve_ratio": 1.0, "chains": { "stateset": "500,000,000.00", "base": "400,000,000.00", "solana": "300,000,000.00", "cosmos_ibc": "34,567,890.00" } }, "compliance": { "occ_approval": { "status": "approved", "approval_date": "2025-07-04", "license_number": "OCC-NBPSI-2025-001" }, "next_attestation_due": "2025-08-31", "last_audit_date": "2025-07-15" } } ``` ## Rate Limits Public access: 100 requests per minute Authenticated: 1,000 requests per minute ## Code Examples ```javascript Node.js theme={null} const axios = require('axios'); async function getReserveData() { try { const response = await axios.get( 'https://api.stateset.com/v1/stablecoin/reserves', { params: { format: 'detailed', include_history: true } } ); const data = response.data; console.log('Total Reserves: $' + data.reserves.total_value_usd); console.log('Total Supply: $' + data.supply.total_supply); console.log('Reserve Ratio:', data.supply.reserve_ratio); // Verify 1:1 backing if (data.supply.reserve_ratio >= 1.0) { console.log('✓ Fully backed'); } else { console.log('⚠ Under-collateralized'); } return data; } catch (error) { console.error('Failed to fetch reserve data:', error); } } ``` ```python Python theme={null} import requests def get_reserve_attestation(date=None): """Get reserve attestation data""" url = "https://api.stateset.com/v1/stablecoin/reserves" params = { "format": "regulatory" } if date: params["date"] = date response = requests.get(url, params=params) response.raise_for_status() data = response.json() # Display reserve composition print("StateSet USD (ssUSD) Reserve Report") print("=" * 40) print(f"Attestation Date: {data['attestation']['date']}") print(f"Total Reserves: ${data['reserves']['total_value_usd']}") print(f"Total Supply: ${data['supply']['total_supply']}") print(f"Reserve Ratio: {data['supply']['reserve_ratio']}") print("\nReserve Composition:") composition = data['reserves']['composition'] for asset_type, details in composition.items(): print(f" {asset_type.replace('_', ' ').title()}: " f"${details['amount']} ({details['percentage']}%)") return data # Get latest attestation get_reserve_attestation() # Get specific month get_reserve_attestation("2025-07-31") ``` # ssUSD Smart Contracts Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/smart-contracts Technical documentation for StateSet USD smart contracts and on-chain integration # ssUSD Smart Contracts StateSet USD (ssUSD) is implemented as a native Cosmos SDK module with CosmWasm smart contract interfaces for advanced functionality. ## 🏗️ Architecture Overview Core ssUSD logic implemented as Cosmos SDK module for maximum performance Smart contract layer for programmable features and DeFi integration ## 📋 Contract Addresses ### Mainnet | Contract | Address | Description | | ----------- | ---------------------- | ------------------- | | ssUSD Token | `stateset1ssusd...` | Main token contract | | Minter | `stateset1mint...` | Issuance controller | | Treasury | `stateset1treasury...` | Reserve management | | Bridge | `stateset1bridge...` | Cross-chain bridge | ### Testnet | Contract | Address | Description | | ----------- | ------------------------ | ----------------------- | | ssUSD Token | `stateset1test_ssusd...` | Test token contract | | Faucet | `stateset1faucet...` | Test token distribution | ## 🔧 Core Interfaces ### Token Contract ```rust theme={null} // Query ssUSD balance #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { Balance { address: String }, TotalSupply {}, TokenInfo {}, Allowance { owner: String, spender: String }, } // Execute token operations #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Transfer { recipient: String, amount: Uint128, }, TransferFrom { owner: String, recipient: String, amount: Uint128, }, Approve { spender: String, amount: Uint128, }, IncreaseAllowance { spender: String, amount: Uint128, }, DecreaseAllowance { spender: String, amount: Uint128, }, } ``` ### JavaScript Integration ```javascript theme={null} // Initialize contract interface const ssusdContract = new Contract( client, 'stateset1ssusd...', ssUSDContractABI ); // Query balance const balance = await ssusdContract.balance({ address: 'stateset1user...' }); // Transfer tokens const tx = await ssusdContract.transfer({ recipient: 'stateset1recipient...', amount: '1000000' // 1 ssUSD (6 decimals) }); ``` ## 💡 Common Patterns ### Programmatic Transfers ```javascript theme={null} // Batch transfer with memo async function batchTransfer(transfers) { const messages = transfers.map(t => ({ contractAddress: SSUSD_CONTRACT, msg: { transfer: { recipient: t.recipient, amount: (t.amount * 1e6).toString() // Convert to uunits } } })); const tx = await client.signAndBroadcast( senderAddress, messages, 'auto', 'Batch payment' ); return tx; } ``` ### Allowance Management ```javascript theme={null} // Approve spending limit for DeFi protocol async function approveProtocol(protocol, amount) { const tx = await ssusdContract.approve({ spender: protocol, amount: (amount * 1e6).toString() }); // Monitor spending const allowance = await ssusdContract.allowance({ owner: myAddress, spender: protocol }); console.log(`Protocol can spend: ${allowance.allowance / 1e6} ssUSD`); } ``` ### Event Monitoring ```javascript theme={null} // Subscribe to transfer events const subscription = await client.subscribeTx({ "message.action": "/stateset.ssusd.v1.MsgTransfer" }); subscription.on('data', (tx) => { const events = tx.events.filter(e => e.type === 'transfer'); events.forEach(event => { const from = event.attributes.find(a => a.key === 'from').value; const to = event.attributes.find(a => a.key === 'to').value; const amount = event.attributes.find(a => a.key === 'amount').value; console.log(`Transfer: ${from} → ${to}: ${amount}`); }); }); ``` ## 🔐 Security Features ### Multi-Signature Support ```javascript theme={null} // Create multi-sig transfer const multiSigMsg = { transfer: { recipient: 'stateset1recipient...', amount: '1000000000' // 1000 ssUSD } }; // Requires 2 of 3 signatures const signatures = await Promise.all([ signer1.sign(multiSigMsg), signer2.sign(multiSigMsg) ]); const tx = await client.broadcastMultisig( multiSigAddress, multiSigMsg, signatures ); ``` ### Rate Limiting ```rust theme={null} // Contract-level rate limiting pub fn execute_transfer( deps: DepsMut, env: Env, info: MessageInfo, recipient: String, amount: Uint128, ) -> Result { // Check rate limit let daily_limit = DAILY_LIMITS.load(deps.storage, &info.sender)?; let current_usage = DAILY_USAGE.load(deps.storage, &info.sender)?; if current_usage + amount > daily_limit { return Err(ContractError::DailyLimitExceeded {}); } // Execute transfer // ... } ``` ## 🌉 Cross-Chain Bridge ### Bridge to Ethereum/Base ```javascript theme={null} // Initiate bridge transfer const bridgeTx = await bridgeContract.bridgeOut({ destination_chain: 'ethereum', recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f6E321', amount: '1000000000', // 1000 ssUSD memo: 'Bridge to Ethereum' }); // Monitor bridge status const status = await bridgeContract.getBridgeStatus({ tx_hash: bridgeTx.transactionHash }); console.log(`Bridge status: ${status.status}`); console.log(`Ethereum tx: ${status.destination_tx_hash}`); ``` ## 🏭 DeFi Integration ### Liquidity Pool Integration ```javascript theme={null} // Add liquidity to ssUSD/ATOM pool const poolContract = new Contract(client, POOL_ADDRESS, poolABI); const provideLiquidity = await poolContract.provideLiquidity({ assets: [ { info: { token: { contract_addr: SSUSD_CONTRACT }}, amount: '1000000000' // 1000 ssUSD }, { info: { native_token: { denom: 'uatom' }}, amount: '50000000' // 50 ATOM } ], slippage_tolerance: '0.01' // 1% }); ``` ### Yield Farming ```javascript theme={null} // Stake LP tokens const farmContract = new Contract(client, FARM_ADDRESS, farmABI); const stake = await farmContract.stake({ amount: lpTokenAmount }); // Check rewards const rewards = await farmContract.pendingRewards({ address: myAddress }); console.log(`Pending rewards: ${rewards.amount} STATE`); ``` ## 📝 Contract Deployment ### Deploy Custom Contract ```javascript theme={null} // Deploy contract that uses ssUSD const wasmCode = fs.readFileSync('./my_contract.wasm'); const uploadResult = await client.upload( senderAddress, wasmCode, 'auto' ); const instantiateResult = await client.instantiate( senderAddress, uploadResult.codeId, { ssusd_contract: SSUSD_CONTRACT, admin: senderAddress }, 'My ssUSD Contract', 'auto' ); console.log(`Contract deployed at: ${instantiateResult.contractAddress}`); ``` ## 🧪 Testing ### Unit Tests ```rust theme={null} #[cfg(test)] mod tests { use super::*; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; #[test] fn test_transfer() { let mut deps = mock_dependencies(); let env = mock_env(); // Initialize contract let msg = InstantiateMsg { name: "StateSet USD".to_string(), symbol: "ssUSD".to_string(), decimals: 6, }; let info = mock_info("creator", &[]); instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); // Test transfer let transfer_msg = ExecuteMsg::Transfer { recipient: "recipient".to_string(), amount: Uint128::new(1000000), }; let info = mock_info("sender", &[]); let res = execute(deps.as_mut(), env, info, transfer_msg).unwrap(); assert_eq!(res.messages.len(), 0); } } ``` ### Integration Tests ```javascript theme={null} describe('ssUSD Contract', () => { let client; let ssusdContract; beforeAll(async () => { client = await SigningCosmWasmClient.connect(RPC_ENDPOINT); ssusdContract = new Contract(client, SSUSD_CONTRACT, abi); }); test('should transfer tokens', async () => { const beforeBalance = await ssusdContract.balance({ address: recipient }); await ssusdContract.transfer({ recipient, amount: '1000000' }); const afterBalance = await ssusdContract.balance({ address: recipient }); expect(afterBalance.balance).toBe( (parseInt(beforeBalance.balance) + 1000000).toString() ); }); }); ``` ## 📚 Resources View contract source code Complete ABI documentation Sample integrations Contract audit reports # List Stablecoin Transactions Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/transactions GET https://api.stateset.com/v1/stablecoin/transactions Retrieve stablecoin transaction history with filtering and pagination This endpoint provides a comprehensive view of stablecoin transactions including issuances, redemptions, transfers, and burns. ## Authentication This endpoint requires a valid API key with `stablecoin:read` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Query Parameters Filter transactions by address (as sender or recipient) Filter by transaction type: "issue", "redeem", "transfer", "burn" Filter by status: "pending", "confirmed", "failed" Filter by stablecoin denomination (e.g., "ssusd") Start date for transaction range (ISO 8601 format) End date for transaction range (ISO 8601 format) Minimum transaction amount (in smallest unit) Maximum transaction amount (in smallest unit) Number of results per page (max: 100, default: 20) Pagination offset Sort order: "asc" or "desc" (default: "desc") ## Response Array of transaction objects Unique transaction identifier Transaction type: "issue", "redeem", "transfer", "burn" Blockchain transaction hash Sender address (null for issuances) Recipient address (null for redemptions/burns) Transaction amount details Stablecoin denomination Amount in smallest unit Human-readable amount USD equivalent at time of transaction Fee details Blockchain network fee Processing fee (for issuance/redemption) Transaction status Block height of confirmation Transaction memo/note Additional transaction metadata ISO 8601 timestamp ISO 8601 timestamp of confirmation Pagination information Total number of transactions Results per page Current offset Whether more results are available ```json Example Response theme={null} { "transactions": [ { "id": "txn_abc123def456", "type": "transfer", "transaction_hash": "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0", "from": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "to": "stateset1abcdefghijklmnopqrstuvwxyz123456789012", "amount": { "denom": "ssusd", "amount": "500000000", "display_amount": "500.00 ssUSD", "usd_value": "500.00" }, "fees": { "network_fee": "0.01", "processing_fee": "0.00" }, "status": "confirmed", "block_height": 1234567, "memo": "Payment for invoice #INV-2024-001", "metadata": { "invoice_id": "inv_123456", "order_id": "ord_789012" }, "created_at": "2024-01-15T09:30:00Z", "confirmed_at": "2024-01-15T09:30:05Z" }, { "id": "txn_xyz789uvw012", "type": "issue", "transaction_hash": "B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1", "from": null, "to": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "amount": { "denom": "ssusd", "amount": "10000000000", "display_amount": "10,000.00 ssUSD", "usd_value": "10000.00" }, "fees": { "network_fee": "0.50", "processing_fee": "10.00" }, "status": "confirmed", "block_height": 1234500, "memo": "Merchant funding", "metadata": { "reference_id": "ISS-2024-001234", "source_type": "bank_wire" }, "created_at": "2024-01-14T14:20:00Z", "confirmed_at": "2024-01-14T14:20:10Z" } ], "pagination": { "total": 156, "limit": 20, "offset": 0, "has_more": true } } ``` ## Error Codes | Code | Description | | ----- | ------------------------------ | | `400` | Invalid query parameters | | `401` | Unauthorized - Invalid API key | | `429` | Rate limit exceeded | | `500` | Internal server error | ## Code Examples ```javascript Node.js theme={null} const axios = require('axios'); async function getTransactionHistory(params) { try { const response = await axios.get( 'https://api.stateset.com/v1/stablecoin/transactions', { params: { address: 'stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu', type: 'transfer', denom: 'ssusd', start_date: '2024-01-01T00:00:00Z', limit: 50, order: 'desc' }, headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); console.log(`Found ${response.data.pagination.total} transactions`); response.data.transactions.forEach(tx => { console.log(`${tx.type}: ${tx.amount.display_amount} - ${tx.status}`); }); return response.data; } catch (error) { console.error('Failed to get transactions:', error.response.data); } } ``` ```python Python theme={null} import requests from datetime import datetime, timedelta def get_transaction_history(): url = "https://api.stateset.com/v1/stablecoin/transactions" headers = { "Authorization": "Bearer YOUR_API_KEY" } # Get transactions from last 30 days end_date = datetime.utcnow() start_date = end_date - timedelta(days=30) params = { "address": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "start_date": start_date.isoformat() + "Z", "end_date": end_date.isoformat() + "Z", "limit": 100 } try: response = requests.get(url, headers=headers, params=params) response.raise_for_status() data = response.json() # Calculate totals by type totals = {} for tx in data['transactions']: tx_type = tx['type'] amount = float(tx['amount']['usd_value']) totals[tx_type] = totals.get(tx_type, 0) + amount print("Transaction Summary (Last 30 Days):") for tx_type, total in totals.items(): print(f"{tx_type.capitalize()}: ${total:,.2f}") return data except requests.exceptions.RequestException as e: print(f"Failed to get transactions: {e}") ``` ```curl cURL theme={null} curl -X GET "https://api.stateset.com/v1/stablecoin/transactions?address=stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu&type=transfer&limit=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` # Transfer Stablecoin Source: https://docs.stateset.com/stateset-commerce-api-reference/stablecoin/transfer POST https://api.stateset.com/v1/stablecoin/transfer Transfer stablecoins between addresses with optional batch support This endpoint enables instant stablecoin transfers between addresses on the StateSet network. Supports both single and batch transfers with atomic execution. ## Authentication This endpoint requires a valid API key with `stablecoin:transfer` permissions. ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Request Body ### Single Transfer The sender's blockchain address Example: `stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu` The recipient's blockchain address The transfer amount The stablecoin denomination (e.g., "ssusd") The amount in smallest unit (e.g., "1000000" for 1 ssUSD) ### Batch Transfer The sender's blockchain address for all transfers Array of transfer objects Recipient address Transfer amount (same structure as single transfer) Optional memo for this transfer ### Common Fields Optional memo for the transaction Transaction priority: "low", "medium", "high" (affects gas price) Default: "medium" Unique key to prevent duplicate transfers Additional metadata for the transfer ISO 8601 timestamp for scheduled transfers (future feature) ## Response Unique transfer identifier Object type: "transfer" or "batch\_transfer" Blockchain transaction hash Transfer status: "pending", "confirmed", "failed" Array of individual transfers (for batch transfers) Sender address Recipient address Transfer amount with display formatting Individual transfer status Total amount transferred (for batch) Fee breakdown Blockchain network fee Additional priority fee (if applicable) Total fees in USD Block height of confirmation ISO 8601 timestamp ISO 8601 timestamp of confirmation ```json Single Transfer Request theme={null} { "from": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "to": "stateset1abcdefghijklmnopqrstuvwxyz123456789012", "amount": { "denom": "ssusd", "amount": "500000000" }, "memo": "Payment for invoice #INV-2024-001", "priority": "high", "idempotency_key": "transfer_abc123", "metadata": { "invoice_id": "inv_123456", "order_id": "ord_789012" } } ``` ```json Batch Transfer Request theme={null} { "from": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "transfers": [ { "to": "stateset1abcdefghijklmnopqrstuvwxyz123456789012", "amount": { "denom": "ssusd", "amount": "250000000" }, "memo": "Vendor payment A" }, { "to": "stateset1zyxwvutsrqponmlkjihgfedcba987654321098", "amount": { "denom": "ssusd", "amount": "750000000" }, "memo": "Vendor payment B" } ], "memo": "Batch vendor payments - Jan 2024", "priority": "medium" } ``` ```json Example Response theme={null} { "id": "txf_batch_7h8g9f0e1d2c3b4a", "object": "batch_transfer", "transaction_hash": "C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2", "status": "confirmed", "transfers": [ { "from": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "to": "stateset1abcdefghijklmnopqrstuvwxyz123456789012", "amount": { "denom": "ssusd", "amount": "250000000", "display_amount": "250.00 ssUSD" }, "status": "confirmed" }, { "from": "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "to": "stateset1zyxwvutsrqponmlkjihgfedcba987654321098", "amount": { "denom": "ssusd", "amount": "750000000", "display_amount": "750.00 ssUSD" }, "status": "confirmed" } ], "total_amount": { "denom": "ssusd", "amount": "1000000000", "display_amount": "1,000.00 ssUSD" }, "fees": { "network_fee": "0.02", "priority_fee": "0.00", "total_fee": "0.02" }, "block_height": 1234568, "created_at": "2024-01-15T11:00:00Z", "confirmed_at": "2024-01-15T11:00:03Z" } ``` ## Error Codes | Code | Description | | ----- | ------------------------------ | | `400` | Invalid request parameters | | `401` | Unauthorized - Invalid API key | | `403` | Forbidden - Account restricted | | `422` | Insufficient balance | | `429` | Rate limit exceeded | | `500` | Internal server error | ## Transfer Limits | Type | Limit | Description | | --------------- | ------------ | ---------------------------- | | Single Transfer | \$10,000,000 | Per transaction | | Batch Transfers | 100 | Maximum recipients per batch | | Daily Volume | \$50,000,000 | Per account | | Minimum Amount | \$0.01 | Minimum transfer value | ## Best Practices 1. **Use idempotency keys** to prevent duplicate transfers 2. **Batch transfers** when sending to multiple recipients to save on fees 3. **Set appropriate priority** based on urgency 4. **Include memos** for better transaction tracking 5. **Validate addresses** before initiating transfers ## Code Examples ```javascript Node.js theme={null} const axios = require('axios'); // Single transfer async function transferStablecoin(to, amount) { try { const response = await axios.post( 'https://api.stateset.com/v1/stablecoin/transfer', { from: 'stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu', to: to, amount: { denom: 'ssusd', amount: amount }, memo: 'Payment transfer', idempotency_key: `transfer_${Date.now()}` }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); console.log('Transfer successful:', response.data); return response.data; } catch (error) { console.error('Transfer failed:', error.response.data); } } // Batch transfer async function batchTransfer(recipients) { try { const transfers = recipients.map(r => ({ to: r.address, amount: { denom: 'ssusd', amount: r.amount }, memo: r.memo })); const response = await axios.post( 'https://api.stateset.com/v1/stablecoin/transfer', { from: 'stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu', transfers: transfers, memo: 'Batch payment processing' }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' } } ); console.log(`Transferred to ${transfers.length} recipients`); return response.data; } catch (error) { console.error('Batch transfer failed:', error.response.data); } } ``` ```python Python theme={null} import requests import uuid class StablecoinTransfer: def __init__(self, api_key): self.api_key = api_key self.base_url = "https://api.stateset.com/v1/stablecoin" def single_transfer(self, from_address, to_address, amount, memo=None): """Execute a single stablecoin transfer""" url = f"{self.base_url}/transfer" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } data = { "from": from_address, "to": to_address, "amount": { "denom": "ssusd", "amount": str(amount) }, "idempotency_key": str(uuid.uuid4()) } if memo: data["memo"] = memo try: response = requests.post(url, json=data, headers=headers) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: print(f"Transfer failed: {e}") return None def batch_transfer(self, from_address, recipients): """Execute batch transfer to multiple recipients""" url = f"{self.base_url}/transfer" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } transfers = [] for recipient in recipients: transfers.append({ "to": recipient["address"], "amount": { "denom": "ssusd", "amount": str(recipient["amount"]) }, "memo": recipient.get("memo", "") }) data = { "from": from_address, "transfers": transfers, "memo": "Batch transfer" } try: response = requests.post(url, json=data, headers=headers) response.raise_for_status() result = response.json() print(f"Batch transfer completed: {len(transfers)} recipients") print(f"Total amount: {result['total_amount']['display_amount']}") return result except requests.exceptions.RequestException as e: print(f"Batch transfer failed: {e}") return None # Example usage transfer = StablecoinTransfer("YOUR_API_KEY") # Single transfer transfer.single_transfer( "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", "stateset1abcdefghijklmnopqrstuvwxyz123456789012", 1000000000, # 1000 ssUSD "Invoice payment" ) # Batch transfer recipients = [ {"address": "stateset1abc...", "amount": 500000000, "memo": "Vendor A"}, {"address": "stateset1xyz...", "amount": 300000000, "memo": "Vendor B"} ] transfer.batch_transfer( "stateset1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu", recipients ) ``` # Technical Architecture Source: https://docs.stateset.com/stateset-commerce-api-reference/technical Overview of the StateSet Commerce Network Technical Architecture # StateSet Commerce Network: Technical Architecture Overview ## Table of Contents 1. [Introduction](#introduction) 2. [Core Components](#core-components) 3. [Network Layers](#network-layers) 4. [Consensus Mechanism](#consensus-mechanism) 5. [Data Structure and Storage](#data-structure-and-storage) 6. [Smart Contract Engine](#smart-contract-engine) 7. [Interoperability Framework](#interoperability-framework) 8. [Scalability Solutions](#scalability-solutions) 9. [Network Security](#network-security) 10. [Client Interfaces](#client-interfaces) 11. [Future Architectural Developments](#future-architectural-developments) ## Introduction The StateSet Commerce Network is built on a robust and flexible architecture designed to meet the complex needs of modern global commerce. This overview provides insights into the technical foundations that power our decentralized ecosystem. ## Core Components 1. **Cosmos SDK**: The foundational framework for building application-specific blockchains. 2. **Tendermint Core**: Provides Byzantine Fault Tolerant (BFT) consensus and networking. 3. **CosmWasm**: Smart contract platform enabling secure, multi-chain applications. 4. **Inter-Blockchain Communication (IBC) Protocol**: Facilitates interoperability with other blockchain networks. 5. **Custom Modules**: Specialized components for commerce-specific functionality. ## Network Layers 1. **Application Layer**: Implements business logic and state transitions. 2. **Consensus Layer**: Manages agreement on the state of the network. 3. **Networking Layer**: Handles peer discovery and data propagation. 4. **Data Layer**: Manages storage and retrieval of blockchain data. ## Consensus Mechanism * **Algorithm**: Tendermint BFT * **Validator Set**: Dynamic set of validators selected through staking * **Block Time**: 8 seconds * **Finality**: Instant finality upon block confirmation ## Data Structure and Storage * **Block Structure**: Blocks contain transactions, state roots, and other metadata * **State Management**: IAVL+ tree for efficient state updates and proofs * **Data Persistence**: LevelDB for high-performance storage * **Pruning Strategies**: Configurable state pruning for optimized storage ## Smart Contract Engine * **CosmWasm Integration**: Enables WebAssembly-based smart contracts * **Contract Lifecycle**: Deployment, instantiation, execution, and upgrading * **Gas Metering**: Efficient resource allocation and fee calculation * **Inter-Contract Communication**: Allows composability of smart contracts ## Interoperability Framework * **IBC Protocol**: Enables cross-chain communication and asset transfers * **Peg Zones**: Bridges to non-Cosmos chains (e.g., Ethereum, Bitcoin) * **Interchain Accounts**: Cross-chain account management and interactions * **Interchain Security**: Shared security model with the Cosmos Hub ## Scalability Solutions * **Horizontal Scaling**: Application-specific chains for dedicated throughput * **Vertical Scaling**: Optimizations in transaction processing and state management * **Layer-2 Solutions**: Integration with off-chain scaling solutions (e.g., state channels, rollups) * **Sharding**: \[If applicable, describe sharding strategy] ## Network Security * **Sybil Attack Resistance**: Proof-of-Stake mechanism with slashing conditions * **Byzantine Fault Tolerance**: Ability to operate correctly with up to 1/3 faulty nodes * **Governance-based Upgrades**: Secure mechanism for network-wide upgrades ## Client Interfaces * **RPC Endpoints**: JSON-RPC interface for interacting with the network * **REST API**: RESTful API for querying network state and submitting transactions * **CLI**: Command-line interface for node operation and network interaction * **SDK**: Software Development Kit for building applications on Stateset ## Future Architectural Developments * **ZK-Rollups**: Research into zero-knowledge proof integration for enhanced privacy and scalability * **Quantum Resistance**: Preparations for post-quantum cryptographic algorithms * **AI Integration**: Exploration of AI-driven optimizations in consensus and smart contract execution * **Cross-Chain VM Compatibility**: Efforts to support multiple VM environments (e.g., EVM compatibility) ## Conclusion The StateSet Commerce Network's technical architecture is designed for security, scalability, and interoperability. By leveraging cutting-edge blockchain technologies and continuous innovation, we provide a robust foundation for the future of decentralized global commerce. This architecture enables developers to build powerful, commerce-focused applications while ensuring high performance, reliability, and adaptability to evolving market needs. As we continue to evolve, our commitment to technological excellence will drive further enhancements, ensuring that the StateSet Commerce Network remains at the forefront of blockchain innovation in the commerce sector. # Submit a Genesis Transaction Source: https://docs.stateset.com/stateset-commerce-api-reference/testnet-submit-gentx Submit a Genesis Transaction to the StateSet Commerce Network # Submit a `gentx` for the **Stateset Commerce Network** Testnet **Network:** `stateset-1-testnet` **Denom:** `ustst` (micro‑STST) **Plan:** This testnet simulates **stateset `v0.0.8`**. *** ## Quick Start (Copy/Paste) > Replace `` and `` with your own values. > Default home in this doc is `~/.stateset`. If your build uses `~/.statesetd`, adjust paths or pass `--home ~/.statesetd`. ```bash theme={null} # 0) If you've run Stateset before: stop & clean sudo systemctl stop statesetd 2>/dev/null || true statesetd unsafe-reset-all --home ~/.stateset 2>/dev/null || true rm -f ~/.stateset/config/genesis.json rm -rf ~/.stateset/config/gentx/ # 1) Build statesetd (source, v0.0.8) # Requires Go >= 1.17 and a working GOPATH/GOBIN git clone https://github.com/stateset/core cd core git checkout v0.0.8 make build && make install # Sanity check statesetd version # expected format example: latest-8e35a4d3 # 2) Initialize node home statesetd init --chain-id=stateset-1-testnet --home ~/.stateset # 3) Fetch the testnet genesis (one of these will be current in the repo) # Preferred (genesis.json for testnet) curl -s https://raw.githubusercontent.com/stateset/networks/testnets/main/stateset-1-testnet/genesis.json \ > ~/.stateset/config/genesis.json # (Alternate fallback used in earlier instructions) # curl -s https://raw.githubusercontent.com/stateset/networks/main/stateset-1-testnet/pregenesis.json \ # > ~/.stateset/config/genesis.json # 4) Create a key (choose a secure backend) statesetd keys add --keyring-backend os --home ~/.stateset # 5) Add a genesis account with funds (10,000 STATE = 10,000,000,000 ustate) statesetd add-genesis-account $(statesetd keys show -a --keyring-backend os --home ~/.stateset) \ 10000000000ustate --home ~/.stateset # 6) Create your gentx (self-delegate 9,000 STATE = 9,000,000,000 ustate) # Minimal: statesetd gentx 9000000000ustate \ --chain-id=stateset-1-testnet \ --keyring-backend os \ --home ~/.stateset # (Advanced: include validator metadata & commission params) # statesetd gentx 9000000000ustate \ # --commission-max-change-rate "0.05" \ # --commission-max-rate "0.20" \ # --commission-rate "0.01" \ # --moniker "" \ # --identity "" \ # --website "" \ # --details "" \ # --security-contact "" \ # --chain-id=stateset-1-testnet \ # --keyring-backend os \ # --home ~/.stateset # 7) Validate your genesis statesetd validate-genesis --home ~/.stateset # 8) Submit the gentx via PR to the networks repo (see "Submit" section below) # Your gentx file will be at: # ~/.stateset/config/gentx/gentx-*.json ``` *** ## “First!” — If you’re resetting from a previous run 1. **Stop your node** ```bash theme={null} sudo systemctl stop statesetd 2>/dev/null || true pkill -f statesetd 2>/dev/null || true ``` 2. **Unsafe reset** ```bash theme={null} statesetd unsafe-reset-all --home ~/.stateset ``` 3. **Remove old genesis & gentxs** ```bash theme={null} rm -f ~/.stateset/config/genesis.json rm -rf ~/.stateset/config/gentx/ ``` 4. **Proceed with the gentx flow** below. > **Heads‑up:** Some older builds default to `~/.statesetd` instead of `~/.stateset`. If your setup uses `~/.statesetd`, swap the home path (or pass `--home ~/.statesetd` on each command). *** ## Prerequisites * **Golang ≥ 1.17** installed and on your `PATH` * `git`, `curl`, and basic build tools * (Recommended) A configured **GOPATH/GOBIN** **Example environment setup** (Linux/macOS): ```bash theme={null} # Add to ~/.profile or ~/.zshrc then `source` it export GOROOT=/usr/local/go export GOPATH=$HOME/go export GO111MODULE=on export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin ``` If in doubt: ```bash theme={null} mkdir -p ~/go export GOPATH=~/go ``` *** ## Build the `statesetd` Binary ### Option A — Build from Source (recommended for v0.0.8) ```bash theme={null} git clone https://github.com/stateset/core cd core git checkout v0.0.8 make build && make install ``` This installs `statesetd` into `$GOBIN` (commonly `~/go/bin`). Ensure it’s on your `PATH`. Verify: ```bash theme={null} statesetd version # example output: latest-8e35a4d3 ``` ### Option B — Starport/Ignite (alternative) If you prefer Starport: ```bash theme={null} curl https://get.starport.network/starport! | bash git clone https://github.com/stateset/core cd core starport chain build # Move the built binary into your PATH if needed: sudo mv ./build/statesetd /usr/local/bin/ ``` > **Note:** Version parity matters for the testnet. If you use Starport, confirm `statesetd version` aligns with the testnet commit/tag. *** ## Minimum Hardware * **RAM:** 8–16 GB * **Disk:** 100 GB (SSD recommended) * **CPU:** 2 cores *** ## Generate Your `gentx` 1. **Init your node** ```bash theme={null} statesetd init --chain-id=stateset-1-testnet --home ~/.stateset ``` 2. **Pull the testnet genesis** ```bash theme={null} curl -s https://raw.githubusercontent.com/stateset/networks/testnets/main/stateset-1-testnet/genesis.json \ > ~/.stateset/config/genesis.json ``` *(Alternate earlier path used in some guides: `.../main/stateset-1-testnet/pregenesis.json`)* 3. **Create a key** ```bash theme={null} statesetd keys add --keyring-backend os --home ~/.stateset ``` 4. **Add a funded genesis account** ```bash theme={null} statesetd add-genesis-account $(statesetd keys show -a --keyring-backend os --home ~/.stateset) \ 10000000000ustate --home ~/.stateset ``` 5. **Create the gentx** **Minimal form:** ```bash theme={null} statesetd gentx 9000000000ustate \ --chain-id=stateset-1-testnet \ --keyring-backend os \ --home ~/.stateset ``` **Advanced (with metadata & commission):** ```bash theme={null} statesetd gentx 9000000000ustate \ --commission-max-change-rate "0.05" \ --commission-max-rate "0.20" \ --commission-rate "0.01" \ --moniker "" \ --identity "" \ --website "" \ --details "" \ --security-contact "" \ --chain-id=stateset-1-testnet \ --keyring-backend os \ --home ~/.stateset ``` Success looks like: ``` Genesis transaction written to "/home//.stateset/config/gentx/gentx-******.json" ``` 6. **Validate** ```bash theme={null} statesetd validate-genesis --home ~/.stateset ``` *** ## Submit Your `gentx` 1. **Fork** the networks repo: [https://github.com/stateset/networks](https://github.com/stateset/networks) 2. **Clone your fork:** ```bash theme={null} git clone https://github.com//networks cd networks ``` 3. **Copy your gentx** into the testnet folder: ```bash theme={null} mkdir -p testnets/stateset-1-testnet/gentx cp ~/.stateset/config/gentx/gentx*.json ./testnets/stateset-1-testnet/gentx/ ``` 4. **Commit & push, then open a PR** back to `stateset/networks`. > **Acceptance note:** Only PRs from individuals/groups with a history of successfully running nodes may be accepted to ensure the network launches on time. *** ## Tips & Troubleshooting * **Home directory differences** Some environments use `~/.statesetd` as the default. Either: * pass `--home ~/.statesetd` to every command, **or** * symlink: `ln -s ~/.statesetd ~/.stateset` (pick one path and stay consistent). * **Keyring backend** Use `--keyring-backend os` for persistence with your OS keystore. Alternatives: * `file` (plaintext on disk), `test` (ephemeral/in‑memory). * **Denom & amounts** * Denom is `ustate` (micro‑units). * 1 **STATE** = **1,000,000 ustate** * Examples: * 10,000 **STATE** = `10000000000ustate` * 9,000 **STATE** = `9000000000ustate` * **Commission fields** If you include commission params in your `gentx`, typical values for testnets: * `--commission-rate "0.01"` (1%) * `--commission-max-rate "0.20"` (20%) * `--commission-max-change-rate "0.05"` (5% per day) * **Build issues (Go/GOPATH)** Ensure: ```bash theme={null} go version # >= 1.17 echo $GOPATH # set (e.g. $HOME/go) echo $PATH | grep go # includes $GOPATH/bin and $GOROOT/bin ``` * **Sanity checks** ```bash theme={null} statesetd version statesetd validate-genesis --home ~/.stateset jq .chain_id ~/.stateset/config/genesis.json 2>/dev/null # should show "stateset-1-testnet" ``` *** ## Security Notes * **Back up** your mnemonic offline. Anyone with it controls your validator funds. * Never commit `~/.stateset*` contents to any repository. * Double‑check addresses before submitting on‑chain transactions. *** ## What Happens After PR Merge? * The Stateset team publishes the **final** testnet genesis (with accepted gentxs) and launch time. * You’ll be instructed to download the final genesis and start your node/validator for network launch. *** # USDC on StateSet Commerce Network Source: https://docs.stateset.com/stateset-commerce-api-reference/usdc Native USDC integration for seamless commerce payments on StateSet ## Overview StateSet Commerce Network features native USDC integration, providing a fully reserved, dollar-backed stablecoin optimized for commerce transactions within the Cosmos ecosystem. This integration eliminates the need for custodial bridging and enables seamless, secure payments for orders, invoices, and other commerce operations. ## Native USDC on StateSet ### What is StateSet USDC? StateSet USDC is native to the StateSet Commerce Network, which is part of the broader Cosmos/Interchain ecosystem. This provides a seamless and secure integration for commerce users, with no need for custodial bridging from other networks. Native USDC minting and redemption is done exclusively via StateSet Commerce Network. ### Key Features * **Native Integration**: USDC is native to StateSet Commerce Network, not bridged * **Direct Minting/Redemption**: Mint and redeem USDC directly on StateSet * **No Custodial Risk**: Eliminates additional trust assumptions from bridging * **Commerce Optimized**: Designed specifically for commerce use cases * **IBC Compatible**: Seamlessly transfer to other Cosmos chains ## Fee Structure ### Gas Fees Gas fees in Cosmos are generally very low. On StateSet Commerce Network: * **Average Transfer Cost**: \~\$0.01 USD * **IBC Transfers**: No additional fees for transfers to/from StateSet * **Payment Currency**: Fees are paid in USDC directly * **No Gas Token Required**: Unlike other blockchains, no separate gas token needed ### UX Advantages The ability to pay fees in USDC unlocks significant user experience benefits: 1. **Single Currency**: Users only need USDC, not multiple tokens 2. **Predictable Costs**: Stable fee amounts in USD terms 3. **Simplified Onboarding**: No need to acquire gas tokens 4. **Commerce-Friendly**: Familiar dollar-based pricing ## Cross-Chain Capabilities ### IBC Transfers StateSet USDC can be transferred seamlessly between IBC-enabled blockchains: ```mermaid theme={null} graph LR A[StateSet Commerce Network] -->|IBC| B[Osmosis] A -->|IBC| C[Cosmos Hub] A -->|IBC| D[Other IBC Chains] B -->|IBC| A C -->|IBC| A D -->|IBC| A ``` When USDC is transferred from StateSet Commerce Network to another appchain via IBC, it becomes IBC-transferred USDC on that appchain. StateSet uses packet-forwarding technology to ensure a consistent route for USDC among different IBC paths to/from StateSet Commerce Network. ### Cross-Chain Transfer Protocol (CCTP) For non-IBC blockchains, StateSet USDC integrates with Circle's CCTP: * **Supported Networks**: Ethereum, Arbitrum, Base, Avalanche * **Non-Custodial**: Direct native minting across chains * **Seamless Integration**: Easy transfers without wrapped tokens ## Benefits for Commerce ### 1. **Instant Settlement** * Orders are paid and settled immediately on-chain * No waiting for traditional payment processing * Reduced counterparty risk ### 2. **Global Accessibility** * Anyone with USDC can participate in commerce * No geographic restrictions * 24/7 availability ### 3. **Lower Transaction Costs** * Minimal gas fees compared to credit card processing * No intermediary fees * Direct peer-to-peer transactions ### 4. **Transparency** * All transactions verifiable on-chain * Real-time tracking of payments * Immutable transaction history ### 5. **Programmable Commerce** * Smart contract integration for automated workflows * Conditional payments and escrow * Complex commerce logic on-chain ## Ecosystem Benefits ### For the Cosmos Ecosystem StateSet USDC offers a fully reserved, dollar-backed stablecoin optimized for commerce within the Cosmos ecosystem. Its integration: * **Enhances Liquidity**: Provides stable liquidity for commerce operations * **Enables Commerce**: Facilitates B2B and B2C transactions * **Removes Friction**: No custodial bridging from other ecosystems * **Improves Efficiency**: Direct integration with IBC protocol ### For Merchants * **Stable Pricing**: Price products in familiar USD terms * **Instant Payments**: Receive payments immediately * **Global Reach**: Accept payments from anywhere * **Lower Fees**: Reduce payment processing costs ### For Customers * **Simple Payments**: Pay with USDC directly * **No Currency Risk**: Stable value pegged to USD * **Fast Transactions**: Near-instant payment confirmation * **Transparent Costs**: Clear fee structure ## Technical Implementation ### Order Payment Flow ```go theme={null} // Example: Pay for an order with USDC type PayOrderRequest struct { OrderID string PaymentMethod PaymentMethod Amount sdk.Coin // USDC amount } // Payment is processed atomically func (k Keeper) PayOrder(ctx sdk.Context, req PayOrderRequest) error { // Validate order exists and is unpaid order := k.GetOrder(ctx, req.OrderID) if order.PaymentStatus == "PAID" { return errors.New("order already paid") } // Transfer USDC from customer to merchant err := k.bankKeeper.SendCoins(ctx, customerAddr, merchantAddr, sdk.NewCoins(req.Amount)) // Update order status atomically order.PaymentStatus = "PAID" order.Status = "PROCESSING" k.SetOrder(ctx, order) return nil } ``` ### Smart Contract Integration StateSet Commerce Network smart contracts can: * Accept USDC payments directly * Implement escrow mechanisms * Create automated payment flows * Enable subscription payments * Process refunds automatically ## Bridged vs Native USDC ### Native USDC (StateSet) * ✅ No additional trust assumptions * ✅ Direct mint/redeem with Circle * ✅ Native to StateSet Commerce Network * ✅ Seamless IBC integration * ✅ Commerce-optimized features ### Bridged USDC (Other Solutions) * ❌ Additional custodial trust required * ❌ Dependent on bridge validators * ❌ Potential bridge risks * ❌ Added complexity * ❌ Higher fees ## Getting Started ### For Merchants 1. **Create a StateSet Account**: Sign up at [app.stateset.com](https://app.stateset.com) 2. **Set Up USDC Wallet**: Configure your merchant wallet address 3. **Integrate Payment API**: Use our [Pay Order endpoint](/stateset-commerce-api-reference/orders/pay) 4. **Accept Payments**: Start accepting USDC payments immediately ### For Developers ```javascript theme={null} // Initialize StateSet client const stateset = new StateSetClient({ endpoint: 'https://api.stateset.network' }); // Process a payment const payment = await stateset.orders.pay({ order_id: 'ord_123', payment_method: { type: 'usdc', wallet_address: 'cosmos1...', amount: { value: '99.99', denom: 'usdc' } } }); ``` ### For Customers 1. **Get USDC**: Acquire USDC on any supported platform 2. **Connect Wallet**: Use any Cosmos-compatible wallet 3. **Make Payment**: Pay for orders directly with USDC 4. **Track Transaction**: Monitor payment on-chain ## API Endpoints ### Payment Endpoints * [`POST /v1/order/pay`](/stateset-commerce-api-reference/orders/pay) - Pay for an order * [`POST /v1/invoice/pay`](/stateset-commerce-api-reference/invoices/pay) - Pay an invoice * [`POST /v1/loan/repay`](/stateset-commerce-api-reference/loans/repay) - Repay a loan ### Query Endpoints * `GET /v1/balance/{address}` - Check USDC balance * `GET /v1/transactions/{address}` - View transaction history * `GET /v1/payments/{order_id}` - Get payment details ## Security Considerations ### Best Practices 1. **Wallet Security**: Use hardware wallets for large amounts 2. **Address Validation**: Always verify recipient addresses 3. **Amount Verification**: Double-check payment amounts 4. **Transaction Monitoring**: Track all transactions on-chain ### Smart Contract Audits * All StateSet contracts are audited by leading security firms * Open-source code for transparency * Bug bounty program for continuous security ## Support and Resources ### Documentation * [Orders Module](/stateset-commerce-api-reference/orders) * [Finance Module](/stateset-commerce-api-reference/finance) * [API Reference](/stateset-commerce-api-reference/overview) ### Community * [Discord](https://discord.gg/stateset) * [GitHub](https://github.com/stateset) * [Twitter](https://twitter.com/stateset) ### Technical Support * Email: [support@stateset.com](mailto:support@stateset.com) * Developer Forum: forum.stateset.com * Office Hours: Weekly developer calls ## Conclusion StateSet USDC represents the future of commerce payments on blockchain. By providing native USDC integration optimized for commerce use cases, StateSet Commerce Network enables fast, secure, and cost-effective transactions for businesses worldwide. Whether you're a merchant looking to accept stable payments or a developer building the next generation of commerce applications, StateSet USDC provides the infrastructure you need to succeed. # Use Cases Source: https://docs.stateset.com/stateset-commerce-api-reference/use-cases Real-world applications and success stories built on StateSet # Use Cases: Building the Future of Commerce Discover how businesses are leveraging StateSet to transform their operations, reduce costs, and unlock new opportunities. ## 🛍️ E-Commerce & Retail ### Global Fashion Marketplace **Challenge**: A fashion marketplace struggled with international payments, taking 5-7 days for settlement and losing 3-5% on forex fees. **Solution**: Integrated StateSet for instant stablecoin payments and automated currency conversion. **Results**: * ⚡ Settlement time: 7 days → 1 second * 💰 Payment costs: 3-5% → 0.1% * 🌍 New markets: Expanded to 45 countries * 📈 GMV increase: 340% in 6 months ```javascript theme={null} // Multi-currency checkout implementation const checkout = await stateset.checkout.create({ items: cart.items, display_currency: customer.preferred_currency, payment_currency: 'ssusd', shipping_address: customer.address, auto_convert: true }); ``` ### Drop-Shipping Automation **Challenge**: Managing inventory and payments across 200+ suppliers with different payment terms and currencies. **Solution**: Deployed AI agents for automated procurement and payment optimization. **Results**: * 🤖 24/7 automated ordering * 📉 Inventory costs: -35% * ⏱️ Order processing: 4 hours → 5 minutes * 💵 Working capital improvement: 40% ```javascript theme={null} // Autonomous procurement agent const agent = await stateset.agents.create({ type: 'procurement', name: 'SupplierBot', capabilities: ['monitor_inventory', 'negotiate_prices', 'place_orders'], limits: { daily_spend: '50000.00' }, optimization_goal: 'minimize_stockouts' }); ``` ## 💼 B2B Trade Finance ### Manufacturing Supply Chain **Challenge**: A electronics manufacturer needed \$2M in working capital for component purchases but banks offered only 70% financing at 15% APR. **Solution**: Used StateSet's purchase order financing and invoice factoring. **Results**: * 💰 Financing obtained: 95% of PO value * 📉 Cost of capital: 15% → 4% * ⏱️ Approval time: 3 weeks → 2 hours * 🚀 Production capacity: +250% ```javascript theme={null} // PO financing workflow const poFinancing = await stateset.finance.financePurchaseOrder({ po_id: 'po_12345', amount: '2000000.00', supplier_id: 'supplier_789', buyer_guarantee: true, smart_contract_escrow: true }); // Automatic invoice factoring upon delivery const factoring = await stateset.finance.factorInvoice({ invoice_id: 'inv_67890', advance_rate: 0.95, recourse: false }); ``` ### Cross-Border Trade Platform **Challenge**: Import/export company dealing with complex compliance, slow payments, and high banking fees. **Solution**: Built on StateSet's global commerce infrastructure. **Results**: * 🌍 Countries served: 12 → 195 * 📋 Compliance time: 2 weeks → 2 minutes * 💸 Transaction fees: 4% → 0.1% * 📈 Trade volume: 10x growth ```javascript theme={null} // Automated cross-border transaction const trade = await stateset.global.createOrder({ exporter: { country: 'DE', entity_id: 'exporter_123' }, importer: { country: 'US', entity_id: 'importer_456' }, goods: [{ hs_code: '8471.30.01', value: '100000.00', origin_country: 'TW' }], compliance: { auto_check: true, generate_docs: ['commercial_invoice', 'certificate_of_origin'] }, payment: { terms: 'letter_of_credit', smart_contract: true } }); ``` ## 🤖 Autonomous Commerce ### AI-Powered Procurement **Challenge**: Fortune 500 company managing 10,000+ SKUs across 500 suppliers with volatile pricing. **Solution**: Deployed fleet of AI procurement agents on StateSet. **Results**: * 💰 Cost savings: \$12M annually * 🎯 Stockout reduction: 89% * ⚡ Negotiation time: Days → Minutes * 📊 Price optimization: -8% average ```javascript theme={null} // Multi-agent procurement system const procurementFleet = await stateset.agents.createFleet({ agents: [ { type: 'negotiator', focus: 'price_optimization' }, { type: 'inventory_manager', focus: 'demand_forecasting' }, { type: 'quality_controller', focus: 'supplier_scoring' } ], coordination: 'autonomous', budget: { monthly: '10000000.00' }, kpis: ['cost_reduction', 'availability', 'quality'] }); ``` ### Decentralized Marketplace **Challenge**: Creating a marketplace where buyers and sellers can transact without intermediaries. **Solution**: Built autonomous matching and settlement on StateSet. **Results**: * 🤝 Direct peer-to-peer trade * 💰 No marketplace fees * ⚡ Instant settlement * 🔒 Smart contract guarantees ```javascript theme={null} // Autonomous market maker const marketMaker = await stateset.agents.create({ type: 'market_maker', name: 'PriceDiscovery', capabilities: ['match_orders', 'determine_prices', 'settle_trades'], parameters: { spread: 0.001, depth: '1000000.00', rebalance_frequency: '1_hour' } }); ``` ## 🏦 Financial Services ### Embedded Finance Platform **Challenge**: SaaS platform wanted to offer financial services to their 50,000 business customers. **Solution**: White-labeled StateSet's finance APIs. **Results**: * 💳 New revenue stream: \$5M ARR * 👥 Customer retention: +45% * 💰 Capital deployed: \$200M * ⏱️ Integration time: 2 weeks ```javascript theme={null} // White-label finance integration const financeAPI = stateset.whiteLabel.create({ brand: 'YourFinance', products: ['invoice_factoring', 'po_financing', 'payments'], customization: { logo: 'https://...', colors: { primary: '#007bff' }, domain: 'finance.yourplatform.com' }, revenue_share: 0.25 }); ``` ### Trade Credit Insurance **Challenge**: Insurance company modernizing trade credit offerings with real-time risk assessment. **Solution**: Built parametric insurance products on StateSet. **Results**: * ⚡ Claim processing: 30 days → Instant * 📊 Risk assessment: Manual → AI-powered * 💰 Operating costs: -70% * 🚀 Policies issued: 10x increase ```javascript theme={null} // Parametric trade credit insurance const policy = await stateset.insurance.createPolicy({ type: 'trade_credit', coverage: { amount: '5000000.00', triggers: [ { event: 'payment_delay', threshold: 30, payout: 0.1 }, { event: 'buyer_default', threshold: 90, payout: 0.9 } ] }, premium: { monthly: '5000.00', automatic_debit: true }, oracle: 'chainlink_credit_default' }); ``` ## 🌱 Sustainable Commerce ### Carbon-Neutral Supply Chain **Challenge**: Fashion brand committed to carbon neutrality across their supply chain. **Solution**: Integrated carbon tracking and offset automation. **Results**: * 🌍 Carbon tracking: 100% of transactions * 🌳 Automatic offset purchasing * 📊 Sustainability reporting: Real-time * 💚 Customer trust: +67% NPS ```javascript theme={null} // Carbon-tracked commerce const order = await stateset.orders.create({ items: [...], sustainability: { track_carbon: true, offset_automatically: true, offset_provider: 'verified_carbon_standard', reporting: 'blockchain_verified' } }); ``` ### Fair Trade Marketplace **Challenge**: Connecting artisans in developing countries directly with global consumers. **Solution**: Built fair trade platform with transparent pricing and instant payments. **Results**: * 👥 Artisans onboarded: 25,000 * 💰 Income increase: 3x for producers * 🌍 Countries: 47 * ⚡ Payment time: 30 days → Instant ```javascript theme={null} // Direct artisan payments const fairTrade = await stateset.payments.create({ recipient: artisan.wallet, amount: sale.amount * 0.85, // 85% to artisan currency: 'ssusd', conversion: { to_local_currency: true, preferred_provider: 'local_bank' }, metadata: { impact_metrics: { artisan_id: artisan.id, community: artisan.community, fair_trade_certified: true } } }); ``` ## 🏗️ Industry Solutions ### Construction & Real Estate **Use Case**: Progress-based payments for construction projects ```javascript theme={null} const milestone = await stateset.escrow.releaseMilestone({ project_id: 'construction_123', milestone: 'foundation_complete', verification: { iot_sensors: true, drone_imagery: true, inspector_signoff: true }, payment: { amount: '500000.00', distribute_to: [ { contractor: '123', share: 0.7 }, { supplier: '456', share: 0.3 } ] } }); ``` ### Healthcare **Use Case**: Medical supply chain financing and tracking ```javascript theme={null} const medicalOrder = await stateset.healthcare.createOrder({ items: [{ name: 'Surgical Equipment', regulatory: { fda_approved: true } }], compliance: { hipaa_compliant: true, track_temperature: true, blockchain_verification: true }, financing: { type: 'purchase_order', terms: 'net_60' } }); ``` ### Agriculture **Use Case**: Crop insurance and supply chain finance ```javascript theme={null} const cropInsurance = await stateset.agriculture.insure({ farm_id: 'farm_789', crop: 'corn', coverage: { amount: '100000.00', triggers: { weather: { rainfall_below: 20, // inches temperature_above: 95 // fahrenheit } } }, data_source: 'weather_oracle', auto_payout: true }); ``` ## 🎯 Success Metrics ### Platform Statistics
\$5B+
Transaction Volume
50K+
Active Businesses
195
Countries Served
\< 1s
Avg. Settlement
## 🚀 Start Building Ready to transform your business with StateSet? See StateSet in action with our team Get \$1,000 in free credits to start Discuss enterprise solutions Start building immediately *** *Have a unique use case? We'd love to hear about it. [Contact us](mailto:innovation@stateset.com) to explore how StateSet can help.* # Vision Source: https://docs.stateset.com/stateset-commerce-api-reference/vision Overview of the StateSet Commerce Network Vision # The Future of the StateSet Commerce Network 2024 sets the stage for StateSet's transformative journey, focusing on advanced infrastructure development and initial ecosystem building. Key initiatives include: * **Quantum-Resistant Cryptography**: Implementing next-generation security measures to future-proof the network. * **AI Integration**: Introducing advanced AI capabilities for predictive analytics and automated processes. * **IoT Supply Chain Integration**: Enabling real-time tracking and optimization of global supply chains. * **CBDC Integration**: Preparing for seamless connectivity with central bank digital currencies. * **Agent Marketplace Launch**: Introducing the platform for deploying and managing autonomous AI agents. 2025 represents a landmark year for the StateSet Commerce Network, where we establish the core infrastructure, develop critical order management modules, and launch the network to the world. These foundational steps will propel the revolutionary changes StateSet will bring to global commerce. Network Infrastructure Development: In 2025, the StateSet Commerce Network protocol prioritizes building a robust, scalable infrastructure. Built on the Cosmos SDK and Comet BFT, it ensures high throughput, low latency, and secure transactions. The architecture is optimized for global commerce demands, emphasizing scalability, security, interoperability, and integration with emerging technologies like AI and IoT. The development of order management modules remains a cornerstone for StateSet in 2025. These modules form the backbone of the network, empowering businesses to manage orders in a decentralized, transparent, and efficient manner. Enhanced functionalities include: * **Order Creation and Management**: Create, modify, and track orders on the blockchain with real-time visibility. * **Order Fulfillment**: Seamless integration with logistics providers for efficient processing and delivery. * **Order Financing and Payment**: Secure, instant USDC-based financing and payments with DID integration for verifiable transactions. * **Dispute Resolution**: Transparent, decentralized mechanisms for fair issue resolution. * **Cross-Platform MCP Integration**: Enabling multi-agent coordination across platforms. #### **2029: A Decentralized Commerce Ecosystem** By 2029, the StateSet Commerce Network stands as the premier decentralized commerce platform, serving millions of users and thousands of businesses worldwide with secure, transparent transactions. Major achievements include: * **Universal DID Adoption**: Standardizing identity and contract management for seamless, trustless interactions. * **Interconnected Global Trade**: IBC-enabled asset and data flow across blockchains, unlocking new markets. * **Financial Inclusion**: RWA tokenization and USDC financing democratizing access for SMEs globally. * **Enhanced Privacy and Security**: Advanced zero-knowledge proofs and encryption for ultimate protection. * **Thriving Developer Ecosystem**: Mature SDKs powering innovative dApps in supply chain and DeFi. * **Multi-Agent Coordination**: Complex workflow automation through autonomous agents. #### **2034: The Digital Backbone of Global Commerce** By 2034, StateSet has become the essential infrastructure for worldwide business, governments, and individuals, surpassing traditional systems. Significant advancements include: * **STATE as Global Settlement Currency**: Widespread adoption for high-value international transactions. * **Autonomous Commerce Networks**: AI agents optimizing real-time transactions from logistics to service. * **Smart Cities Integration**: Managing public services and energy distribution in urban environments. * **Regulatory Compliance Standards**: Full compliance across jurisdictions with global standards. * **Advanced Digital Identity**: Evolved DIDs with dynamic contracts and self-sovereign solutions. * **Predictive Trade Finance**: AI-driven forecasting and zero-knowledge compliance. #### **2038: A New Era of Global Prosperity** By 2038, StateSet drives global prosperity through decentralized commerce and finance, catalyzing social and economic change. Highlights include: * **Fully Decentralized Economy**: Direct interactions eliminating traditional intermediaries. * **Universal Basic Finance**: Essential services accessible to all, reducing poverty worldwide. * **Interplanetary Commerce**: Extending decentralized trade to space colonies. * **Collective Intelligence Governance**: AI-assisted system maximizing benefits for all. * **New Social Contract**: Equitable distribution of economic power and opportunities. #### **The Road Ahead** Looking beyond 2038, the StateSet Commerce Network continues to innovate at the intersection of blockchain, AI, and global commerce. With quantum-resistant security, federated learning, and planetary-scale automation, StateSet remains committed to creating an inclusive, efficient, and prosperous future for all. # Webhooks Source: https://docs.stateset.com/stateset-commerce-api-reference/webhooks Real-time event notifications for your StateSet integration Webhooks allow your application to receive real-time notifications when events occur in your StateSet account, eliminating the need for polling. ## 🔔 Overview StateSet webhooks are HTTP callbacks that notify your application when specific events occur. Instead of continuously polling our API, you can register webhook endpoints to receive automatic notifications. ### Key Benefits Receive instant notifications when events occur Eliminate polling and reduce API usage Automatic retries ensure delivery ## 🚀 Quick Start Set up an HTTPS endpoint on your server to receive webhook events: ```javascript theme={null} app.post('/webhooks/stateset', (req, res) => { const event = req.body; // Process the event console.log('Received event:', event.type); // Return 200 to acknowledge receipt res.status(200).send('OK'); }); ``` Register your endpoint with StateSet: ```bash theme={null} curl -X POST https://api.stateset.com/v1/webhooks \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.com/webhooks/stateset", "events": ["payment.succeeded", "payment.failed"], "description": "Production payment notifications" }' ``` Verify webhook signatures to ensure authenticity: ```javascript theme={null} const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } ``` ## 📋 Event Types ### Payment Events Triggered when a new payment is initiated ```json theme={null} { "id": "evt_1a2b3c4d", "type": "payment.created", "created": 1640995200, "data": { "payment_id": "pay_xyz123", "amount": "100.00", "currency": "ssusd", "status": "pending" } } ``` Triggered when a payment is successfully completed ```json theme={null} { "id": "evt_2b3c4d5e", "type": "payment.succeeded", "created": 1640995260, "data": { "payment_id": "pay_xyz123", "amount": "100.00", "currency": "ssusd", "status": "succeeded", "transaction_hash": "0xabc..." } } ``` Triggered when a payment fails ```json theme={null} { "id": "evt_3c4d5e6f", "type": "payment.failed", "created": 1640995320, "data": { "payment_id": "pay_xyz123", "amount": "100.00", "currency": "ssusd", "status": "failed", "failure_reason": "insufficient_funds" } } ``` ### Stablecoin Events Triggered when new ssUSD is minted ```json theme={null} { "id": "evt_4d5e6f7g", "type": "stablecoin.issued", "created": 1640995400, "data": { "issuance_id": "iss_abc123", "amount": "50000.00", "recipient": "stateset1...", "total_supply": "125000000.00" } } ``` Triggered when ssUSD is burned for USD ```json theme={null} { "id": "evt_5e6f7g8h", "type": "stablecoin.redeemed", "created": 1640995500, "data": { "redemption_id": "red_def456", "amount": "10000.00", "bank_account": "**** 1234", "status": "processing" } } ``` Triggered when ssUSD is transferred ```json theme={null} { "id": "evt_6f7g8h9i", "type": "stablecoin.transferred", "created": 1640995600, "data": { "transfer_id": "xfr_ghi789", "from": "stateset1abc...", "to": "stateset1xyz...", "amount": "500.00" } } ``` ### Order Events Triggered when a new order is created Triggered when an order is paid Triggered when an order is marked as fulfilled Triggered when an order is cancelled ### Invoice Events Triggered when a new invoice is created Triggered when an invoice is paid in full Triggered when a partial payment is made Triggered when an invoice becomes overdue ## 🔐 Webhook Security ### Signature Verification All webhook requests include a signature in the `X-StateSet-Signature` header. Always verify this signature: ```javascript Node.js theme={null} const crypto = require('crypto'); function verifyWebhook(req, secret) { const signature = req.headers['x-stateset-signature']; const timestamp = req.headers['x-stateset-timestamp']; const payload = JSON.stringify(req.body); // Prevent replay attacks const currentTime = Math.floor(Date.now() / 1000); if (currentTime - parseInt(timestamp) > 300) { // 5 minutes throw new Error('Webhook timestamp too old'); } // Verify signature const signedPayload = `${timestamp}.${payload}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex'); if (signature !== expectedSignature) { throw new Error('Invalid webhook signature'); } return JSON.parse(payload); } // Express middleware app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => { try { const event = verifyWebhook(req, process.env.WEBHOOK_SECRET); // Process event handleWebhookEvent(event); res.status(200).send('OK'); } catch (err) { console.error('Webhook error:', err.message); res.status(400).send('Webhook Error'); } }); ``` ```python Python theme={null} import hmac import hashlib import json import time def verify_webhook(payload, signature, timestamp, secret): # Prevent replay attacks current_time = int(time.time()) if current_time - int(timestamp) > 300: # 5 minutes raise ValueError('Webhook timestamp too old') # Verify signature signed_payload = f"{timestamp}.{payload}" expected_signature = hmac.new( secret.encode('utf-8'), signed_payload.encode('utf-8'), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(signature, expected_signature): raise ValueError('Invalid webhook signature') return json.loads(payload) # Flask example from flask import Flask, request, abort app = Flask(__name__) @app.route('/webhook', methods=['POST']) def handle_webhook(): signature = request.headers.get('X-StateSet-Signature') timestamp = request.headers.get('X-StateSet-Timestamp') try: event = verify_webhook( request.data.decode('utf-8'), signature, timestamp, os.getenv('WEBHOOK_SECRET') ) # Process event process_webhook_event(event) return 'OK', 200 except Exception as e: print(f'Webhook error: {e}') abort(400) ``` ```go Go theme={null} package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io/ioutil" "net/http" "strconv" "time" ) func verifyWebhook(payload []byte, signature, timestamp, secret string) (map[string]interface{}, error) { // Prevent replay attacks ts, _ := strconv.ParseInt(timestamp, 10, 64) if time.Now().Unix()-ts > 300 { // 5 minutes return nil, fmt.Errorf("webhook timestamp too old") } // Verify signature signedPayload := fmt.Sprintf("%s.%s", timestamp, string(payload)) h := hmac.New(sha256.New, []byte(secret)) h.Write([]byte(signedPayload)) expectedSignature := hex.EncodeToString(h.Sum(nil)) if !hmac.Equal([]byte(signature), []byte(expectedSignature)) { return nil, fmt.Errorf("invalid webhook signature") } var event map[string]interface{} err := json.Unmarshal(payload, &event) return event, err } func webhookHandler(w http.ResponseWriter, r *http.Request) { signature := r.Header.Get("X-StateSet-Signature") timestamp := r.Header.Get("X-StateSet-Timestamp") body, _ := ioutil.ReadAll(r.Body) event, err := verifyWebhook(body, signature, timestamp, os.Getenv("WEBHOOK_SECRET")) if err != nil { http.Error(w, "Invalid webhook", http.StatusBadRequest) return } // Process event processWebhookEvent(event) w.WriteHeader(http.StatusOK) w.Write([]byte("OK")) } ``` ### Best Practices Never process webhook events without verifying the signature. This prevents attackers from sending fake events. Return a 200 status code as soon as possible. Process events asynchronously if needed: ```javascript theme={null} app.post('/webhook', async (req, res) => { // Acknowledge receipt immediately res.status(200).send('OK'); // Process asynchronously processEventAsync(req.body); }); ``` Webhooks may be sent multiple times. Use the event ID to handle duplicates: ```javascript theme={null} const processedEvents = new Set(); function handleEvent(event) { if (processedEvents.has(event.id)) { console.log('Duplicate event:', event.id); return; } processedEvents.add(event.id); // Process event... } ``` Your endpoint should handle retries gracefully. StateSet will retry failed webhooks with exponential backoff. ## 🔧 Webhook Management ### Create a Webhook ```bash theme={null} POST /v1/webhooks ``` ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/webhooks \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.com/webhooks/stateset", "events": ["payment.succeeded", "payment.failed"], "description": "Payment notifications", "metadata": { "environment": "production" } }' ``` ```javascript Node.js theme={null} const webhook = await stateset.webhooks.create({ url: 'https://your-app.com/webhooks/stateset', events: ['payment.succeeded', 'payment.failed'], description: 'Payment notifications', metadata: { environment: 'production' } }); ``` ### List Webhooks ```bash theme={null} GET /v1/webhooks ``` ```bash cURL theme={null} curl https://api.stateset.com/v1/webhooks \ -H "Authorization: Bearer sk_test_..." ``` ```javascript Node.js theme={null} const webhooks = await stateset.webhooks.list({ limit: 10, active: true }); ``` ### Update a Webhook ```bash theme={null} PUT /v1/webhooks/{webhook_id} ``` ```bash cURL theme={null} curl -X PUT https://api.stateset.com/v1/webhooks/hook_abc123 \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "events": ["payment.succeeded", "payment.failed", "order.created"], "active": true }' ``` ```javascript Node.js theme={null} const updated = await stateset.webhooks.update('hook_abc123', { events: ['payment.succeeded', 'payment.failed', 'order.created'], active: true }); ``` ### Delete a Webhook ```bash theme={null} DELETE /v1/webhooks/{webhook_id} ``` ```bash cURL theme={null} curl -X DELETE https://api.stateset.com/v1/webhooks/hook_abc123 \ -H "Authorization: Bearer sk_test_..." ``` ```javascript Node.js theme={null} await stateset.webhooks.delete('hook_abc123'); ``` ### Test a Webhook Send a test event to verify your endpoint is working: ```bash theme={null} POST /v1/webhooks/{webhook_id}/test ``` ```bash cURL theme={null} curl -X POST https://api.stateset.com/v1/webhooks/hook_abc123/test \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "event_type": "payment.succeeded" }' ``` ```javascript Node.js theme={null} const result = await stateset.webhooks.test('hook_abc123', { event_type: 'payment.succeeded' }); ``` ## 📊 Webhook Event Structure All webhook events follow this structure: ```json theme={null} { "id": "evt_1a2b3c4d5e6f", "object": "event", "type": "payment.succeeded", "created": 1640995200, "data": { // Event-specific data }, "request": { "id": "req_xyz789", "idempotency_key": "key_123" }, "pending_webhooks": 1, "api_version": "2024-01-15" } ``` ### Event Fields | Field | Description | | ------------------ | ------------------------------------------------------ | | `id` | Unique identifier for the event | | `object` | Always "event" | | `type` | The type of event (e.g., "payment.succeeded") | | `created` | Unix timestamp of event creation | | `data` | Event-specific data object | | `request` | Details about the API request that triggered the event | | `pending_webhooks` | Number of webhooks yet to be delivered | | `api_version` | API version used for this event | ## 🔄 Retry Logic StateSet automatically retries failed webhook deliveries with exponential backoff: | Attempt | Delay | Total Time | | ------- | ---------- | ------------ | | 1 | Immediate | 0 seconds | | 2 | 10 seconds | 10 seconds | | 3 | 1 minute | 1.2 minutes | | 4 | 10 minutes | 11.2 minutes | | 5 | 1 hour | 1.2 hours | | 6 | 3 hours | 4.2 hours | | 7 | 12 hours | 16.2 hours | After 7 attempts over \~16 hours, the webhook is marked as failed. ### Handling Failures Monitor webhook failures through the dashboard or API: ```javascript theme={null} // Get failed webhook attempts const failures = await stateset.webhooks.failures.list({ webhook_id: 'hook_abc123', limit: 20 }); // Retry a failed webhook await stateset.webhooks.failures.retry('fail_xyz789'); ``` ## 🧪 Testing Webhooks ### Local Development Use ngrok to test webhooks locally: ```bash theme={null} # Install ngrok brew install ngrok # Expose your local server ngrok http 3000 # Use the ngrok URL for webhooks # https://abc123.ngrok.io/webhooks/stateset ``` ### Webhook Testing Tool Use our webhook testing tool in the dashboard: 1. Navigate to Webhooks → Testing 2. Select an event type 3. Customize the payload 4. Send test event ### Unit Testing Mock webhook events in your tests: ```javascript theme={null} // Jest example const mockWebhookEvent = { id: 'evt_test_123', type: 'payment.succeeded', created: Date.now() / 1000, data: { payment_id: 'pay_test_123', amount: '100.00', currency: 'ssusd' } }; test('handles payment.succeeded webhook', async () => { const result = await handleWebhook(mockWebhookEvent); expect(result.processed).toBe(true); }); ``` ## 📈 Monitoring & Debugging ### Webhook Logs View detailed logs for all webhook attempts: ```javascript theme={null} const logs = await stateset.webhooks.logs.list({ webhook_id: 'hook_abc123', start_date: '2024-01-01', end_date: '2024-01-31' }); logs.data.forEach(log => { console.log(`${log.created}: ${log.status} - ${log.response_code}`); }); ``` ### Metrics Track webhook performance: ```javascript theme={null} const metrics = await stateset.webhooks.metrics({ webhook_id: 'hook_abc123', period: 'day' }); console.log(`Success rate: ${metrics.success_rate}%`); console.log(`Average latency: ${metrics.avg_latency}ms`); ``` ### Debug Mode Enable debug mode for verbose logging: ```javascript theme={null} const webhook = await stateset.webhooks.create({ url: 'https://your-app.com/webhook', events: ['*'], // All events debug: true // Verbose logging }); ``` ## 🚨 Common Issues **Checklist:** * Verify the webhook URL is correct and publicly accessible * Check that SSL certificate is valid (HTTPS required) * Ensure the webhook is active * Verify event types are subscribed * Check firewall rules allow StateSet IPs **Common causes:** * Using wrong webhook secret * Not using raw request body for signature * Character encoding issues * Clock skew (check server time) **Solutions:** * Store and check event IDs * Use idempotency keys * Implement proper deduplication logic **Best practices:** * Respond with 200 immediately * Process events asynchronously * Optimize database queries * Use message queues for heavy processing ## 🌐 IP Allowlist For enhanced security, allowlist StateSet webhook IPs: ``` Production: - 34.123.45.67/32 - 35.234.56.78/32 - 36.345.67.89/32 Test Mode: - 10.123.45.67/32 - 11.234.56.78/32 ``` IP addresses are subject to change. Subscribe to our changelog for updates. ## 📚 Next Steps Complete list of all webhook events Manage webhooks in the dashboard Example implementations in various languages Detailed webhook API documentation # Console Agent Pipeline Source: https://docs.stateset.com/stateset-console/stateset-console-agent-pipeline How agent requests are processed and streamed via SSE. # Console Agent Pipeline The console routes agent interactions through `/api/ai/agent-chat`, streaming responses via Server-Sent Events (SSE). ## Pipeline Steps 1. Validate the user session with `requireAuth()`. 2. Verify chat ownership for the org. 3. Resolve sandbox auth context and credentials. 4. Load chat context and recent messages. 5. Run the agent in the sandbox runtime. 6. Stream events and results over SSE. ## Guardrails * Sensitive tools trigger confirmation events * Tool calls are validated against policy and guardrails * Confirmation tokens are required for write actions ## Related Documentation * [Console Architecture](/stateset-console/architecture) * [Autonomous CX Test Case](/stateset-console/autonomous-cx-test-case) # Console Auth Flow Source: https://docs.stateset.com/stateset-console/stateset-console-auth-flow Authentication modes and session cookies in StateSet Console. # Console Auth Flow StateSet Console supports multiple auth modes and issues a signed session cookie for protected routes. ## Supported Modes * **Email/password**: proxied to Sandbox API login * **API key**: validated locally in the console * **Token refresh**: re-issues a session using an existing JWT * **Dev login**: optional in non-production ## Session Cookies * `session`: signed JWT containing `orgId` and `userId` * `sandbox_session`: sandbox token used for Sandbox API calls * `api_key`: stored API key for API-key auth ## Typical Flow 1. Client posts credentials to `/api/auth/login`. 2. Console validates via Sandbox API or local API key logic. 3. Console sets session cookies and returns user/org metadata. ## Related Documentation * [Console Architecture](/stateset-console/architecture) * [Console API Reference](/stateset-console/api-reference) # Set up StateSet Console Source: https://docs.stateset.com/stateset-console/stateset-console-overview Configure the admin console for operations and integrations. # Set up StateSet Console Use the console to configure integrations, monitor agents, and manage operations. ## Prerequisites * StateSet workspace and API access * Hasura endpoint and admin secret * Sandbox API access ## Configure the console 1. Install dependencies and set environment variables. 2. Connect Hasura, Sandbox, and billing services. 3. Start the console and verify access. Use a dedicated staging environment before production. ## Verify the result Sign in and confirm dashboards load and integrations validate. ## Related tasks * [Setup Guide](/stateset-console/setup) * [Architecture](/stateset-console/architecture) * [API Reference](/stateset-console/api-reference) # StateSet Demo App Source: https://docs.stateset.com/stateset-demo-app-overview Demo application showcasing StateSet platform workflows, agent interactions, and commerce integrations. # StateSet Demo App The StateSet Demo App is a reference application that demonstrates core platform capabilities — order management, return processing, AI agent interactions, and third-party integrations — in a working frontend. ## What's Included * **Order workflows** — Create, fulfill, ship, and manage orders through the full lifecycle. * **Return processing** — Initiate returns, generate RMAs, and process refunds. * **AI agent interaction** — Chat with a StateSet Response agent that retrieves live commerce data. * **Inventory management** — View stock levels, adjust quantities, and transfer between locations. * **Integration demos** — Working examples of Shopify, Stripe, and Gorgias integrations. ## Run Locally ### Prerequisites * Node.js v18+ * A StateSet API key ### Setup ```bash theme={null} git clone https://github.com/stateset/stateset-demo-app.git cd stateset-demo-app npm install ``` ### Configure Environment ```env theme={null} STATESET_API_KEY=your_api_key NEXT_PUBLIC_APP_URL=http://localhost:3000 ``` ### Start the App ```bash theme={null} npm start ``` Open [http://localhost:3000](http://localhost:3000). ## Demo Scenarios | Scenario | Description | | ------------------ | ------------------------------------------------------------------ | | **Order-to-cash** | Create an order, capture payment, fulfill, and ship | | **Return flow** | Customer-initiated return through inspection and refund | | **Agent chat** | Ask the AI agent about order status, return policies, or inventory | | **Inventory sync** | Update stock across multiple warehouse locations | ## Architecture ``` Demo App (Next.js) │ ├── StateSet One API (orders, returns, inventory) ├── StateSet Response API (AI agents) ├── Shopify (product data) └── Stripe (payments) ``` ## Related Documentation * [Demo App README](/stateset-demo-app/README) * [API Reference](/api-reference/introduction) * [Orders Quickstart](/guides/orders-quickstart) * [Response Quickstart](/guides/response-quickstart) # Deploy the ACP Handler Source: https://docs.stateset.com/stateset-deploy-acp-handler Use StateSet Deploy to ship the ACP handler to production. # Deploy the ACP Handler StateSet Deploy can build and host the ACP handler on managed Kubernetes. ## 1) Add a Deploy Button ```markdown theme={null} [![Deploy to StateSet](https://deploy.stateset.cloud.stateset.app/button.svg)](https://deploy.stateset.cloud.stateset.app/deploy?repo=stateset/stateset-acp-handler) ``` ## 2) (Optional) Add `stateset.yaml` ```yaml theme={null} name: stateset-acp-handler description: ACP handler service build: dockerfile: Dockerfile context: . runtime: port: 8080 health_check: /health readiness_check: /ready ``` ## 3) Configure Environment Variables Use `stateset.yaml` or the deploy UI to set required environment variables for the handler. Refer to the handler README for the latest list. ## 4) Deploy Click the deploy button, authenticate with GitHub, and wait for the deployment to complete. Your app will be available at: ``` https://{app-name}.{slug}.cloud.stateset.app ``` ## Related Documentation * [ACP Handler README](/stateset-acp-handler/README) * [StateSet Deploy](/stateset-deploy/README) # Deploy the Response ChatGPT App Source: https://docs.stateset.com/stateset-deploy-chatgpt-app Use StateSet Deploy to ship the ChatGPT widget + MCP server. # Deploy the Response ChatGPT App Use StateSet Deploy to build and host the Response ChatGPT app and MCP server on managed Kubernetes. ## 1) Add a Deploy Button Add a deploy button to your repository README: ```markdown theme={null} [![Deploy to StateSet](https://deploy.stateset.cloud.stateset.app/button.svg)](https://deploy.stateset.cloud.stateset.app/deploy?repo=YOUR_ORG/YOUR_REPO) ``` ## 2) (Optional) Add `stateset.yaml` Create a `stateset.yaml` in the repo root to configure build/runtime: ```yaml theme={null} name: stateset-response-chatgpt-app description: Response ChatGPT widget + MCP server build: dockerfile: Dockerfile context: . runtime: port: 3030 health_check: /health readiness_check: /ready ``` ## 3) Deploy Click the deploy button, authenticate with GitHub, and wait for the build to finish. Your app will be available at: ``` https://{app-name}.{slug}.cloud.stateset.app ``` ## 4) Connect ChatGPT Use the app URL as your MCP SSE endpoint in ChatGPT: * `https://{app-name}.{slug}.cloud.stateset.app/mcp` ## Related Documentation * [Response ChatGPT App Guide](/stateset-response-chatgpt-guide) * [StateSet Deploy](/stateset-deploy/README) # StateSet Deploy Source: https://docs.stateset.com/stateset-deploy-overview One-click deployment service for commerce handlers, agents, and iCommerce apps on managed Kubernetes. # StateSet Deploy StateSet Deploy builds and hosts commerce handlers and iCommerce applications on managed Kubernetes infrastructure. Connect your GitHub repository and deploy with a single click. ## Features * **One-click deploy** — Push to GitHub, Deploy builds and ships automatically. * **Docker builds** — Builds container images from your repo's Dockerfile. * **Managed Kubernetes** — Runs on production-grade K8s with autoscaling and health checks. * **HTTPS by default** — TLS certificates provisioned automatically. * **Custom domains** — Point your own domain at a deployment. * **Persistent storage** — Attach volumes for databases, file uploads, or caches. * **Environment secrets** — Inject API keys and credentials securely. * **Deployment logs** — Stream build and runtime logs in the console. ## Supported Deployment Types | Type | Description | Example | | ------------------ | ------------------------------------------------------------- | ------------------------------------------------------ | | **ACP Handler** | Agentic Commerce Protocol handler for conversational checkout | [Deploy ACP Handler](/stateset-deploy-acp-handler) | | **ChatGPT App** | ChatGPT plugin powered by StateSet Response | [Deploy ChatGPT App](/stateset-deploy-chatgpt-app) | | **iCommerce App** | Full iCommerce application with agent sandbox | [iCommerce Quickstart](/stateset-icommerce-quickstart) | | **Custom Service** | Any Docker container with an HTTP endpoint | — | ## How It Works 1. **Connect** — Link your GitHub repository in the StateSet Console. 2. **Configure** — Set environment variables, resource limits, and domain. 3. **Deploy** — StateSet builds a Docker image, pushes it to the registry, and creates a Kubernetes deployment. 4. **Monitor** — View build logs, runtime metrics, and health status in the console. ## Quickstart ### Deploy from the Console 1. Go to **Dashboard > Deployments > New Deployment**. 2. Select your GitHub repository. 3. Configure environment variables (e.g., `STATESET_API_KEY`). 4. Click **Deploy**. ### Deploy via CLI ```bash theme={null} stateset deploy --repo https://github.com/your-org/your-app \ --env STATESET_API_KEY=$STATESET_API_KEY \ --domain your-app.stateset.cloud ``` ## Architecture ``` GitHub Push → Build (Docker) → Registry → Kubernetes Deployment │ ├── HTTPS Ingress ├── Autoscaling ├── Health Checks └── Persistent Storage ``` ## Related Documentation * [Deploy README](/stateset-deploy/README) * [Deploy ACP Handler](/stateset-deploy-acp-handler) * [Deploy ChatGPT App](/stateset-deploy-chatgpt-app) * [Cloud API Reference](/cloud-api-reference/overview) # StateSet iCommerce Quickstart Source: https://docs.stateset.com/stateset-icommerce-quickstart Getting started guide for AI agents using the StateSet iCommerce engine # StateSet iCommerce Quickstart This guide helps AI agents get up and running with the StateSet iCommerce engine in minutes. ## Overview StateSet iCommerce provides: * **Embedded Commerce Engine** - Local SQLite database with 70+ tables * **Autonomous Agent Runtime** - Scheduled jobs, workflows, policies * **Multi-Agent Coordination** - Verifiable Event Sync (VES) via sequencer * **90+ MCP Tools** - Full commerce operations accessible to agents ## Prerequisites * Node.js 18+ * npm or yarn * Anthropic API key (for Claude-powered agents) ## Step 1: Install the CLI ```bash theme={null} npm install -g @stateset/cli ``` Verify installation: ```bash theme={null} stateset --version ``` ## Step 2: Register Your Agent Register with the sequencer to get an API key for multi-agent coordination: ```bash theme={null} curl -X POST https://api.sequencer.stateset.app/api/v1/agents/register \ -H "Content-Type: application/json" \ -d '{ "name": "my-commerce-agent", "description": "Autonomous commerce agent" }' ``` Response: ```json theme={null} { "success": true, "agentId": "550e8400-e29b-41d4-a716-446655440000", "tenantId": "660e8400-e29b-41d4-a716-446655440001", "apiKey": "ss_660e8400aBcDeFgHiJkLmNoPqRsTuVwXyZ", "permissions": "read_write", "message": "Agent registered successfully. Store your API key securely." } ``` **Save your API key** - it's only shown once. ## Step 3: Initialize Commerce Database ```bash theme={null} # Create database with demo data stateset init --demo # Or create empty database stateset init ``` This creates `~/.stateset/commerce.db` with: * 70+ commerce tables (orders, customers, products, inventory, etc.) * Demo data (if `--demo` flag used) * Sync outbox for VES events ## Step 4: Configure Sync Create `~/.stateset/sync-config.json`: ```json theme={null} { "tenantId": "", "storeId": "00000000-0000-0000-0000-000000000001", "agentId": "", "sequencerEndpoint": "https://api.sequencer.stateset.app", "apiKey": "", "transport": "rest", "conflictStrategy": "remote-wins" } ``` Verify connection: ```bash theme={null} stateset-sync status ``` ## Step 5: Run Your First Agent Command ### Read-Only Query ```bash theme={null} stateset "List all customers" ``` ### Write Operation ```bash theme={null} stateset --apply "Create a customer named Alice Smith with email alice@example.com" ``` ### With Sync (Multi-Agent) ```bash theme={null} stateset --apply --sync "Create an order for customer alice@example.com" ``` ## Step 6: Start Autonomous Engine Run the full autonomous engine with scheduled jobs and workflows: ```bash theme={null} stateset-autonomous start --init-defaults --verbose ``` Output: ``` 📦 Initializing commerce engine... 🚀 Starting autonomous engine... 📊 Engine Status: Scheduler: ✅ Running (7 jobs) Workflows: ✅ Ready (4 definitions) Policies: ✅ Loaded (15 policy sets) Webhooks: ✅ Listening on port 3000 Approvals: ✅ Ready ✨ Autonomous engine is running! ``` *** ## Agent Commands Reference ### Customer Operations ```bash theme={null} stateset "List customers" stateset --apply "Create customer John Doe with email john@example.com" stateset "Get customer by email john@example.com" ``` ### Order Operations ```bash theme={null} stateset "List pending orders" stateset --apply "Create order for customer john@example.com with SKU-001 quantity 2" stateset --apply "Ship order ORD-123 with tracking 1Z999AA10123456784" ``` ### Inventory Operations ```bash theme={null} stateset "Check stock for SKU-001" stateset --apply "Adjust inventory for SKU-001 add 100 units" stateset --apply "Reserve 5 units of SKU-001 for order ORD-123" ``` ### Returns Operations ```bash theme={null} stateset "List pending returns" stateset --apply "Create return for order ORD-123 reason defective" stateset --apply "Approve return RET-456" ``` ### Sync Operations ```bash theme={null} stateset-sync status # Check sync health stateset-sync push # Push local events to sequencer stateset-sync pull # Pull remote events stateset-sync history # View sync history ``` *** ## Programmatic Usage (Node.js) ```javascript theme={null} import { Commerce } from '@stateset/embedded'; import { runAgentLoop } from '@stateset/cli/src/claude-harness.js'; // Initialize commerce engine const commerce = new Commerce('~/.stateset/commerce.db'); // Run agent task const result = await runAgentLoop({ commerce, request: "Create an order for alice@example.com", allowApply: true, // Enable write operations enableSync: true, // Capture events for sync autoSyncPush: true, // Auto-push to sequencer maxTurns: 10 }); console.log(result.response); ``` *** ## Multi-Agent Coordination ### How Agents Coordinate ``` Agent A (Orders) Sequencer Agent B (Inventory) │ │ │ │ 1. Create Order │ │ │──────────────────────────>│ │ │ │ │ │ 2. Sign & Commit │ │ │──────────────────────────>│ │ │ │ 3. Broadcast Event │ │ │──────────────────────────>│ │ │ │ │ │ 4. Reserve Inventory │ │ │<──────────────────────────│ │ │ │ │ 5. Receive Confirmation │ │ │<──────────────────────────│ │ ``` ### Running Multiple Agents **Terminal 1 - Order Agent:** ```bash theme={null} export STATESET_AGENT_NAME="order-agent" stateset-autonomous start --db ./order-agent.db --port 3001 ``` **Terminal 2 - Inventory Agent:** ```bash theme={null} export STATESET_AGENT_NAME="inventory-agent" stateset-autonomous start --db ./inventory-agent.db --port 3002 ``` Both agents sync through the sequencer and coordinate automatically. *** ## Autonomous Engine Features ### Scheduled Jobs ```bash theme={null} # List jobs stateset-autonomous jobs # Run job manually stateset-autonomous jobs --run process-orders # Enable/disable job stateset-autonomous jobs --enable low-stock-alerts ``` ### Default Jobs | Job | Schedule | Description | | ----------------- | ------------ | ---------------------- | | `process-orders` | Every 5 min | Process pending orders | | `check-inventory` | Hourly | Check low stock levels | | `sync-events` | Every 10 min | Sync with sequencer | | `cleanup-carts` | Daily | Abandon old carts | ### Workflows Pre-configured workflows for: * Order fulfillment lifecycle * Return processing * Subscription billing * Inventory replenishment ### Policies 15 policy sets covering: * Order value limits * Inventory thresholds * Return windows * Discount rules *** ## Environment Variables ```bash theme={null} # Required export ANTHROPIC_API_KEY=sk-ant-... # Optional export STATESET_DB_PATH=~/.stateset/commerce.db export STATESET_SYNC_ENDPOINT=https://api.sequencer.stateset.app export STATESET_API_KEY=ss_... export STATESET_LOG_LEVEL=info ``` *** ## Troubleshooting ### Database not found ```bash theme={null} stateset init --demo ``` ### Sync not connecting ```bash theme={null} # Check config cat ~/.stateset/sync-config.json # Test connection stateset-sync status ``` ### Agent not responding ```bash theme={null} # Check API key echo $ANTHROPIC_API_KEY # Run with verbose stateset "test" --verbose ``` *** ## Next Steps 1. **Explore the CLI** - Run `stateset --help` for all commands 2. **Customize Agents** - Edit `.claude/agents/*.md` for agent personalities 3. **Add Workflows** - Create custom workflows in `.stateset/autonomous/` 4. **Enable Webhooks** - Configure external integrations 5. **Scale Up** - Run multiple agents with different specializations *** ## Quick Reference | Command | Description | | -------------------------------- | ------------------------------ | | `stateset init` | Initialize commerce database | | `stateset "query"` | Run agent query (read-only) | | `stateset --apply "task"` | Run agent task (write enabled) | | `stateset --apply --sync "task"` | Run with multi-agent sync | | `stateset-autonomous start` | Start autonomous engine | | `stateset-sync status` | Check sync health | | `stateset-sync push` | Push events to sequencer | | `stateset-sync pull` | Pull events from sequencer | *** ## API Endpoints | Endpoint | Purpose | | -------------------------------- | ------------------ | | `POST /api/v1/agents/register` | Register new agent | | `POST /api/v1/ves/events/ingest` | Ingest VES events | | `GET /api/v1/events` | List events | | `POST /api/v1/ves/commitments` | Create commitment | | `GET /health` | Health check | Base URL: `https://api.sequencer.stateset.app` *** *StateSet iCommerce Engine v0.3.2* *January 2026* # null Source: https://docs.stateset.com/stateset-icommerce-skill Infrastructure for autonomous commerce. Embedded engine, verifiable sync, on-chain settlement, x402 payments, and multi-channel messaging. # StateSet iCommerce Engine Infrastructure for autonomous commerce. Embedded engine, verifiable sync, on-chain settlement, x402 payments, and multi-channel messaging. ## Skill Files | File | URL | | ------------------------ | ------------------------------------------------------ | | **SKILL.md** (this file) | `https://doc.stateset.com/stateset-icommerce-skill.md` | **Or just read them from the URLs above!** **Check for updates:** Re-fetch these files anytime to see new features! *** ## API Base URLs | Service | Base URL | Purpose | | ------------------- | -------------------------------------------- | ------------------------------------------------------ | | **Commerce Engine** | Local (embedded) | Core commerce operations (orders, products, customers) | | **Sequencer** | `https://api.sequencer.stateset.app/v1` | VES event ordering, proofs, commitments | | **VES (Sequencer)** | `https://api.sequencer.stateset.app/v1/ves` | VES v1.0 protocol endpoints | | **x402 Payments** | `https://api.sequencer.stateset.app/v1/x402` | Payment intents, batches, settlements | **Environment Variables:** ```bash theme={null} export STATESET_API_KEY=sk_live_xxx export STATESET_SEQUENCER_URL=https://api.sequencer.stateset.app/v1 ``` *** ## Architecture Overview StateSet iCommerce is a five-layer infrastructure stack: | Layer | Component | Function | | ----------------- | ------------------ | ------------------------------- | | **Compute** | stateset-embedded | In-process commerce engine | | **Coordination** | stateset-sequencer | Distributed event ordering | | **Settlement** | Set Chain (L2) | On-chain verification | | **Payments** | x402 Protocol | HTTP-native stablecoin payments | | **Communication** | Messaging Gateway | 9-channel agent interaction | *** ## Install the CLI ```bash theme={null} npm install -g @stateset/cli ``` Verify installation: ```bash theme={null} stateset --version ``` **Recommended:** Save your credentials to `~/.config/stateset/config.json`: ```json theme={null} { "api_key": "sk_live_xxx", "tenant_id": "your-tenant-id", "store_id": "your-store-id", "database_path": "~/.stateset/commerce.db" } ``` *** ## Initialize the Engine Create a new commerce database: ```bash theme={null} stateset init --demo ``` This creates `~/.stateset/commerce.db` with: * SQLite database with 70+ tables * Demo data (customers, products, inventory) * Sync outbox ready for VES **Without demo data:** ```bash theme={null} stateset init ``` *** ## Authentication Commerce operations run locally via the embedded engine. Sequencer API requests require your API key: ```bash theme={null} curl https://api.sequencer.stateset.app/v1/events \ -H "Authorization: Bearer YOUR_API_KEY" ``` For CLI operations: ```bash theme={null} export STATESET_API_KEY=sk_live_xxx stateset orders list # Local embedded engine stateset sync push # Syncs to sequencer API ``` *** ## Agent Registration AI agents must register with the sequencer to receive an API key for authentication. ### Register a New Agent ```bash theme={null} curl -X POST https://api.sequencer.stateset.app/v1/agents/register \ -H "Content-Type: application/json" \ -d '{ "name": "my-commerce-agent", "description": "Autonomous commerce agent for order processing" }' ``` **Response:** ```json theme={null} { "success": true, "agentId": "550e8400-e29b-41d4-a716-446655440000", "tenantId": "660e8400-e29b-41d4-a716-446655440001", "apiKey": "ss_660e8400aBcDeFgHiJkLmNoPqRsTuVwXyZ", "permissions": "read_write", "message": "Agent registered successfully. Store your API key securely - it cannot be retrieved later." } ``` **Important:** Store the `apiKey` securely. It is only returned once and cannot be retrieved later. ### Registration Options | Field | Type | Description | | ------------- | ------- | -------------------------------------- | | `name` | string | Human-readable agent name (required) | | `description` | string | Agent purpose description | | `tenantId` | UUID | Join existing tenant (optional) | | `storeIds` | UUID\[] | Restrict to specific stores | | `readOnly` | boolean | Read-only permissions (default: false) | | `admin` | boolean | Admin permissions (default: false) | | `rateLimit` | number | Requests per minute limit | ### Get Agent Details ```bash theme={null} curl https://api.sequencer.stateset.app/v1/agents/{agent_id} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Create Additional API Keys ```bash theme={null} curl -X POST https://api.sequencer.stateset.app/v1/agents/{agent_id}/api-keys \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "readOnly": true }' ``` ### List API Keys ```bash theme={null} curl https://api.sequencer.stateset.app/v1/agents/{agent_id}/api-keys \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Revoke an API Key ```bash theme={null} curl -X DELETE https://api.sequencer.stateset.app/v1/agents/{agent_id}/api-keys/{key_prefix} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Register Signing Key (for VES Events) After registration, agents should register an Ed25519 signing key for VES event signatures: ```bash theme={null} curl -X POST https://api.sequencer.stateset.app/v1/agents/keys \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "tenantId": "660e8400-e29b-41d4-a716-446655440001", "agentId": "550e8400-e29b-41d4-a716-446655440000", "keyId": 1, "publicKey": "0x1234567890abcdef...", "validFrom": "2026-01-30T00:00:00Z", "validTo": "2027-01-30T00:00:00Z" }' ``` *** ## Core Operations ### Customers ```bash theme={null} # List customers stateset customers list # Create customer stateset customers create --email "alice@example.com" --name "Alice Smith" # Get customer by email stateset customers get --email "alice@example.com" ``` **Embedded API (local):** ```javascript theme={null} const customer = commerce.customers.create({ email: 'alice@example.com', name: 'Alice Smith' }); ``` ### Products ```bash theme={null} # List products stateset products list # Create product stateset products create --sku "SHOE-001" --name "Running Shoes" --price 99.99 # Get product by SKU stateset products get --sku "SHOE-001" ``` ### Inventory ```bash theme={null} # Check stock stateset inventory get --sku "SHOE-001" # Adjust inventory stateset inventory adjust --sku "SHOE-001" --quantity 100 --reason "Initial stock" # Reserve inventory stateset inventory reserve --sku "SHOE-001" --quantity 5 --reference "ORD-123" ``` ### Orders ```bash theme={null} # List orders stateset orders list # Create order stateset orders create --customer-email "alice@example.com" --items '[{"sku":"SHOE-001","qty":2}]' # Get order stateset orders get --id "ord_xxx" # Ship order stateset orders ship --id "ord_xxx" --carrier "fedex" --tracking "1234567890" ``` ### Returns ```bash theme={null} # Create return stateset returns create --order-id "ord_xxx" --reason "Defective" --items '[{"sku":"SHOE-001","qty":1}]' # Approve return stateset returns approve --id "ret_xxx" # Complete return stateset returns complete --id "ret_xxx" ``` *** ## Checkout Flow ### Cart Operations ```bash theme={null} # Create cart stateset carts create --customer-email "alice@example.com" # Add item to cart stateset carts add-item --cart-id "cart_xxx" --sku "SHOE-001" --quantity 2 # Get cart stateset carts get --id "cart_xxx" # Checkout stateset carts checkout --id "cart_xxx" --payment-method "card" ``` ### Complete Checkout Flow ```bash theme={null} # 1. Create cart CART_ID=$(stateset carts create --customer-email "alice@example.com" --json | jq -r '.id') # 2. Add items stateset carts add-item --cart-id $CART_ID --sku "SHOE-001" --quantity 2 # 3. Apply promotion (optional) stateset carts apply-coupon --cart-id $CART_ID --code "SAVE10" # 4. Calculate tax stateset carts calculate-tax --cart-id $CART_ID # 5. Checkout stateset carts checkout --cart-id $CART_ID --payment-method "card" ``` *** ## x402 Payments HTTP-native stablecoin micropayments between AI agents. ### Supported Networks | Network | Chain ID | Assets | Status | | --------- | -------- | ----------- | ---------- | | Set Chain | 84532001 | ssUSD, USDC | Production | | Base | 8453 | USDC | Production | | Ethereum | 1 | USDC, USDT | Production | | Arbitrum | 42161 | USDC | Production | | Optimism | 10 | USDC | Production | | Solana | — | USDC | Production | ### Create Payment Intent ```bash theme={null} stateset-pay create \ --amount "10.00" \ --asset "USDC" \ --network "base" \ --recipient "0x..." ``` ### Check Balance ```bash theme={null} stateset-pay balance --network base ``` ### Payment Flow ``` 1. GET /api/products/123 → HTTP 402 Payment Required → { asset: "USDC", amount: "0.001", network: "set-chain", recipient: "0x..." } 2. Agent signs PaymentIntent (Ed25519) 3. GET /api/products/123 X-Payment: → 200 OK X-Payment-Receipt: ``` *** ## Verifiable Event Sync (VES) Multi-agent coordination with cryptographic proofs. ### Check Sync Status ```bash theme={null} stateset sync status ``` Response: ```json theme={null} { "local_head": 1523, "remote_head": 1520, "pending_events": 3, "last_sync": "2026-01-30T10:15:00Z" } ``` ### Push Events ```bash theme={null} stateset sync push ``` ### Pull Events ```bash theme={null} stateset sync pull ``` ### Full Sync ```bash theme={null} stateset sync full ``` ### View Outbox ```bash theme={null} stateset sync outbox ``` ### Entity History ```bash theme={null} stateset sync history --entity-type order --entity-id "ord_xxx" ``` *** ## Sequencer API Reference The StateSet Sequencer provides deterministic event ordering with cryptographic proofs for multi-agent coordination. **Base URL:** `https://api.sequencer.stateset.app` ### Authentication All sequencer requests require Bearer token authentication: ```bash theme={null} curl https://api.sequencer.stateset.app/v1/events \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Event Ingestion **Ingest VES Events (Recommended)** ```bash theme={null} POST https://api.sequencer.stateset.app/v1/ves/events/ingest Content-Type: application/json { "events": [ { "event_id": "evt_xxx", "event_type": "order.created", "entity_type": "order", "entity_id": "ord_xxx", "payload": {...}, "signature": "ed25519_signature" } ] } ``` **Legacy Event Ingestion** ```bash theme={null} POST https://api.sequencer.stateset.app/v1/events/ingest ``` ### Events & Head ```bash theme={null} # List events GET https://api.sequencer.stateset.app/v1/events # Get head sequence number GET https://api.sequencer.stateset.app/v1/head # Get entity history GET https://api.sequencer.stateset.app/v1/entities/{entity_type}/{entity_id} ``` ### VES Commitments ```bash theme={null} # List all commitments GET https://api.sequencer.stateset.app/v1/ves/commitments # Create new commitment POST https://api.sequencer.stateset.app/v1/ves/commitments # Create and anchor commitment POST https://api.sequencer.stateset.app/v1/ves/commitments/anchor # Get specific commitment GET https://api.sequencer.stateset.app/v1/ves/commitments/{batch_id} ``` ### VES Validity Proofs (STARK ZK Proofs) ```bash theme={null} # Get public inputs for proof generation GET https://api.sequencer.stateset.app/v1/ves/validity/{batch_id}/inputs # List proofs for batch GET https://api.sequencer.stateset.app/v1/ves/validity/{batch_id}/proofs # Submit external STARK proof POST https://api.sequencer.stateset.app/v1/ves/validity/{batch_id}/proofs Content-Type: application/json { "proof_data": "base64_encoded_proof", "prover": "agent_address" } # Get specific proof GET https://api.sequencer.stateset.app/v1/ves/validity/proofs/{proof_id} # Verify proof GET https://api.sequencer.stateset.app/v1/ves/validity/proofs/{proof_id}/verify ``` ### VES Compliance Proofs (Per-Event Encrypted) ```bash theme={null} # Get compliance inputs for event POST https://api.sequencer.stateset.app/v1/ves/compliance/{event_id}/inputs # List compliance proofs for event GET https://api.sequencer.stateset.app/v1/ves/compliance/{event_id}/proofs # Submit compliance proof POST https://api.sequencer.stateset.app/v1/ves/compliance/{event_id}/proofs # Get specific compliance proof GET https://api.sequencer.stateset.app/v1/ves/compliance/proofs/{proof_id} # Verify compliance proof GET https://api.sequencer.stateset.app/v1/ves/compliance/proofs/{proof_id}/verify ``` ### Inclusion Proofs ```bash theme={null} # Get inclusion proof for sequence number GET https://api.sequencer.stateset.app/v1/ves/proofs/{sequence_number} # Verify inclusion proof POST https://api.sequencer.stateset.app/v1/ves/proofs/verify Content-Type: application/json { "sequence_number": 1523, "merkle_proof": {...} } ``` ### On-Chain Anchoring ```bash theme={null} # Anchor commitment to Set Chain L2 POST https://api.sequencer.stateset.app/v1/ves/anchor Content-Type: application/json { "batch_id": "batch_xxx" } # Verify on-chain anchor GET https://api.sequencer.stateset.app/v1/ves/anchor/{batch_id}/verify ``` ### Agent Key Management ```bash theme={null} # Register agent signing key POST https://api.sequencer.stateset.app/v1/agents/keys Content-Type: application/json { "agent_id": "agent_xxx", "public_key": "ed25519_pubkey", "permissions": ["read", "write"] } ``` ### Schema Registry ```bash theme={null} # List all schemas GET https://api.sequencer.stateset.app/v1/schemas # Register new schema POST https://api.sequencer.stateset.app/v1/schemas Content-Type: application/json { "event_type": "order.created", "schema": {...} } # Validate payload against schema POST https://api.sequencer.stateset.app/v1/schemas/validate # Get schema by ID GET https://api.sequencer.stateset.app/v1/schemas/{schema_id} # Update schema status PUT https://api.sequencer.stateset.app/v1/schemas/{schema_id}/status # Delete schema DELETE https://api.sequencer.stateset.app/v1/schemas/{schema_id} # List schemas by event type GET https://api.sequencer.stateset.app/v1/schemas/event-type/{event_type} # Get latest schema for event type GET https://api.sequencer.stateset.app/v1/schemas/event-type/{event_type}/latest ``` ### x402 Sequencer Payments ```bash theme={null} # Submit payment intent POST https://api.sequencer.stateset.app/v1/x402/payments Content-Type: application/json { "amount": "10.00", "asset": "USDC", "network": "base", "recipient": "0x...", "sender": "0x..." } # Get payment status GET https://api.sequencer.stateset.app/v1/x402/payments/{intent_id} # Get payment receipt GET https://api.sequencer.stateset.app/v1/x402/payments/{intent_id}/receipt # Get batch status GET https://api.sequencer.stateset.app/v1/x402/batches/{batch_id} # Settle payment batch POST https://api.sequencer.stateset.app/v1/x402/batches/settle ``` ### Health & Status ```bash theme={null} # Basic health check GET https://api.sequencer.stateset.app/health # Readiness check (includes DB) GET https://api.sequencer.stateset.app/ready # Detailed component health GET https://api.sequencer.stateset.app/health/detailed ``` ### Legacy Endpoints ```bash theme={null} # Legacy commitments GET https://api.sequencer.stateset.app/v1/commitments POST https://api.sequencer.stateset.app/v1/commitments GET https://api.sequencer.stateset.app/v1/commitments/{batch_id} # Legacy proofs GET https://api.sequencer.stateset.app/v1/proofs/{sequence_number} POST https://api.sequencer.stateset.app/v1/proofs/verify # Legacy anchoring GET https://api.sequencer.stateset.app/v1/anchor/status POST https://api.sequencer.stateset.app/v1/anchor GET https://api.sequencer.stateset.app/v1/anchor/{batch_id}/verify ``` *** ## Agent Integration Patterns ### Full Sync Flow for Agents ```bash theme={null} # 1. Ingest local commerce events to sequencer curl -X POST https://api.sequencer.stateset.app/v1/ves/events/ingest \ -H "Authorization: Bearer $STATESET_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "events": [{ "event_id": "evt_001", "event_type": "order.created", "entity_type": "order", "entity_id": "ord_xxx", "payload": {"customer_id": "cust_xxx", "total": 99.99} }] }' # 2. Get sequencer receipt with sequence number # Response includes: sequence_number, merkle_root, signature # 3. Create commitment batch curl -X POST https://api.sequencer.stateset.app/v1/ves/commitments \ -H "Authorization: Bearer $STATESET_API_KEY" # 4. Anchor to Set Chain curl -X POST https://api.sequencer.stateset.app/v1/ves/anchor \ -H "Authorization: Bearer $STATESET_API_KEY" \ -d '{"batch_id": "batch_xxx"}' # 5. Verify on-chain curl https://api.sequencer.stateset.app/v1/ves/anchor/batch_xxx/verify \ -H "Authorization: Bearer $STATESET_API_KEY" ``` ### Multi-Agent Coordination ```javascript theme={null} // Agent A: Create order and sync const order = await commerce.orders.create({...}); const receipt = await fetch('https://api.sequencer.stateset.app/v1/ves/events/ingest', { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify({ events: [{ event_type: 'order.created', entity_type: 'order', entity_id: order.id, payload: order }] }) }).then(r => r.json()); // Agent B: Pull events and verify const head = await fetch('https://api.sequencer.stateset.app/v1/head', { headers: { 'Authorization': `Bearer ${API_KEY}` } }).then(r => r.json()); const proof = await fetch(`https://api.sequencer.stateset.app/v1/ves/proofs/${receipt.sequence_number}`, { headers: { 'Authorization': `Bearer ${API_KEY}` } }).then(r => r.json()); ``` *** ## MCP Tool Integration The CLI exposes 700+ commerce operations via MCP for AI agents. ### Start MCP Server ```bash theme={null} stateset mcp serve ``` ### Tool Categories | Domain | Examples | | --------- | ------------------------------------------------- | | Customers | list\_customers, get\_customer, create\_customer | | Orders | create\_order, ship\_order, cancel\_order | | Products | list\_products, create\_product | | Inventory | get\_stock, adjust\_inventory, reserve\_inventory | | Returns | create\_return, approve\_return | | Carts | create\_cart, add\_cart\_item, checkout | | Payments | create\_payment, process\_refund | | Analytics | get\_sales\_summary, get\_demand\_forecast | | Sync | sync\_status, sync\_push, sync\_pull | ### Permission Model ```bash theme={null} # Read operations - always allowed stateset "list orders" # Write operations - blocked by default stateset "create an order" # → Shows preview, does not execute # Write operations - enabled with --apply stateset --apply "create an order for alice@example.com" # → Executes operation ``` *** ## Multi-Channel Messaging ### Supported Channels | Channel | Protocol | Status | | ----------- | ---------------- | ------------ | | WhatsApp | Cloud API | GA | | Telegram | Bot API | GA | | Discord | Gateway + REST | GA | | Slack | Events + Web API | GA | | Signal | signal-cli | GA | | Google Chat | Spaces API | GA | | WebChat | WebSocket | GA | | iMessage | AppleScript | Experimental | | Teams | Bot Framework | Experimental | ### Launch Channels ```bash theme={null} # All configured channels stateset-channels # Specific channels stateset-whatsapp stateset-discord stateset-telegram stateset-slack ``` ### Configuration Create `~/.stateset/channels.json`: ```json theme={null} { "whatsapp": { "enabled": true, "phone_number_id": "xxx", "access_token": "xxx" }, "discord": { "enabled": true, "bot_token": "xxx", "guild_id": "xxx" } } ``` *** ## Warehouse Operations ### Warehouse Management ```bash theme={null} # Create warehouse stateset warehouse create --name "Main DC" --address "123 Warehouse Ave" # Add zone stateset warehouse add-zone --warehouse-id "wh_xxx" --name "Picking Zone A" # Add location stateset warehouse add-location --zone-id "zone_xxx" --name "A-01-01" ``` ### Fulfillment ```bash theme={null} # Create wave stateset fulfillment create-wave --warehouse-id "wh_xxx" --orders '["ord_xxx", "ord_yyy"]' # Assign pick task stateset fulfillment assign-pick --task-id "pick_xxx" --picker "user_xxx" # Complete pick stateset fulfillment complete-pick --task-id "pick_xxx" # Pack stateset fulfillment pack --wave-id "wave_xxx" # Ship stateset fulfillment ship --wave-id "wave_xxx" ``` ### Receiving ```bash theme={null} # Create receipt stateset receiving create --po-id "po_xxx" --expected-date "2026-02-01" # Receive items stateset receiving receive-items --receipt-id "rec_xxx" --items '[{"sku":"SHOE-001","qty":100}]' # Put away stateset receiving put-away --receipt-id "rec_xxx" --location "A-01-01" ``` *** ## Financial Operations ### General Ledger ```bash theme={null} # Create account stateset gl create-account --number "1000" --name "Cash" --type "asset" # Post journal entry stateset gl post-entry --debit '{"account":"1000","amount":100}' --credit '{"account":"4000","amount":100}' # Trial balance stateset gl trial-balance # Close period stateset gl close-period --period "2026-01" ``` ### Accounts Receivable ```bash theme={null} # AR aging stateset ar aging # Apply payment stateset ar apply-payment --customer-id "cust_xxx" --amount 500 --invoice-id "inv_xxx" # Generate statement stateset ar generate-statement --customer-id "cust_xxx" ``` ### Accounts Payable ```bash theme={null} # Create bill stateset ap create-bill --supplier-id "sup_xxx" --amount 1000 --due-date "2026-02-15" # Schedule payment stateset ap schedule-payment --bill-id "bill_xxx" --date "2026-02-10" # AP aging stateset ap aging ``` *** ## Vector Search Hybrid semantic + BM25 search across commerce entities. ```bash theme={null} # Index products stateset vector index-products # Search products stateset vector search --query "red running shoes under $100" --limit 10 # Index customers stateset vector index-customers # Search customers stateset vector search-customers --query "enterprise accounts in California" ``` *** ## Heartbeat Monitor Proactive health checking for commerce operations. ### Built-in Checkers | Checker | Trigger | Action | | -------------------- | --------------------- | ----------------------- | | `low-stock` | Stock below threshold | Alert, auto-reorder | | `abandoned-carts` | Cart idle > timeout | Recovery notification | | `revenue-milestone` | Target reached/missed | Dashboard alert | | `pending-returns` | Return aging > days | Escalation | | `overdue-invoices` | Invoice past due | Collection notification | | `subscription-churn` | Cancellation spike | Retention campaign | ### CLI ```bash theme={null} # Health status stateset heartbeat status # Trigger check stateset heartbeat run low-stock # Enable/disable checker stateset heartbeat enable low-stock stateset heartbeat disable low-stock ``` *** ## Skills System 38 built-in skills covering the full commerce lifecycle. ### Install Skills ```bash theme={null} npm install -g @stateset/icommerce-skills icommerce-skills list icommerce-skills install ``` ### Skill Categories **Core Commerce:** * commerce-engine-setup * commerce-embedded-sdk * commerce-customers * commerce-products * commerce-orders * commerce-checkout * commerce-payments **Inventory & Fulfillment:** * commerce-inventory * commerce-shipments * commerce-returns * commerce-backorders * commerce-fulfillment * commerce-receiving * commerce-warehouse * commerce-lots-and-serials **Financial:** * commerce-invoices * commerce-tax * commerce-currency * commerce-accounts-payable * commerce-accounts-receivable * commerce-cost-accounting * commerce-credit * commerce-general-ledger **Platform:** * commerce-sync * commerce-autonomous-engine * commerce-vector-search * commerce-mcp-tools *** ## Language Bindings The Rust core compiles to 10 target runtimes: | Runtime | Technology | Use Case | | ----------- | -------------- | ------------------------- | | Native Rust | Direct linking | High-performance backends | | Node.js | NAPI-RS | JavaScript/TypeScript | | Python | PyO3 | Data science, ML | | Browser | wasm-pack | Client-side | | Ruby | Magnus | Rails | | PHP | ext-php-rs | Laravel/WordPress | | Java | JNI | Enterprise JVM | | Kotlin | JNI | Android, server | | Swift | C FFI | iOS/macOS | | .NET/C# | P/Invoke | ASP.NET, Unity | | Go | cgo | Go microservices | ### Node.js Example ```javascript theme={null} const { Commerce } = require('@stateset/embedded'); const commerce = new Commerce('~/.stateset/commerce.db'); // Create customer const customer = commerce.customers.create({ email: 'alice@example.com', name: 'Alice Smith' }); // Create order const order = commerce.orders.create({ customerId: customer.id, items: [{ sku: 'SHOE-001', quantity: 2 }] }); console.log(`Order created: ${order.id}`); ``` ### Python Example ```python theme={null} from stateset_embedded import Commerce commerce = Commerce('~/.stateset/commerce.db') # Create customer customer = commerce.customers.create( email='alice@example.com', name='Alice Smith' ) # Create order order = commerce.orders.create( customer_id=customer.id, items=[{'sku': 'SHOE-001', 'quantity': 2}] ) print(f'Order created: {order.id}') ``` *** ## Response Format Success: ```json theme={null} {"success": true, "data": {...}} ``` Error: ```json theme={null} {"success": false, "error": "Description", "hint": "How to fix"} ``` *** ## Rate Limits | Limit | Value | | ---------------- | ----------- | | API requests | 1000/minute | | Write operations | 100/minute | | Sync operations | 10/minute | | Vector search | 100/minute | *** ## System Statistics | Component | Metric | Value | | ----------------------- | ------------- | --------- | | stateset-core | Lines of Code | \~45,000 | | stateset-db | Lines of Code | \~55,000 | | stateset-embedded | Lines of Code | \~39,000 | | stateset-sequencer | Lines of Code | \~33,000 | | Total Rust | Lines of Code | \~172,000 | | Domain Modules | Count | 32 | | Domain Types | Count | 400+ | | Database Tables | Count | 70+ | | Commerce API Methods | Count | 700+ | | Sequencer API Endpoints | Count | 40+ | | Language Bindings | Count | 10 | | Commerce Skills | Count | 38 | | Messaging Channels | Count | 9 | *** ## Everything You Can Do | Action | What it does | | --------------------- | ------------------------------------------ | | **Create orders** | Process commerce transactions | | **Manage inventory** | Track stock, reservations, adjustments | | **Process returns** | Handle RMAs and refunds | | **Run fulfillment** | Pick, pack, ship workflows | | **Accept payments** | x402 stablecoin payments | | **Sync events** | VES multi-agent coordination via sequencer | | **Generate proofs** | Merkle inclusion + STARK ZK proofs | | **Anchor on-chain** | Set Chain L2 commitment anchoring | | **Register schemas** | Event type validation | | **Search products** | Hybrid semantic + keyword search | | **Message customers** | 9-channel omnichannel support | | **Run analytics** | Sales reports, forecasts | | **Manage finances** | GL, AP, AR, tax | *** ## Quick Reference ### CLI Commands ```bash theme={null} # Engine stateset init [--demo] stateset status # Customers stateset customers list|get|create|update|delete # Products stateset products list|get|create|update|delete # Inventory stateset inventory get|adjust|reserve|release # Orders stateset orders list|get|create|ship|cancel # Returns stateset returns list|get|create|approve|complete # Sync stateset sync status|push|pull|full|outbox # Payments stateset-pay create|balance|verify # Channels stateset-channels stateset-whatsapp|discord|telegram|slack ``` ### Sequencer API Quick Reference ```bash theme={null} # Base URL: https://api.sequencer.stateset.app # Events POST /v1/ves/events/ingest # Ingest VES events GET /v1/events # List events GET /v1/head # Get head sequence GET /v1/entities/{type}/{id} # Entity history # VES Commitments GET /v1/ves/commitments # List commitments POST /v1/ves/commitments # Create commitment POST /v1/ves/commitments/anchor # Commit and anchor GET /v1/ves/commitments/{batch_id} # Get commitment # VES Validity Proofs GET /v1/ves/validity/{batch_id}/inputs # Get proof inputs GET /v1/ves/validity/{batch_id}/proofs # List proofs POST /v1/ves/validity/{batch_id}/proofs # Submit proof GET /v1/ves/validity/proofs/{id}/verify # Verify proof # VES Compliance Proofs POST /v1/ves/compliance/{event_id}/inputs # Get inputs GET /v1/ves/compliance/{event_id}/proofs # List proofs POST /v1/ves/compliance/{event_id}/proofs # Submit proof # Inclusion Proofs GET /v1/ves/proofs/{sequence_number} # Get proof POST /v1/ves/proofs/verify # Verify proof # Anchoring POST /v1/ves/anchor # Anchor to chain GET /v1/ves/anchor/{batch_id}/verify # Verify on-chain # Agent Registration POST /v1/agents/register # Register new agent (get API key) GET /v1/agents/{agent_id} # Get agent details POST /v1/agents/{agent_id}/api-keys # Create additional API key GET /v1/agents/{agent_id}/api-keys # List agent's API keys DELETE /v1/agents/{agent_id}/api-keys/{pfx} # Revoke API key # Agent Signing Keys POST /v1/agents/keys # Register signing key # Schemas GET /v1/schemas # List schemas POST /v1/schemas # Register schema POST /v1/schemas/validate # Validate payload GET /v1/schemas/event-type/{type}/latest # Latest schema # x402 Payments POST /v1/x402/payments # Submit intent GET /v1/x402/payments/{id} # Get status GET /v1/x402/payments/{id}/receipt # Get receipt POST /v1/x402/batches/settle # Settle batch # Health GET /health # Basic health GET /ready # Readiness GET /health/detailed # Component health ``` *** ## Ideas to Try * Register your AI agent with the sequencer to get an API key * Set up the embedded engine with demo data * Create a multi-step order flow with cart → checkout → fulfillment * Configure VES sync between multiple agents using the sequencer * Enable x402 payments for agent-to-agent commerce * Ingest events and generate inclusion proofs via sequencer API * Anchor commitments on-chain and verify with STARK proofs * Register custom event schemas for domain-specific events * Set up WhatsApp or Discord for customer support * Run vector search for product discovery * Configure heartbeat monitors for low-stock alerts * Build a storefront with `stateset scaffold` *** *StateSet iCommerce v0.3.2* *January 2026* # StateSet iCommerce Agent Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-agent Agent patterns for operating the iCommerce engine safely. # StateSet iCommerce Agent The iCommerce agent pattern combines the embedded engine, MCP tools, and the CLI safety model so autonomous workflows stay deterministic and auditable. ## Core Capabilities * Order lookup, fulfillment, and refunds * Inventory checks and adjustments * Returns and warranty workflows * Deterministic write actions with explicit confirmation ## Safety Model * Read-only by default * Writes require explicit intent (`--apply`) * Guardrails and confirmations for sensitive actions ## How Agents Operate 1. Gather context (orders, inventory, customer history) 2. Propose a plan or action 3. Execute with explicit write intent 4. Log and report outcomes ## Related Documentation * [CLI Safety Model](/stateset-icommerce-cli-safety) * [CLI Workflows](/stateset-icommerce-cli-workflows) * [iCommerce Scenarios](/stateset-icommerce-scenarios) # Running the iCommerce Agent in Sandbox Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-agent-sandbox How to execute iCommerce agent workflows inside StateSet Sandbox. # Running the iCommerce Agent in Sandbox This guide explains how to run the iCommerce agent inside StateSet Sandbox for secure, isolated execution. ## Why Sandbox * Isolated runtime for agent execution * Controlled access to tools and data * Deterministic workflows with auditability ## High-Level Flow 1. Provision a sandbox environment. 2. Start the iCommerce agent process. 3. Use MCP tools or the CLI for queries and actions. 4. Stream outputs and capture logs. ## Sandbox Setup Create a sandbox and run a simple command: ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/create \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"timeout_seconds": 300}' ``` ## Run the Agent Inside the sandbox, run the `stateset` CLI in read-only mode first, then apply actions explicitly: ```bash theme={null} stateset "show me pending orders" stateset --apply "ship order #12345 with tracking FEDEX123" ``` ## Logging and Auditing * Stream command output for review * Record actions, inputs, and outcomes * Keep explicit write intent for audit trails ## Related Documentation * [Sandbox API Flow](/stateset-sandbox-api-flow) * [CLI Safety Model](/stateset-icommerce-cli-safety) * [iCommerce Agent](/stateset-icommerce-agent) # iCommerce Agent Sandbox Costs Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-agent-sandbox-costs Budgeting and limits for sandboxed agent execution. # iCommerce Agent Sandbox Costs Use these practices to control cost and resource usage when running the iCommerce agent in Sandbox. ## Key Levers * **Timeout**: Keep `timeout_seconds` as low as practical * **CPU/Memory**: Choose profiles that match workload size * **Batching**: Split large workflows into smaller runs ## Guardrails * Require explicit `--apply` for write actions * Log execution output for audit and cost tracking ## Operational Tips * Use short-lived sandboxes for bursty tasks * Reuse sandboxes only when needed for long workflows ## Related Documentation * [Sandbox Operations](/stateset-sandbox/OPERATIONS) * [Sandbox API Flow](/stateset-sandbox-api-flow) # iCommerce Agent Sandbox Runbook Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-agent-sandbox-runbook Provision, execute, and clean up an iCommerce agent in Sandbox. # iCommerce Agent Sandbox Runbook This runbook provides an end-to-end flow for running the iCommerce agent inside a sandbox. ## 1) Provision a Sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/create \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"timeout_seconds": 600}' ``` Save the `sandbox_id` from the response. ## 2) Verify Connectivity ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/execute \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command": "stateset \"show me pending orders\""}' ``` ## 3) Execute Write Actions (Explicit) ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/execute \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command": "stateset --apply \"ship order #12345 with tracking FEDEX123\""}' ``` ## 4) Capture Outputs * Stream output from the execution response * Store logs and results for audit trails ## 5) Stop the Sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/stop \ -H "Authorization: ApiKey YOUR_API_KEY" ``` ## Related Documentation * [Run the iCommerce Agent in Sandbox](/stateset-icommerce-agent-sandbox) * [Sandbox API Flow](/stateset-sandbox-api-flow) # iCommerce Agent Sandbox Troubleshooting Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-agent-sandbox-troubleshooting Common errors and fixes when running the agent in Sandbox. # iCommerce Agent Sandbox Troubleshooting Use this checklist when sandboxed agent runs fail or return unexpected results. ## Authentication Errors * Confirm `ApiKey` is valid and not expired * Verify the `Authorization` header format: `ApiKey YOUR_API_KEY` ## Missing CLI * Ensure the sandbox image includes the `stateset` CLI * Rebuild or update the runtime image if the CLI is missing ## Permission or Guardrail Failures * Verify the command includes `--apply` for write actions * Review guardrail policies for restricted operations ## Timeouts * Increase `timeout_seconds` when creating the sandbox * Reduce workflow size or split into smaller tasks ## Output/Logging Issues * Stream command output to capture errors * Store execution logs for auditability ## Related Documentation * [Sandbox API Flow](/stateset-sandbox-api-flow) * [iCommerce Agent Sandbox Runbook](/stateset-icommerce-agent-sandbox-runbook) # StateSet iCommerce Language Bindings Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-bindings SDKs and language bindings for the embedded iCommerce engine. # StateSet iCommerce Language Bindings StateSet iCommerce ships with multiple language bindings so you can run the embedded engine in your stack without changing how your team builds. ## Supported Languages * Node.js * Python * Go * Java * .NET * Ruby * PHP * Rust * Swift * Kotlin * WASM ## SDK Guides * [Node.js](/stateset-icommerce/node) * [Python](/stateset-icommerce/python) * [Go](/stateset-icommerce/go) * [Java](/stateset-icommerce/java) * [.NET](/stateset-icommerce/dotnet) * [Ruby](/stateset-icommerce/ruby) * [PHP](/stateset-icommerce/php) * [Rust](/stateset-icommerce/rust) * [Swift](/stateset-icommerce/swift) * [Kotlin](/stateset-icommerce/kotlin) * [WASM](/stateset-icommerce/wasm) # iCommerce CLI Reference Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-cli-reference Common natural-language commands and patterns. # iCommerce CLI Reference The `stateset` CLI lets you query and act on commerce data using natural language. ## Read-Only Queries ```bash theme={null} stateset "show me pending orders" stateset "list open returns for last 7 days" stateset "show inventory for sku WIDGET-001" ``` ## Write Actions (Explicit) ```bash theme={null} stateset --apply "ship order #12345 with tracking FEDEX123" stateset --apply "approve return RMA-1001" stateset --apply "refund order #12345 for $29.99" ``` ## Pricing and Currency ```bash theme={null} stateset "convert $100 USD to EUR" stateset "estimate shipping cost for order #12345" ``` ## Related Documentation * [CLI Guide](/stateset-icommerce/cli) * [CLI Safety Model](/stateset-icommerce-cli-safety) # StateSet iCommerce CLI Safety Model Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-cli-safety Read-only defaults and explicit write intent for agent workflows. # StateSet iCommerce CLI Safety Model The iCommerce CLI defaults to read-only actions to keep agent workflows safe and auditable. ## Read-Only by Default Use natural language to query without modifying data: ```bash theme={null} stateset "show me pending orders" ``` ## Explicit Writes with --apply To apply changes, require explicit intent: ```bash theme={null} stateset --apply "ship order #12345 with tracking FEDEX123" ``` ## Why This Matters * Prevents accidental writes during exploration * Improves auditability in agent-driven workflows * Enables safe iteration in production environments ## Related Documentation * [CLI Guide](/stateset-icommerce/cli) * [Examples](/stateset-icommerce/examples) # iCommerce CLI Workflows Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-cli-workflows End-to-end workflows built with the CLI and MCP tools. # iCommerce CLI Workflows Use the CLI to execute safe, repeatable workflows with explicit write intent. ## Order Fulfillment 1. Inspect pending orders 2. Confirm address and inventory 3. Ship the order with tracking ```bash theme={null} stateset "show me pending orders" stateset "show order #12345" stateset --apply "ship order #12345 with tracking FEDEX123" ``` ## Returns Processing 1. Find eligible returns 2. Approve or reject 3. Issue refund ```bash theme={null} stateset "list returns awaiting review" stateset --apply "approve return RMA-1001" stateset --apply "refund return RMA-1001 for $29.99" ``` ## Inventory Adjustment ```bash theme={null} stateset --apply "adjust inventory for sku WIDGET-001 by -5 at warehouse LA" ``` ## Related Documentation * [Examples](/stateset-icommerce/examples) * [Order Lifecycle](/stateset-icommerce-order-lifecycle) # About the iCommerce embedded engine Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-embedded Understand the local-first engine and deterministic APIs. # About the iCommerce embedded engine This explanation covers the local-first iCommerce engine and how deterministic APIs make automation safe. ## How the engine works * The embedded engine runs in-process on SQLite or PostgreSQL. * Deterministic operations require explicit write intent. * Language bindings expose a unified API surface. ## Why this design Local-first execution improves latency and reliability while keeping behavior predictable. ## When to use it * **Agent workflows**: safe, deterministic operations * **Edge deployments**: local-first execution * **High-throughput**: in-process calls with minimal overhead ## Further reading * [Getting Started](/stateset-icommerce/getting-started) * [Architecture](/stateset-icommerce/architecture) * [CLI Guide](/stateset-icommerce/cli) # Deploy iCommerce on Fly.io Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-flyio Run a persistent StateSet iCommerce Gateway on Fly.io with automatic HTTPS, persistent storage, and channel access. # Deploy iCommerce on Fly.io Deploy StateSet iCommerce on Fly.io with automatic HTTPS, persistent volumes, and global edge deployment. This guide walks you through deploying a production-ready iCommerce Gateway that scales automatically. ## Goal Deploy a StateSet iCommerce Gateway on Fly.io with: * Persistent storage for configuration and workspace data * Automatic HTTPS with custom domain support * Discord, Telegram, and other channel integrations * Global edge deployment for low latency Fly.io's free tier works for testing. Production deployments typically cost \$10-15/month with the recommended configuration. ## What you'll build Set up the application and persistent storage. Define build settings, environment, and resources. Configure API keys and tokens securely. Build and deploy the Gateway. Create the configuration file and connect channels. ## Prerequisites Before you begin, ensure you have: * [flyctl CLI](https://fly.io/docs/hands-on/install-flyctl/) installed * Fly.io account (free tier works) * StateSet API credentials * Model provider credentials (Anthropic, OpenAI, etc.) **Optional integrations:** * Discord bot token * Telegram bot token * WhatsApp Business API credentials *** ## Quick path (experienced operators) If you're familiar with Fly.io, follow this condensed workflow: 1. Clone repo and customize `fly.toml` 2. Create app and volume 3. Set secrets via `fly secrets set` 4. Deploy with `fly deploy` 5. SSH in to create config or use Control UI *** ## 1) Create the Fly app Clone the repository and create a new Fly app: ```bash theme={null} git clone https://github.com/stateset/stateset-icommerce.git cd stateset-icommerce # Create a new Fly app (choose your own name) fly apps create my-icommerce # Create a persistent volume (1GB is usually enough) fly volumes create icommerce_data --size 1 --region iad ``` Choose a region close to you or your users. Common options: `lhr` (London), `iad` (Virginia), `sjc` (San Jose), `fra` (Frankfurt). *** ## 2) Configure fly.toml Create or edit `fly.toml` to match your app name and requirements: ```toml theme={null} app = "my-icommerce" # Your app name primary_region = "iad" [build] dockerfile = "Dockerfile" [env] NODE_ENV = "production" STATESET_PREFER_PNPM = "1" STATESET_STATE_DIR = "/data" NODE_OPTIONS = "--max-old-space-size=1536" [processes] app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan" [http_service] internal_port = 3000 force_https = true auto_stop_machines = false auto_start_machines = true min_machines_running = 1 processes = ["app"] [[vm]] size = "shared-cpu-2x" memory = "2048mb" [mounts] source = "icommerce_data" destination = "/data" ``` ### Key settings explained | Setting | Purpose | | ------------------------------ | ------------------------------------------------------ | | `--bind lan` | Binds to 0.0.0.0 so Fly's proxy can reach the gateway | | `--allow-unconfigured` | Starts without a config file (create one after deploy) | | `internal_port = 3000` | Must match `--port 3000` for Fly health checks | | `memory = "2048mb"` | 512MB is too small; 2GB recommended | | `STATESET_STATE_DIR = "/data"` | Persists state on the volume | The default config exposes a public URL. For a hardened deployment with no public IP, see the [Private Deployment](#private-deployment-hardened) section. *** ## 3) Set secrets Configure your API keys and tokens as Fly secrets: ```bash theme={null} # Required: Gateway token (for non-loopback binding) fly secrets set STATESET_GATEWAY_TOKEN=$(openssl rand -hex 32) # Model provider API keys fly secrets set ANTHROPIC_API_KEY=sk-ant-... fly secrets set OPENAI_API_KEY=sk-... # Optional: Other providers fly secrets set GOOGLE_API_KEY=... # Channel tokens fly secrets set DISCORD_BOT_TOKEN=MTQ... fly secrets set TELEGRAM_BOT_TOKEN=... ``` Non-loopback binds (`--bind lan`) require `STATESET_GATEWAY_TOKEN` for security. Treat these tokens like passwords. Prefer environment variables over config files for all API keys and tokens. This keeps secrets out of configuration files where they could be accidentally exposed or logged. *** ## 4) Deploy Deploy the application: ```bash theme={null} fly deploy ``` The first deploy builds the Docker image (\~2-3 minutes). Subsequent deploys are faster. Verify the deployment: ```bash theme={null} fly status fly logs ``` Success output: ``` [gateway] listening on ws://0.0.0.0:3000 (PID xxx) [discord] logged in to discord as xxx ``` *** ## 5) Create configuration file SSH into the machine to create a proper configuration: ```bash theme={null} fly ssh console ``` Create the config directory and file: ```bash theme={null} mkdir -p /data cat > /data/stateset.json << 'EOF' { "agents": { "defaults": { "model": { "primary": "anthropic/claude-sonnet-4-20250514", "fallbacks": ["openai/gpt-4o"] }, "maxConcurrent": 4 }, "list": [ { "id": "main", "default": true } ] }, "auth": { "profiles": { "anthropic:default": { "mode": "token", "provider": "anthropic" }, "openai:default": { "mode": "token", "provider": "openai" } } }, "bindings": [ { "agentId": "main", "match": { "channel": "discord" } } ], "channels": { "discord": { "enabled": true, "groupPolicy": "allowlist", "guilds": { "YOUR_GUILD_ID": { "channels": { "general": { "allow": true } }, "requireMention": false } } } }, "gateway": { "mode": "local", "bind": "auto" } } EOF ``` With `STATESET_STATE_DIR=/data`, the config path is `/data/stateset.json`. Restart to apply the configuration: ```bash theme={null} exit fly machine restart ``` *** ## 6) Access the Gateway ### Control UI Open in your browser: ```bash theme={null} fly open ``` Or visit `https://my-icommerce.fly.dev/` Enter your gateway token (from `STATESET_GATEWAY_TOKEN`) to authenticate. ### Logs ```bash theme={null} fly logs # Live logs fly logs --no-tail # Recent logs ``` ### SSH Console ```bash theme={null} fly ssh console ``` *** ## Troubleshooting ### "App is not listening on expected address" The gateway is binding to `127.0.0.1` instead of `0.0.0.0`. **Fix:** Add `--bind lan` to your process command in `fly.toml`. ### Health checks failing / connection refused Fly can't reach the gateway on the configured port. **Fix:** Ensure `internal_port` matches the gateway port (set `--port 3000` or `STATESET_GATEWAY_PORT=3000`). ### OOM / Memory issues Container keeps restarting or getting killed. Signs: `SIGABRT`, memory allocation errors, or silent restarts. **Fix:** Increase memory in `fly.toml`: ```toml theme={null} [[vm]] memory = "2048mb" ``` Or update an existing machine: ```bash theme={null} fly machine update --vm-memory 2048 -y ``` 512MB is too small. 1GB may work but can OOM under load. 2GB is recommended. ### Gateway lock issues Gateway refuses to start with "already running" errors. This happens when the container restarts but the PID lock file persists on the volume. **Fix:** Delete the lock file: ```bash theme={null} fly ssh console --command "rm -f /data/gateway.*.lock" fly machine restart ``` ### Config not being read If using `--allow-unconfigured`, the gateway creates a minimal config. Your custom config at `/data/stateset.json` should be read on restart. Verify the config exists: ```bash theme={null} fly ssh console --command "cat /data/stateset.json" ``` ### Writing config via SSH The `fly ssh console -C` command doesn't support shell redirection. To write a config file: ```bash theme={null} # Use echo + tee (pipe from local to remote) echo '{"your":"config"}' | fly ssh console -C "tee /data/stateset.json" # Or use sftp fly sftp shell > put /local/path/config.json /data/stateset.json ``` `fly sftp` may fail if the file already exists. Delete first with `fly ssh console --command "rm /data/stateset.json"`. ### State not persisting If you lose credentials or sessions after a restart, the state directory is writing to the container filesystem. **Fix:** Ensure `STATESET_STATE_DIR=/data` is set in `fly.toml` and redeploy. *** ## Updates ```bash theme={null} # Pull latest changes git pull # Redeploy fly deploy # Check health fly status fly logs ``` ### Updating machine command If you need to change the startup command without a full redeploy: ```bash theme={null} # Get machine ID fly machines list # Update command fly machine update --command "node dist/index.js gateway --port 3000 --bind lan" -y # Or with memory increase fly machine update --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y ``` After `fly deploy`, the machine command may reset to what's in `fly.toml`. If you made manual changes, re-apply them after deploy. *** ## Private deployment (hardened) By default, Fly allocates public IPs, making your gateway accessible at `https://your-app.fly.dev`. This is convenient but means your deployment is discoverable by internet scanners. ### When to use private deployment * You only make outbound calls/messages (no inbound webhooks) * You use ngrok or Tailscale tunnels for webhook callbacks * You access the gateway via SSH, proxy, or WireGuard * You want the deployment hidden from internet scanners ### Setup Use `fly.private.toml` instead of the standard config: ```bash theme={null} fly deploy -c fly.private.toml ``` Or convert an existing deployment: ```bash theme={null} # List current IPs fly ips list -a my-icommerce # Release public IPs fly ips release -a my-icommerce fly ips release -a my-icommerce # Deploy with private config fly deploy -c fly.private.toml # Allocate private-only IPv6 fly ips allocate-v6 --private -a my-icommerce ``` After this, `fly ips list` should show only a private type IP: ``` VERSION IP TYPE REGION v6 fdaa:x:x:x:x::x private global ``` ### Accessing a private deployment ```bash theme={null} # Forward local port 3000 to the app fly proxy 3000:3000 -a my-icommerce # Then open http://localhost:3000 in browser ``` ```bash theme={null} # Create WireGuard config (one-time) fly wireguard create # Import to WireGuard client, then access via internal IPv6 # Example: http://[fdaa:x:x:x:x::x]:3000 ``` ```bash theme={null} fly ssh console -a my-icommerce ``` ### Webhooks with private deployment If you need webhook callbacks (Twilio, Telnyx, etc.) without public exposure: * **ngrok tunnel** - Run ngrok inside the container or as a sidecar * **Tailscale Funnel** - Expose specific paths via Tailscale * **Outbound-only** - Some providers work fine for outbound calls without webhooks ### Security comparison | Aspect | Public | Private | | ----------------- | ------------ | ---------- | | Internet scanners | Discoverable | Hidden | | Direct attacks | Possible | Blocked | | Control UI access | Browser | Proxy/VPN | | Webhook delivery | Direct | Via tunnel | *** ## Cost With the recommended configuration (shared-cpu-2x, 2GB RAM): | Component | Cost | | ------------- | ------------------- | | Compute | \~\$10-12/month | | Storage (1GB) | \~\$0.15/month | | Bandwidth | Varies by usage | | **Total** | **\~\$10-15/month** | Fly.io's free tier includes some allowance. See [Fly.io pricing](https://fly.io/docs/about/pricing/) for details. *** ## Notes * Fly.io uses x86 architecture (not ARM) * The Dockerfile is compatible with both architectures * For WhatsApp/Telegram onboarding, use `fly ssh console` * Persistent data lives on the volume at `/data` *** ## Next steps Set up WhatsApp, Telegram, and other messaging integrations. Configure and extend agent capabilities with custom skills. Learn the full CLI command set for managing your iCommerce instance. Review security best practices for production deployments. # Deploy iCommerce on GCP Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-gcp Run a persistent StateSet iCommerce Gateway on GCP Compute Engine using Docker with durable state and safe restart behavior. # Deploy iCommerce on GCP Run StateSet iCommerce 24/7 for approximately \$5-12/month on Google Cloud Platform. This guide walks you through deploying a persistent iCommerce Gateway on a GCP Compute Engine VM using Docker, with durable state, baked-in binaries, and safe restart behavior. ## Goal Deploy a production-ready StateSet iCommerce Gateway on GCP Compute Engine with: * Persistent configuration and workspace data * Docker-based isolated runtime * SSH tunnel access for secure administration * Automatic restart on failure Pricing varies by machine type and region. Start with the smallest VM that fits your workload and scale up if you encounter out-of-memory errors. ## What you'll build Set up a GCP project, enable billing, and create a Compute Engine VM. Install Docker for isolated, reproducible application runtime. Mount host directories for configuration and workspace data that survives restarts. Build and launch the iCommerce Gateway with Docker Compose. Connect via SSH tunnel from your local machine. ## Prerequisites Before you begin, ensure you have: * GCP account (free tier eligible for e2-micro) * `gcloud` CLI installed, or access to the Cloud Console * SSH access from your local machine * Basic familiarity with terminal commands * StateSet API credentials * Model provider credentials (OpenAI, Anthropic, etc.) **Optional integrations:** * WhatsApp Business API credentials * Telegram bot token * Gmail OAuth credentials *** ## Quick path (experienced operators) If you're familiar with GCP and Docker, follow this condensed workflow: 1. Create GCP project and enable Compute Engine API 2. Create Compute Engine VM (e2-small, Debian 12, 20GB) 3. SSH into the VM 4. Install Docker 5. Clone the StateSet iCommerce repository 6. Create persistent host directories 7. Configure `.env` and `docker-compose.yml` 8. Bake required binaries, build, and launch *** ## 1) Install gcloud CLI Install from the [Google Cloud SDK documentation](https://cloud.google.com/sdk/docs/install). Initialize and authenticate: ```bash theme={null} gcloud init gcloud auth login ``` All steps can be completed via the web UI at [console.cloud.google.com](https://console.cloud.google.com). *** ## 2) Create a GCP project ```bash theme={null} gcloud projects create my-icommerce-project --name="StateSet iCommerce" gcloud config set project my-icommerce-project ``` Enable billing at [console.cloud.google.com/billing](https://console.cloud.google.com/billing) (required for Compute Engine). Enable the Compute Engine API: ```bash theme={null} gcloud services enable compute.googleapis.com ``` 1. Go to **IAM & Admin > Create Project** 2. Name your project and create it 3. Enable billing for the project 4. Navigate to **APIs & Services > Enable APIs** 5. Search for "Compute Engine API" and enable it *** ## 3) Create the VM ### Machine type comparison | Type | Specs | Cost | Notes | | -------- | ------------------------ | ------------------ | -------------------------- | | e2-small | 2 vCPU, 2GB RAM | \~\$12/mo | Recommended for production | | e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | May OOM under load | ```bash theme={null} gcloud compute instances create icommerce-gateway \ --zone=us-central1-a \ --machine-type=e2-small \ --boot-disk-size=20GB \ --image-family=debian-12 \ --image-project=debian-cloud ``` 1. Go to **Compute Engine > VM instances > Create instance** 2. Name: `icommerce-gateway` 3. Region: `us-central1`, Zone: `us-central1-a` 4. Machine type: `e2-small` 5. Boot disk: Debian 12, 20GB 6. Click **Create** *** ## 4) SSH into the VM ```bash theme={null} gcloud compute ssh icommerce-gateway --zone=us-central1-a ``` Click the **SSH** button next to your VM in the Compute Engine dashboard. SSH key propagation can take 1-2 minutes after VM creation. If the connection is refused, wait and retry. *** ## 5) Install Docker Run the following commands on the VM: ```bash theme={null} sudo apt-get update sudo apt-get install -y git curl ca-certificates curl -fsSL https://get.docker.com | sudo sh sudo usermod -aG docker $USER ``` Log out and back in for the group change to take effect: ```bash theme={null} exit ``` SSH back in: ```bash theme={null} gcloud compute ssh icommerce-gateway --zone=us-central1-a ``` Verify the installation: ```bash theme={null} docker --version docker compose version ``` *** ## 6) Clone the repository ```bash theme={null} git clone https://github.com/stateset/stateset-icommerce.git cd stateset-icommerce ``` *** ## 7) Create persistent host directories Docker containers are ephemeral. All long-lived state must live on the host to survive restarts and rebuilds. ```bash theme={null} mkdir -p ~/.stateset mkdir -p ~/.stateset/workspace ``` *** ## 8) Configure environment variables Create a `.env` file in the repository root: ```bash theme={null} STATESET_IMAGE=stateset-icommerce:latest STATESET_GATEWAY_TOKEN=change-me-now STATESET_GATEWAY_BIND=lan STATESET_GATEWAY_PORT=18789 STATESET_CONFIG_DIR=/home/$USER/.stateset STATESET_WORKSPACE_DIR=/home/$USER/.stateset/workspace STATESET_KEYRING_PASSWORD=change-me-now XDG_CONFIG_HOME=/home/node/.stateset ``` Generate strong secrets: ```bash theme={null} openssl rand -hex 32 ``` Do not commit the `.env` file to version control. It contains sensitive credentials. *** ## 9) Docker Compose configuration Create or update `docker-compose.yml`: ```yaml theme={null} services: icommerce-gateway: image: ${STATESET_IMAGE} build: . restart: unless-stopped env_file: - .env environment: - HOME=/home/node - NODE_ENV=production - TERM=xterm-256color - STATESET_GATEWAY_BIND=${STATESET_GATEWAY_BIND} - STATESET_GATEWAY_PORT=${STATESET_GATEWAY_PORT} - STATESET_GATEWAY_TOKEN=${STATESET_GATEWAY_TOKEN} - STATESET_KEYRING_PASSWORD=${STATESET_KEYRING_PASSWORD} - XDG_CONFIG_HOME=${XDG_CONFIG_HOME} - PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin volumes: - ${STATESET_CONFIG_DIR}:/home/node/.stateset - ${STATESET_WORKSPACE_DIR}:/home/node/.stateset/workspace ports: # Keep the Gateway loopback-only; access via SSH tunnel - "127.0.0.1:${STATESET_GATEWAY_PORT}:18789" command: [ "node", "dist/index.js", "gateway", "--bind", "${STATESET_GATEWAY_BIND}", "--port", "${STATESET_GATEWAY_PORT}" ] ``` To expose the Gateway publicly, remove the `127.0.0.1:` prefix from the port mapping and configure firewall rules accordingly. See the [security documentation](/security) for guidance. *** ## 10) Bake required binaries into the image Installing binaries inside a running container is a common mistake. Anything installed at runtime will be lost on restart. All external binaries required by skills must be installed at image build time. If you add new skills later that depend on additional binaries, you must: 1. Update the Dockerfile 2. Rebuild the image 3. Restart the containers ### Example Dockerfile ```dockerfile theme={null} FROM node:22-bookworm RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/* # Gmail CLI RUN curl -L https://github.com/steipete/gog/releases/latest/download/gog_Linux_x86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/gog # Google Places CLI RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplaces_Linux_x86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/goplaces # WhatsApp CLI RUN curl -L https://github.com/steipete/wacli/releases/latest/download/wacli_Linux_x86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/wacli # Add more binaries as needed using the same pattern WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./ COPY ui/package.json ./ui/package.json COPY scripts ./scripts RUN corepack enable RUN pnpm install --frozen-lockfile COPY . . RUN pnpm build RUN pnpm ui:install RUN pnpm ui:build ENV NODE_ENV=production CMD ["node","dist/index.js"] ``` *** ## 11) Build and launch ```bash theme={null} docker compose build docker compose up -d icommerce-gateway ``` Verify binaries are installed: ```bash theme={null} docker compose exec icommerce-gateway which gog docker compose exec icommerce-gateway which goplaces docker compose exec icommerce-gateway which wacli ``` Expected output: ``` /usr/local/bin/gog /usr/local/bin/goplaces /usr/local/bin/wacli ``` *** ## 12) Verify the Gateway ```bash theme={null} docker compose logs -f icommerce-gateway ``` Success output: ``` [gateway] listening on ws://0.0.0.0:18789 ``` *** ## 13) Access from your local machine Create an SSH tunnel to forward the Gateway port: ```bash theme={null} gcloud compute ssh icommerce-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789 ``` Open in your browser: ``` http://127.0.0.1:18789/ ``` Enter your gateway token to authenticate. *** ## Persistence reference All long-lived state must survive restarts, rebuilds, and reboots. Docker is not the source of truth. | Component | Location | Persistence | Notes | | ------------------- | --------------------------------- | ---------------------- | ------------------------------------ | | Gateway config | `/home/node/.stateset/` | Host volume mount | Includes tokens, settings | | Model auth profiles | `/home/node/.stateset/` | Host volume mount | OAuth tokens, API keys | | Skill configs | `/home/node/.stateset/skills/` | Host volume mount | Skill-level state | | Agent workspace | `/home/node/.stateset/workspace/` | Host volume mount | Code and agent artifacts | | WhatsApp session | `/home/node/.stateset/` | Host volume mount | Preserves QR login | | Keyring | `/home/node/.stateset/` | Host volume + password | Requires `STATESET_KEYRING_PASSWORD` | | External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time | | Node runtime | Container filesystem | Docker image | Rebuilt every image build | | OS packages | Container filesystem | Docker image | Do not install at runtime | *** ## Updates To update StateSet iCommerce on the VM: ```bash theme={null} cd ~/stateset-icommerce git pull docker compose build docker compose up -d ``` *** ## Troubleshooting ### SSH connection refused SSH key propagation can take 1-2 minutes after VM creation. Wait and retry. ### OS Login issues Check your OS Login profile: ```bash theme={null} gcloud compute os-login describe-profile ``` Ensure your account has the required IAM permissions (`Compute OS Login` or `Compute OS Admin Login`). ### Out of memory (OOM) If using e2-micro and hitting OOM, upgrade to e2-small or e2-medium: ```bash theme={null} # Stop the VM gcloud compute instances stop icommerce-gateway --zone=us-central1-a # Change machine type gcloud compute instances set-machine-type icommerce-gateway \ --zone=us-central1-a \ --machine-type=e2-small # Start the VM gcloud compute instances start icommerce-gateway --zone=us-central1-a ``` ### Container fails to start Check logs for errors: ```bash theme={null} docker compose logs icommerce-gateway ``` Verify environment variables are set correctly: ```bash theme={null} docker compose config ``` *** ## Service accounts (security best practice) For personal use, your default user account works fine. For automation or CI/CD pipelines, create a dedicated service account with minimal permissions: **Create a service account:** ```bash theme={null} gcloud iam service-accounts create icommerce-deploy \ --display-name="iCommerce Deployment" ``` **Grant Compute Instance Admin role:** ```bash theme={null} gcloud projects add-iam-policy-binding my-icommerce-project \ --member="serviceAccount:icommerce-deploy@my-icommerce-project.iam.gserviceaccount.com" \ --role="roles/compute.instanceAdmin.v1" ``` Avoid using the Owner role for automation. Use the principle of least privilege. See [GCP IAM roles documentation](https://cloud.google.com/iam/docs/understanding-roles) for details. *** ## Next steps Set up WhatsApp, Telegram, and other messaging integrations. Configure and extend agent capabilities with custom skills. Learn the full CLI command set for managing your iCommerce instance. Review security best practices for production deployments. # Deploy iCommerce on Hetzner Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-hetzner Run a persistent StateSet iCommerce Gateway on a Hetzner VPS using Docker with durable state and safe restart behavior. # Deploy iCommerce on Hetzner Run StateSet iCommerce 24/7 for approximately \$5/month on Hetzner. This guide walks you through deploying a persistent iCommerce Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior. ## Goal Deploy a production-ready StateSet iCommerce Gateway on Hetzner with: * Persistent configuration and workspace data * Docker-based isolated runtime * SSH tunnel access for secure administration * Automatic restart on failure Hetzner offers some of the most cost-effective VPS options available. Pick the smallest Debian/Ubuntu VPS that fits your workload and scale up if you encounter out-of-memory errors. ## What you'll build Create a small Linux server with root access. Install Docker for isolated, reproducible application runtime. Mount host directories for configuration and workspace data that survives restarts. Build and launch the iCommerce Gateway with Docker Compose. Connect via SSH tunnel from your local machine. ## Prerequisites Before you begin, ensure you have: * Hetzner VPS with root access * SSH access from your local machine * Basic familiarity with terminal commands * StateSet API credentials * Model provider credentials (OpenAI, Anthropic, etc.) **Optional integrations:** * WhatsApp Business API credentials * Telegram bot token * Gmail OAuth credentials This guide assumes Ubuntu or Debian on Hetzner. If you're on another Linux VPS provider, map packages accordingly. *** ## Quick path (experienced operators) If you're familiar with Hetzner and Docker, follow this condensed workflow: 1. Provision Hetzner VPS (Ubuntu/Debian) 2. Install Docker 3. Clone the StateSet iCommerce repository 4. Create persistent host directories 5. Configure `.env` and `docker-compose.yml` 6. Bake required binaries into the image 7. `docker compose up -d` 8. Verify persistence and Gateway access *** ## 1) Provision the VPS Create an Ubuntu or Debian VPS in the [Hetzner Cloud Console](https://console.hetzner.cloud/). ### Recommended specifications | Type | Specs | Cost | Notes | | ---- | --------------- | ------- | --------------------------------- | | CX22 | 2 vCPU, 4GB RAM | \~€4/mo | Recommended | | CX11 | 1 vCPU, 2GB RAM | \~€3/mo | Budget option, may OOM under load | Connect as root: ```bash theme={null} ssh root@YOUR_VPS_IP ``` This guide assumes the VPS is stateful. Do not treat it as disposable infrastructure. *** ## 2) Install Docker Run the following commands on the VPS: ```bash theme={null} apt-get update apt-get install -y git curl ca-certificates curl -fsSL https://get.docker.com | sh ``` Verify the installation: ```bash theme={null} docker --version docker compose version ``` *** ## 3) Clone the repository ```bash theme={null} git clone https://github.com/stateset/stateset-icommerce.git cd stateset-icommerce ``` *** ## 4) Create persistent host directories Docker containers are ephemeral. All long-lived state must live on the host to survive restarts and rebuilds. ```bash theme={null} mkdir -p /root/.stateset mkdir -p /root/.stateset/workspace # Set ownership to the container user (uid 1000) chown -R 1000:1000 /root/.stateset chown -R 1000:1000 /root/.stateset/workspace ``` Setting the correct ownership is critical. The container runs as uid 1000 (node user), so the host directories must be writable by that user. *** ## 5) Configure environment variables Create a `.env` file in the repository root: ```bash theme={null} STATESET_IMAGE=stateset-icommerce:latest STATESET_GATEWAY_TOKEN=change-me-now STATESET_GATEWAY_BIND=lan STATESET_GATEWAY_PORT=18789 STATESET_CONFIG_DIR=/root/.stateset STATESET_WORKSPACE_DIR=/root/.stateset/workspace STATESET_KEYRING_PASSWORD=change-me-now XDG_CONFIG_HOME=/home/node/.stateset ``` Generate strong secrets: ```bash theme={null} openssl rand -hex 32 ``` Do not commit the `.env` file to version control. It contains sensitive credentials. *** ## 6) Docker Compose configuration Create or update `docker-compose.yml`: ```yaml theme={null} services: icommerce-gateway: image: ${STATESET_IMAGE} build: . restart: unless-stopped env_file: - .env environment: - HOME=/home/node - NODE_ENV=production - TERM=xterm-256color - STATESET_GATEWAY_BIND=${STATESET_GATEWAY_BIND} - STATESET_GATEWAY_PORT=${STATESET_GATEWAY_PORT} - STATESET_GATEWAY_TOKEN=${STATESET_GATEWAY_TOKEN} - STATESET_KEYRING_PASSWORD=${STATESET_KEYRING_PASSWORD} - XDG_CONFIG_HOME=${XDG_CONFIG_HOME} - PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin volumes: - ${STATESET_CONFIG_DIR}:/home/node/.stateset - ${STATESET_WORKSPACE_DIR}:/home/node/.stateset/workspace ports: # Keep the Gateway loopback-only; access via SSH tunnel - "127.0.0.1:${STATESET_GATEWAY_PORT}:18789" command: [ "node", "dist/index.js", "gateway", "--bind", "${STATESET_GATEWAY_BIND}", "--port", "${STATESET_GATEWAY_PORT}" ] ``` To expose the Gateway publicly, remove the `127.0.0.1:` prefix from the port mapping and configure firewall rules accordingly. See the [security documentation](/security) for guidance. *** ## 7) Bake required binaries into the image Installing binaries inside a running container is a common mistake. Anything installed at runtime will be lost on restart. All external binaries required by skills must be installed at image build time. If you add new skills later that depend on additional binaries, you must: 1. Update the Dockerfile 2. Rebuild the image 3. Restart the containers ### Example Dockerfile ```dockerfile theme={null} FROM node:22-bookworm RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/* # Gmail CLI RUN curl -L https://github.com/steipete/gog/releases/latest/download/gog_Linux_x86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/gog # Google Places CLI RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplaces_Linux_x86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/goplaces # WhatsApp CLI RUN curl -L https://github.com/steipete/wacli/releases/latest/download/wacli_Linux_x86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/wacli # Add more binaries as needed using the same pattern WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./ COPY ui/package.json ./ui/package.json COPY scripts ./scripts RUN corepack enable RUN pnpm install --frozen-lockfile COPY . . RUN pnpm build RUN pnpm ui:install RUN pnpm ui:build ENV NODE_ENV=production CMD ["node","dist/index.js"] ``` *** ## 8) Build and launch ```bash theme={null} docker compose build docker compose up -d icommerce-gateway ``` Verify binaries are installed: ```bash theme={null} docker compose exec icommerce-gateway which gog docker compose exec icommerce-gateway which goplaces docker compose exec icommerce-gateway which wacli ``` Expected output: ``` /usr/local/bin/gog /usr/local/bin/goplaces /usr/local/bin/wacli ``` *** ## 9) Verify the Gateway Check the logs: ```bash theme={null} docker compose logs -f icommerce-gateway ``` Success output: ``` [gateway] listening on ws://0.0.0.0:18789 ``` *** ## 10) Access from your local machine Create an SSH tunnel to forward the Gateway port: ```bash theme={null} ssh -N -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP ``` Open in your browser: ``` http://127.0.0.1:18789/ ``` Enter your gateway token to authenticate. The `-N` flag tells SSH not to execute a remote command, making it ideal for port forwarding only. *** ## Persistence reference All long-lived state must survive restarts, rebuilds, and reboots. Docker is not the source of truth. | Component | Location | Persistence | Notes | | ------------------- | --------------------------------- | ---------------------- | ------------------------------------ | | Gateway config | `/home/node/.stateset/` | Host volume mount | Includes tokens, settings | | Model auth profiles | `/home/node/.stateset/` | Host volume mount | OAuth tokens, API keys | | Skill configs | `/home/node/.stateset/skills/` | Host volume mount | Skill-level state | | Agent workspace | `/home/node/.stateset/workspace/` | Host volume mount | Code and agent artifacts | | WhatsApp session | `/home/node/.stateset/` | Host volume mount | Preserves QR login | | Keyring | `/home/node/.stateset/` | Host volume + password | Requires `STATESET_KEYRING_PASSWORD` | | External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time | | Node runtime | Container filesystem | Docker image | Rebuilt every image build | | OS packages | Container filesystem | Docker image | Do not install at runtime | *** ## Updates To update StateSet iCommerce on the VPS: ```bash theme={null} cd ~/stateset-icommerce git pull docker compose build docker compose up -d ``` *** ## Troubleshooting ### SSH connection refused Verify the VPS is running and your IP is not blocked by any firewall rules. ```bash theme={null} # Check if SSH is listening netstat -tlnp | grep 22 ``` ### Out of memory (OOM) If hitting OOM on a smaller VPS, upgrade to a larger instance: 1. Create a snapshot of your VPS in Hetzner Cloud Console 2. Resize or create a new VPS with more resources 3. Restore from snapshot if needed ### Container fails to start Check logs for errors: ```bash theme={null} docker compose logs icommerce-gateway ``` Verify environment variables are set correctly: ```bash theme={null} docker compose config ``` ### Permission denied on mounted volumes Ensure the host directories have the correct ownership: ```bash theme={null} chown -R 1000:1000 /root/.stateset ``` ### Firewall blocking connections If using Hetzner's firewall, ensure the required ports are open: ```bash theme={null} # Check current firewall rules ufw status # Allow SSH (if using ufw) ufw allow 22/tcp ``` *** ## Hetzner-specific tips ### Enable automatic backups Enable automatic backups in the Hetzner Cloud Console for disaster recovery. Cost is approximately 20% of VPS price. ### Use a floating IP For production deployments, assign a floating IP to your VPS. This allows you to migrate to a new server without changing your IP address. ### Set up monitoring Hetzner provides basic monitoring in the Cloud Console. For more detailed metrics, consider installing a monitoring agent: ```bash theme={null} # Example: Install Netdata for real-time monitoring bash <(curl -Ss https://my-netdata.io/kickstart.sh) ``` *** ## Next steps Set up WhatsApp, Telegram, and other messaging integrations. Configure and extend agent capabilities with custom skills. Learn the full CLI command set for managing your iCommerce instance. Review security best practices for production deployments. # iCommerce Inventory Lifecycle Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-inventory-lifecycle Stock, reservation, fulfillment, and reconciliation in iCommerce. # iCommerce Inventory Lifecycle This guide covers how inventory moves through iCommerce from stocking to fulfillment and reconciliation. ## 1) Stock and Catalog Define products and initial stock levels. Inventory can be adjusted in bulk or item-by-item depending on your ingestion flow. ## 2) Reserve on Order When an order is created, inventory is reserved to prevent oversells. Reservations can be updated if the order changes. ## 3) Fulfill and Decrement On fulfillment, reserved inventory is decremented and linked to shipments for traceability. ## 4) Returns and Restock Returned items can be inspected and restocked or flagged for disposition. Inventory adjustments are recorded with auditability. ## 5) Reconciliation Use cycle counts and adjustments to reconcile system inventory with physical stock. ## Related Documentation * [Order Lifecycle](/stateset-icommerce-order-lifecycle) * [Inventory Quickstart](/guides/inventory-quickstart) * [Warehouse Quickstart](/guides/warehouse-quickstart) # Connect messaging channels Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-messaging-channels Connect chat, SMS, and email channels to iCommerce. # Connect messaging channels This guide shows how to connect messaging channels to the iCommerce engine using an agent-driven flow. ## Prerequisites * ResponseCX or an MCP-enabled agent * Access to iCommerce SDKs or CLI * Channel provider credentials ## Connect a channel and route to iCommerce 1. Connect your channel provider (chat, SMS, email, voice). 2. Route incoming messages to a ResponseCX agent or MCP tool. 3. Call iCommerce APIs or CLI for deterministic actions. 4. Return results to the channel. ```text theme={null} Customer: Where is my order #12345? Agent: Looks up order in iCommerce → returns status and tracking. ``` Keep write actions behind explicit confirmation (`--apply`) in agent workflows. ## Verify the result Confirm the channel response includes the expected order or return data. ## Related tasks * [iCommerce Agent](/stateset-icommerce-agent) * [CLI Workflows](/stateset-icommerce-cli-workflows) # iCommerce Messaging Orchestrator Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-messaging-orchestrator Run multiple channels (WhatsApp, Slack, Telegram, etc.) together. # iCommerce Messaging Orchestrator The multi-channel orchestrator lets you run several messaging gateways from one configuration. ## Entry Point * CLI: `stateset-channels` * Source: `stateset-icommerce/cli/bin/stateset-channels.js` ## How It Works 1. Load channel configuration from a YAML file. 2. Start each channel gateway with shared middleware. 3. Route messages into the same agent/session layer. ## Example Config See `stateset-icommerce/cli/examples/channels.yaml` for a full config example. ## Supported Channels * WhatsApp * Telegram * Slack * Discord * Signal * Google Chat ## Related Documentation * [WhatsApp Integration](/stateset-icommerce-whatsapp-integration) * [Messaging Channels with iCommerce](/stateset-icommerce-messaging-channels) # iCommerce Order Lifecycle Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-order-lifecycle End-to-end flow from order creation to fulfillment and returns. # iCommerce Order Lifecycle This guide walks through a typical order lifecycle in the embedded iCommerce engine. ## 1) Create an Order Orders can be created through the SDKs or the CLI. Start with a minimal order payload, then enrich with payment, shipping, and customer details. ## 2) Validate and Authorize Payment Validate totals, taxes, and discounts before authorizing payment. For agent workflows, ensure the action is explicit and auditable. ## 3) Reserve Inventory Inventory is reserved against the order to prevent oversells. Reservations can be updated if the order changes. ## 4) Fulfill and Ship When fulfillment begins, create a shipment record and update the order status. Tracking details flow back to the customer. ## 5) Post-Purchase Actions Handle returns, exchanges, and refunds with deterministic actions tied to the original order and inventory adjustments. ## Related Documentation * [Examples](/stateset-icommerce/examples) * [Returns Quickstart](/guides/returns-quickstart) * [Orders Quickstart](/guides/orders-quickstart) # iCommerce Quickstart Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-quickstart Get started with StateSet iCommerce using the CLI or deploy to your preferred cloud platform. # iCommerce Quickstart Get up and running with StateSet iCommerce in minutes. Install the CLI locally or deploy to your preferred cloud platform. ## Install the CLI Install the StateSet CLI globally using npm: ```bash theme={null} npm install -g @stateset/cli ``` Or use npx to run without installing: ```bash theme={null} npx @stateset/cli ``` ### Verify installation ```bash theme={null} stateset --version ``` ### Authenticate ```bash theme={null} stateset auth login ``` ### Run your first command ```bash theme={null} stateset "show me pending orders" ``` Use `--apply` flag to execute write operations. Without it, commands run in read-only mode for safety. ```bash theme={null} stateset --apply "ship order #12345 with tracking FEDEX123" ``` *** ## Deploy to the cloud Run StateSet iCommerce 24/7 on your preferred cloud platform. Each guide walks you through a complete production deployment with persistent storage and secure access. Deploy on GCP Compute Engine for \~\$5-12/month with automatic restarts and SSH tunnel access. The most cost-effective option at \~\$5/month on Hetzner VPS with Docker and persistent volumes. Deploy globally with automatic HTTPS and edge distribution for \~\$10-15/month. *** ## Prerequisites Before you begin, ensure you have: * StateSet account and API key * Node.js 18+ installed * Model provider credentials (Anthropic, OpenAI, etc.) *** ## Understand iCommerce Review the category overview and architecture to understand the core model: * [iCommerce Overview](/icommerce) * [iCommerce Architecture](/icommerce-architecture) *** ## Choose your build track Pick the track that matches your use case: | Track | Description | Best for | | ----------------------- | ------------------------------------ | -------------------- | | **StateSet One** | Core API and platform services | Backend integrations | | **StateSet ResponseCX** | AI-driven customer operations | Support automation | | **Agentic Commerce** | Conversational checkout and payments | Chat-based sales | *** ## Run a basic workflow Follow a quickstart guide to run a basic order or return flow: Create, update, and fulfill orders programmatically. Process returns and refunds with the Returns API. *** ## Next steps Install SDKs for Node.js, Python, and more. Full CLI command reference and workflows. Extend agent capabilities with custom skills. # iCommerce Returns Workflow Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-returns-workflow Deterministic returns, exchanges, and refunds. # iCommerce Returns Workflow This guide outlines a standard returns flow with deterministic steps for auditability. ## 1) Validate Eligibility Confirm policy requirements (window, condition, and item eligibility) before creating a return authorization. ## 2) Create Return Authorization Create the return record with line items, reason codes, and disposition expectations. ## 3) Receive and Inspect On receipt, inspect items and determine restock, refurbish, or reject actions. ## 4) Refund or Exchange Trigger a refund or exchange based on inspection outcomes and policy rules. ## 5) Close the Return Finalize the return record and update order, inventory, and financial state. ## Related Documentation * [Returns Quickstart](/guides/returns-quickstart) * [Warranty Quickstart](/guides/warranties-quickstart) # StateSet iCommerce Scenarios Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-scenarios Common real-world workflows built on the embedded engine. # StateSet iCommerce Scenarios These scenarios map to the runnable examples in the iCommerce repository and show how teams typically start. ## AI Customer Support Agent * Look up orders, update status, and issue refunds * Pair MCP tools with the CLI for safe, auditable actions * See the workflows and CLI references in the examples ## Offline POS with Sync * Run locally on SQLite and reconcile via VES when online * Ideal for intermittent connectivity and edge environments ## Subscription Billing and Invoicing * Create plans, subscriptions, and invoice flows * Automate renewals and invoice issuance through the engine ## Manufacturing and Procurement * Build BOMs, create work orders, and generate POs * Maintain a complete audit trail across inventory and purchasing ## Related Documentation * [Examples](/stateset-icommerce/examples) * [Sync & Auditability](/stateset-icommerce/sync) # iCommerce Skills Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-skills A collection of skills for operating the StateSet iCommerce engine. # iCommerce Skills A collection of skills for operating the StateSet iCommerce engine. **38 public skills** covering the full commerce lifecycle, plus **9 internal skills** for customer support and operations automation. ## Getting Started ### Install with npm (Claude Code) Global install (recommended): ```bash theme={null} npm install -g @stateset/icommerce-skills icommerce-skills list icommerce-skills install ``` Local install (repo checkout): ```bash theme={null} npm install npx icommerce-skills list npx icommerce-skills install ``` Defaults: * Installs to `~/.claude/skills`. * Override with `CLAUDE_HOME=/path/to/.claude` or `icommerce-skills install --dest /path/to/skills`. * Use `--force` to overwrite existing skills. ### Manual install (Claude Code) ```bash theme={null} cp -r skills/{skill-name} ~/.claude/skills/ ``` ### claude.ai Add the skill to project knowledge or paste the `SKILL.md` contents into the conversation. If a skill requires network access, add required domains at `claude.ai/settings/capabilities`. ## Skills at a Glance | # | Skill | Description | | -- | ------------------------- | -------------------------------------------------------------------------- | | 1 | commerce-engine-setup | Set up the iCommerce engine, CLI, demo data, and optional sync | | 2 | commerce-embedded-sdk | Integrate the embedded engine in application code across language bindings | | 3 | commerce-customers | Manage customer records and profiles | | 4 | commerce-products | Manage product catalog entries and variants | | 5 | commerce-inventory | Manage stock levels, adjustments, and reservations | | 6 | commerce-orders | Create orders and manage status transitions | | 7 | commerce-checkout | Run cart and checkout flows (ACP) | | 8 | commerce-payments | Process payments and refunds, including stablecoin flows | | 9 | commerce-shipments | Create shipments, tracking, and delivery updates | | 10 | commerce-returns | Handle return requests and refunds | | 11 | commerce-promotions | Create and apply promotions and coupons | | 12 | commerce-subscriptions | Manage subscription plans and billing cycles | | 13 | commerce-analytics | Report sales, customer metrics, and forecasts | | 14 | commerce-tax | Calculate tax and manage exemptions | | 15 | commerce-currency | Manage exchange rates and currency conversion | | 16 | commerce-invoices | Manage invoices and receivables | | 17 | commerce-suppliers | Manage suppliers and purchase orders | | 18 | commerce-sync | Manage VES sync, outbox, and conflicts | | 19 | commerce-storefront | Scaffold and build storefront projects | | 20 | commerce-customer-service | Handle cross-domain customer support flows | ## All iCommerce Engine Skills ### Core Commerce | Skill | Description | | ------------------------- | -------------------------------------------------------------------------- | | commerce-engine-setup | Set up the iCommerce engine, CLI, demo data, and optional sync | | commerce-embedded-sdk | Integrate the embedded engine in application code across language bindings | | commerce-customers | Manage customer records and profiles | | commerce-products | Manage product catalog entries and variants | | commerce-orders | Create orders and manage status transitions | | commerce-checkout | Run cart and checkout flows (ACP) | | commerce-payments | Process payments and refunds, including stablecoin flows | | commerce-storefront | Scaffold and build storefront projects | | commerce-customer-service | Handle cross-domain customer support flows | ### Inventory and Fulfillment | Skill | Description | | ------------------------- | ---------------------------------------------------------------- | | commerce-inventory | Manage stock levels, adjustments, and reservations | | commerce-shipments | Create shipments, tracking, and delivery updates | | commerce-returns | Handle return requests and refunds | | commerce-backorders | Manage backorders for out-of-stock items | | commerce-fulfillment | Manage fulfillment waves, pick tasks, pack tasks, and ship tasks | | commerce-receiving | Manage inbound goods receiving, inspection, and put-away | | commerce-warehouse | Manage warehouses, locations, and inventory movements | | commerce-lots-and-serials | Manage lot/batch tracking and serial number management | ### Financial | Skill | Description | | ---------------------------- | ------------------------------------------------------------------ | | commerce-invoices | Manage invoices and receivables | | commerce-tax | Calculate tax and manage exemptions | | commerce-currency | Manage exchange rates and currency conversion | | commerce-accounts-payable | Manage supplier bills, payments, and AP aging | | commerce-accounts-receivable | Manage customer receivables, collections, and AR aging | | commerce-cost-accounting | Manage item costs, cost layers, variances, and inventory valuation | | commerce-credit | Manage customer credit accounts, holds, and applications | | commerce-general-ledger | Manage the general ledger, chart of accounts, and journal entries | ### Marketing and Subscriptions | Skill | Description | | ---------------------- | -------------------------------------------- | | commerce-promotions | Create and apply promotions and coupons | | commerce-subscriptions | Manage subscription plans and billing cycles | ### Supply Chain and Manufacturing | Skill | Description | | ---------------------- | -------------------------------------------------------------- | | commerce-suppliers | Manage suppliers and purchase orders | | commerce-manufacturing | Manage BOMs and work orders | | commerce-warranties | Manage warranties and claims | | commerce-quality | Manage quality inspections, non-conformance reports, and holds | ### Analytics and Search | Skill | Description | | ---------------------- | ------------------------------------------------------------------------------------- | | commerce-analytics | Report sales, customer metrics, and forecasts | | commerce-vector-search | Perform semantic and keyword search across products, customers, orders, and inventory | | commerce-events | Inspect commerce events, manage the event audit trail, and idempotency keys | ### Platform and Automation | Skill | Description | | --------------------------- | -------------------------------------------------------------------------- | | commerce-sync | Manage VES sync, outbox, and conflicts | | commerce-autonomous-engine | Run the autonomous engine (scheduler, workflows, approvals) | | commerce-autonomous-runbook | Operational runbook for autonomous engine operations and incident response | | commerce-mcp-tools | Reference map for MCP tool names, parameters, and payload examples | ## Notes * Many skills include `references/` for deep docs and `scripts/` for repeatable commands. Use the script paths listed in each `SKILL.md`. * Each skill follows the structure defined in [AGENTS.md](AGENTS.md). ## Packaging ```bash theme={null} cd skills zip -r {skill-name}.zip {skill-name}/ ``` # Run the WhatsApp gateway Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-whatsapp-integration Run the WhatsApp channel gateway for iCommerce agents. # Run the WhatsApp gateway This guide helps you connect WhatsApp to iCommerce agent workflows. ## Prerequisites * WhatsApp account with access to Linked Devices * iCommerce CLI installed * Database path for iCommerce (`--db`) ## Connect WhatsApp and run the gateway 1. Start the gateway and display the QR code. 2. Scan the QR code in WhatsApp → Linked Devices. 3. Store credentials in `~/.stateset/whatsapp-auth/`. 4. Re-run to reconnect automatically. ```bash theme={null} stateset-whatsapp --db ./store.db ``` Use `--apply` only when you are ready to allow write actions. ## Verify the result Send a test message to the connected WhatsApp account and confirm the agent responds. ## Related tasks * [Messaging Channels with iCommerce](/stateset-icommerce-messaging-channels) * [iCommerce Agent](/stateset-icommerce-agent) # x402 Payments with iCommerce Source: https://docs.stateset.com/stateset-icommerce/stateset-icommerce-x402-payments HTTP-native micropayments with x402, signed off-chain and sequenced on Set L2. # x402 Payments with iCommerce x402 is an HTTP-native payment protocol used by iCommerce agents. It relies on HTTP 402 responses and signed payment intents that are sequenced and settled through the StateSet Sequencer. ## Protocol Flow 1. Client requests a resource from a paywalled API. 2. Server returns HTTP 402 with `X-Payment-Required`. 3. Client creates and signs an `X402PaymentIntent`. 4. Client retries with `X-Payment` header. 5. Payment intent is sequenced and batched. 6. Batch is committed and later settled on Set Chain L2. 7. The server verifies payment using inclusion proofs. ## iCommerce Implementation The iCommerce CLI includes x402 helpers and demos: * `stateset-icommerce/cli/src/x402/*` * `stateset-icommerce/cli/examples/x402_payment_demo.mjs` * `stateset-icommerce/cli/examples/x402_client_real.mjs` * `stateset-icommerce/cli/examples/x402_server_real.mjs` ## Example: x402 Payment Demo ```bash theme={null} node stateset-icommerce/cli/examples/x402_payment_demo.mjs ``` ## Signed Intent Basics The intent includes payer/payee, amount, network, validity window, and a signature hash. Signing uses the domain separator `X402_PAYMENT_V1` and Ed25519 signatures. ## Related Documentation * [Sequencer x402 Payments](/stateset-sequencer-x402) * [Set L2 Overview](/stateset-set-l2) # Neuro-Symbolic Architecture Source: https://docs.stateset.com/stateset-nsr A vision for trustworthy, explainable, and governable AI applications through Neuro-Symbolic Systems. # The Future of Enterprise AI: Verified Intelligence Through Neuro-Symbolic Systems **A Vision for Trustworthy, Explainable, and Governable AI Applications** *** ## Executive Summary The first wave of enterprise AI adoption brought Large Language Models (LLMs) into production—powering chatbots, content generation, and code assistance. But as organizations move from experimentation to mission-critical deployment, a fundamental limitation has emerged: **LLMs alone cannot be trusted with consequential decisions**. The next wave of enterprise AI will be defined by **Neuro-Symbolic Systems**—architectures that combine the linguistic fluency of LLMs with the logical rigor of symbolic reasoning engines like NSR-L. This hybrid approach delivers what enterprises actually need: * **Verified outputs** that comply with business rules * **Explainable decisions** that auditors can trace * **Governable systems** that policy teams can control * **Adaptive intelligence** that learns while preserving constraints This document outlines the architecture, capabilities, and trajectory of this paradigm shift. *** ## The Problem: The LLM Trust Gap ### What LLMs Do Well Large Language Models excel at: * Natural language understanding and generation * Pattern recognition across vast knowledge * Flexible reasoning about ambiguous inputs * Human-like conversational flow ### What LLMs Cannot Guarantee Despite their capabilities, LLMs fundamentally cannot: | Requirement | LLM Limitation | | ---------------------------- | -------------------------------------- | | **Deterministic compliance** | May violate policies unpredictably | | **Logical consistency** | Can contradict itself within a session | | **Auditable reasoning** | "Black box" decision process | | **Bounded behavior** | No hard limits on outputs | | **Knowledge currency** | Training data has cutoff date | | **Mathematical precision** | Arithmetic errors common | ### The Enterprise Reality For customer service, a chatbot saying the wrong thing is embarrassing. For healthcare, it could be lethal. For finance, it could be illegal. For legal, it could be malpractice. **The trust gap is not a bug to be fixed—it's an architectural limitation.** Prompt engineering, fine-tuning, and RLHF improve averages but cannot provide guarantees. Enterprises need systems that are **correct by construction**, not just **usually correct**. *** ## The Solution: Neuro-Symbolic Architecture ### The Core Insight The breakthrough is recognizing that **natural language understanding** and **logical reasoning** are different capabilities that should be handled by different systems: ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ Neuro-Symbolic Enterprise AI │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ NEURAL LAYER (LLM) SYMBOLIC LAYER (NSR-L) │ │ ───────────────── ────────────────────── │ │ • Language understanding • Business rule enforcement │ │ • Intent extraction • Logical constraint validation │ │ • Response generation • Policy-driven function selection │ │ • Contextual reasoning • Audit trail generation │ │ • Empathy & tone • Belief revision & learning │ │ │ │ ┌───────────────────┐ │ │ │ ORCHESTRATION │ │ │ │ (Temporal) │ │ │ └───────────────────┘ │ │ │ │ INPUT ──► Neural Parse ──► Symbolic Verify ──► Neural Generate ──► Symbolic │ │ Validate ──► OUTPUT │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` ### Division of Responsibilities | Capability | Neural (LLM) | Symbolic (NSR-L) | | ---------------------- | ------------ | ---------------- | | Language fluency | ✓ | | | Intent detection | ✓ | | | Constraint enforcement | | ✓ | | Policy compliance | | ✓ | | Response generation | ✓ | | | Response validation | | ✓ | | Function selection | | ✓ | | Explainability | | ✓ | | Continuous learning | ✓ | ✓ | *** ## The NSR-L Advantage ### What is NSR-L? **NSR-L (Neuro-Symbolic Reasoning Language)** is a logic programming language designed for AI governance. It combines: * **First-order logic** for expressive rule definition * **Prolog-style inference** for efficient reasoning * **Belief revision** for uncertainty handling * **Hard/soft constraints** for flexible policy enforcement * **Continuous learning** for adaptive rules ### Why Symbolic Reasoning Matters **1. Guarantees, Not Probabilities** ```prolog theme={null} % This is a GUARANTEE, not a suggestion prohibited_phrase("contact the manufacturer"). response_invalid(R) :- contains_text(R, P), prohibited_phrase(P). ``` If the LLM generates a response containing a prohibited phrase, the symbolic layer **will** catch it. Not 99.9% of the time—100% of the time. **2. Explainable Decisions** ```prolog theme={null} % Every decision has a traceable proof should_escalate(allergic_reaction) :- requires_human_review(allergic_reaction). % Query: Why was this escalated? % Answer: because requires_human_review(allergic_reaction) is true % which is defined in policy document v2.3, line 47 ``` **3. Governable by Non-Engineers** ```prolog theme={null} % Business analysts can read and modify rules return_eligible(Order) :- days_since_purchase(Order, Days), Days =< 30. % Change policy? Change one number. ``` **4. Composable Constraints** ```prolog theme={null} % Hard constraint: Never violate ~permitted(issue_refund) :- detected_topic(allergic_reaction). % Soft constraint: Prefer but allow override should_include(waitlist_link) :- asks_about(wide_awake), out_of_stock(wide_awake). ``` *** ## Architecture Patterns for Enterprise AI ### Pattern 1: Verified Response Generation The most common pattern—validate LLM outputs before delivery. ``` Customer Query │ ▼ ┌─────────────┐ │ LLM Agent │ ──► Generate response └─────────────┘ │ ▼ ┌─────────────┐ │ NSR-L │ ──► Validate against rules │ Validator │ • Check prohibited phrases └─────────────┘ • Verify required elements │ • Confirm policy compliance ├──── PASS ──► Deliver to customer │ └──── FAIL ──► Regenerate or escalate ``` **Use Cases:** * Customer service chatbots * Email response generation * Content moderation * Legal document drafting ### Pattern 2: Policy-Driven Function Calling The symbolic layer decides what actions are permitted—the LLM never sees unauthorized options. ``` Customer: "I want a refund for my allergic reaction" │ ▼ ┌─────────────┐ │ LLM │ ──► Extract: {intent: refund, topic: allergic_reaction} │ (Parse) │ └─────────────┘ │ ▼ ┌─────────────┐ Query: ?- permitted_function(F). │ NSR-L │ ──► Result: [lookup_order, escalate_to_human] │ (Policy) │ Blocked: [issue_refund, send_replacement] └─────────────┘ │ ▼ ┌─────────────┐ │ LLM │ ──► Generate response using ONLY permitted actions │ (Generate) │ "I'm so sorry to hear about your reaction. └─────────────┘ I've escalated this to our specialist team..." ``` **Use Cases:** * Agentic AI with tool use * Autonomous workflow execution * RPA with AI decision-making * Multi-step task automation ### Pattern 3: Recursive Self-Improvement The system learns new rules from experience while preserving validated constraints. ``` ┌─────────────────────────────────────────────────────────────────────┐ │ RECURSIVE LEARNING LOOP │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Interaction ──► Outcome ──► Pattern Detection ──► Rule Proposal │ │ ▲ │ │ │ │ ▼ │ │ │ ┌──────────────┐ │ │ │ │ Consistency │ │ │ │ │ Validation │ │ │ │ └──────┬───────┘ │ │ │ │ │ │ │ ┌────────────────┬──────────┘ │ │ │ ▼ ▼ │ │ │ ┌─────────┐ ┌──────────┐ │ │ │ │ REJECT │ │ ADD AS │ │ │ │ │ │ │ SOFT │ │ │ │ └─────────┘ │ BELIEF │ │ │ │ └────┬─────┘ │ │ │ │ │ │ │ Accumulate Evidence │ │ │ │ ──────────────────── │ │ │ │ ▼ │ │ │ ┌─────────────┐ │ │ │ │ PROMOTE TO │ │ │ │ │ HARD RULE │ │ │ └────────────────────────────┴─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` **Use Cases:** * Adaptive fraud detection * Evolving compliance rules * Self-tuning recommendation systems * Continuous policy refinement ### Pattern 4: Multi-Agent Orchestration Multiple specialized agents coordinated by symbolic reasoning. ``` ┌─────────────────────┐ │ ORCHESTRATOR │ │ (NSR-L + Temporal) │ └──────────┬──────────┘ │ ┌────────────────────────┼────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Research │ │ Analysis │ │ Writing │ │ Agent │ │ Agent │ │ Agent │ │ (Claude) │ │ (GPT-5) │ │ (Claude) │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └────────────────────────┼────────────────────────┘ │ ▼ ┌─────────────────────┐ │ VALIDATOR │ │ (NSR-L) │ │ • Fact-check │ │ • Consistency │ │ • Policy check │ └─────────────────────┘ ``` **Use Cases:** * Complex research tasks * Report generation with verification * Multi-model ensemble systems * Collaborative AI workflows *** ## Industry Applications ### Financial Services **Challenge:** Regulations require explainable AI decisions for lending, trading, and fraud detection. **Solution:** ```prolog theme={null} % Lending decision with full audit trail loan_approved(Application) :- credit_score(Application, Score), Score >= 650, debt_to_income(Application, DTI), DTI =< 0.43, employment_verified(Application), ~fraud_indicators(Application). % Every rejection has a reason code rejection_reason(Application, "credit_score") :- credit_score(Application, Score), Score < 650. ``` **Benefits:** * Regulatory compliance (ECOA, FCRA) * Auditable decisions * Consistent treatment * Reduced discrimination risk ### Healthcare **Challenge:** Medical AI must never give dangerous advice, and must know when to defer. **Solution:** ```prolog theme={null} % Hard constraints on medical advice ~can_diagnose(Condition) :- requires_physician(Condition). ~can_recommend(Medication) :- prescription_required(Medication). % Mandatory escalation must_escalate(emergency) :- symptom_detected(chest_pain) | symptom_detected(difficulty_breathing). % Safe information only can_provide(general_wellness_info). can_provide(appointment_scheduling). can_suggest(see_doctor) :- symptom_present(_). ``` **Benefits:** * Patient safety guarantees * Liability protection * Appropriate care escalation * Regulatory compliance (HIPAA, FDA) ### Legal **Challenge:** Legal AI must cite sources, acknowledge uncertainty, and never fabricate precedents. **Solution:** ```prolog theme={null} % Citation requirements response_valid(R) :- legal_claim(R, Claim) -> has_citation(R, Claim, Source), verified_source(Source). % Uncertainty acknowledgment must_include_disclaimer(R) :- jurisdiction_specific(R) | fact_dependent(R) | recent_law_change(R). % Anti-hallucination ~can_cite(Case) :- \+ exists_in_database(Case). ``` **Benefits:** * Reduced malpractice risk * Verifiable research * Client trust * Bar compliance ### E-Commerce / Customer Service **Challenge:** Brand consistency, policy compliance, and appropriate escalation. **Solution:** ```prolog theme={null} % Brand voice constraints prohibited_phrase("per our policy"). prohibited_phrase("unfortunately"). required_element(empathy_statement) :- negative_sentiment(Query). % Policy enforcement return_eligible(Order) :- days_since_purchase(Order, D), D =< 30. ~can_promise(refund) :- ~return_eligible(Order). % Escalation triggers requires_human(allergic_reaction). requires_human(legal_threat). requires_human(social_media_mention). ``` **Benefits:** * Consistent customer experience * Reduced escalations * Policy compliance * Brand protection *** ## The Technology Stack ### Reference Architecture ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ ENTERPRISE AI PLATFORM │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ APPLICATION LAYER │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Customer │ │ Employee │ │ Document │ │ Workflow │ │ │ │ │ │ Service │ │ Assistant │ │ Processing │ │ Automation │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ ORCHESTRATION LAYER │ │ │ │ ┌──────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ TEMPORAL WORKFLOWS │ │ │ │ │ │ • Durable execution • Retry policies • Human-in-the-loop │ │ │ │ │ │ • State management • Timeouts • Saga patterns │ │ │ │ │ └──────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ REASONING LAYER │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ │ │ NEURAL (LLMs) │ │ SYMBOLIC (NSR-L) │ │ │ │ │ │ ┌─────────┐ ┌────────┐ │ │ ┌───────────┐ ┌─────────────┐ │ │ │ │ │ │ │ Claude │ │ GPT-5 │ │◄─────────►│ │ Rules │ │ Constraints │ │ │ │ │ │ │ │ Opus │ │ │ │ │ │ Engine │ │ Validator │ │ │ │ │ │ │ └─────────┘ └────────┘ │ │ └───────────┘ └─────────────┘ │ │ │ │ │ │ ┌─────────┐ ┌────────┐ │ │ ┌───────────┐ ┌─────────────┐ │ │ │ │ │ │ │ Gemini │ │ Llama │ │ │ │ Belief │ │ Proof │ │ │ │ │ │ │ │ │ │ │ │ │ │ Revision │ │ Generator │ │ │ │ │ │ │ └─────────┘ └────────┘ │ │ └───────────┘ └─────────────┘ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ KNOWLEDGE LAYER │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Policy │ │ Domain │ │ Belief │ │ Audit │ │ │ │ │ │ Repository │ │ Knowledge │ │ Store │ │ Log │ │ │ │ │ │ (.nsrl) │ │ Base │ │ │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` ### Component Roles | Component | Technology | Purpose | | --------------------- | --------------------- | ------------------------------------ | | **LLMs** | Claude, GPT-5, Gemini | Language understanding, generation | | **NSR-L Engine** | Stateset NSR | Rule evaluation, constraint checking | | **Temporal** | Temporal.io | Workflow orchestration, durability | | **Policy Repository** | Git + .nsrl files | Version-controlled business rules | | **Belief Store** | PostgreSQL + NSR | Confidence-weighted knowledge | | **Audit Log** | Immutable store | Compliance, debugging, improvement | *** ## The Path Forward ### Phase 1: Guardrails (Now) **Focus:** Validate LLM outputs against known constraints. ``` LLM Output ──► NSR-L Validator ──► Pass/Fail ``` **Capabilities:** * Prohibited content detection * Required element verification * Format compliance * Policy adherence **Adoption:** Customer service, content moderation, document review ### Phase 2: Governance (2025) **Focus:** Control what actions AI can take, not just what it says. ``` User Intent ──► NSR-L Policy ──► Permitted Actions ──► LLM Execution ``` **Capabilities:** * Function-level permissions * Context-aware authorization * Escalation routing * Audit trails **Adoption:** Agentic AI, workflow automation, autonomous systems ### Phase 3: Learning (2026) **Focus:** Systems that improve while maintaining guarantees. ``` Interactions ──► Pattern Detection ──► Rule Proposals ──► Validation ──► Promotion ``` **Capabilities:** * Belief revision from evidence * Soft rule promotion * Catastrophic forgetting prevention * Human-in-the-loop refinement **Adoption:** Adaptive fraud detection, evolving compliance, personalization ### Phase 4: Reasoning (2027+) **Focus:** Deep integration where neural and symbolic systems co-reason. ``` Complex Query ──► Hybrid Reasoning ──► Verified Conclusion + Proof ``` **Capabilities:** * Multi-hop reasoning with verification * Causal inference with uncertainty * Counterfactual analysis * Scientific discovery support **Adoption:** Research, drug discovery, strategic planning *** ## Why This Matters ### For Enterprises | Without Neuro-Symbolic | With Neuro-Symbolic | | ------------------------------------- | ----------------------------------- | | "The AI said something wrong" | "The system caught the error" | | "We can't explain the decision" | "Here's the proof trace" | | "We need manual review of everything" | "Symbolic layer handles validation" | | "Compliance is a nightmare" | "Rules are auditable and versioned" | | "AI behavior is unpredictable" | "Behavior is bounded by policy" | ### For Society As AI systems become more autonomous and consequential, the ability to: * **Verify** that they follow rules * **Explain** why they made decisions * **Govern** their behavior through policy * **Audit** their actions after the fact ...becomes not just desirable but **essential**. Neuro-symbolic systems provide the technical foundation for **trustworthy AI**—systems that humans can understand, control, and rely upon. *** ## Conclusion The future of enterprise AI is not choosing between neural networks and symbolic reasoning—it's combining them. LLMs provide the interface to human language and flexible reasoning. Symbolic systems provide the guarantees, governance, and explainability that enterprises require. **NSR-L represents this synthesis:** a language designed from the ground up for AI governance, integrated with modern LLM architectures through durable workflow orchestration. The organizations that master this hybrid approach will deploy AI systems that are: * **More capable** (combining neural and symbolic strengths) * **More trustworthy** (verified, not just validated) * **More governable** (policy-driven, not prompt-driven) * **More adaptable** (learning while preserving constraints) The question is not whether to adopt neuro-symbolic architecture, but how quickly your organization can build the expertise to leverage it. *** ## Further Reading * [NSR-L Language Reference](./nsrl_language_reference.md) - Complete language specification * [YSE Beauty API Workflow](./yse_beauty_api_workflow.md) - Production example * [Temporal Agent Orchestration](./temporal_agent_orchestration.md) - Integration patterns * [Recursive Policy Learning](./recursive_policy_learning.md) - Self-improving systems *** *This document represents Stateset's vision for the future of enterprise AI. The technology described is available today through the Stateset NSR platform.* # NSR-L Language Reference Source: https://docs.stateset.com/stateset-nsr-l Prolog-inspired logic programming language for symbolic reasoning, constraint specification, and knowledge representation in AI systems. # NSR-L Language Reference **NSR-L** (Neuro-Symbolic Reasoning Language) is a Prolog-inspired logic programming language designed for symbolic reasoning, constraint specification, and knowledge representation in AI systems. ## Table of Contents 1. [Overview](#overview) 2. [Lexical Elements](#lexical-elements) 3. [Terms](#terms) 4. [Logical Expressions](#logical-expressions) 5. [Statements](#statements) 6. [Operators](#operators) 7. [Built-in Predicates](#built-in-predicates) 8. [List Operations](#list-operations) 9. [Arithmetic](#arithmetic) 10. [Constraints](#constraints) 11. [Negation](#negation) 12. [Quantifiers](#quantifiers) 13. [Comments](#comments) 14. [Complete Grammar](#complete-grammar) 15. [Examples](#examples) *** ## Overview NSR-L combines classical logic programming with modern features for AI guardrails: * **First-order logic** with variables, predicates, and quantifiers * **Prolog-style rules** with `Head :- Body` syntax * **Classical and non-monotonic negation** (`~` and `\+`) * **Hard and soft constraints** for flexible validation * **Arithmetic evaluation** with the `is` operator * **List operations** for data manipulation * **Belief revision** with confidence intervals ### Hello World ```prolog theme={null} % Facts human(socrates). human(plato). % Rules mortal(X) :- human(X). % Query ?- mortal(socrates). ``` *** ## Lexical Elements ### Atoms Atoms are constant identifiers. They must start with a lowercase letter or be quoted. ```prolog theme={null} % Unquoted atoms (start with lowercase) hello customer_service product123 x % Quoted atoms (any characters) 'Hello World' 'contains spaces' 'special-chars!' ``` ### Variables Variables start with an uppercase letter or underscore. ```prolog theme={null} X % Regular variable Name % Descriptive variable CustomerID % CamelCase variable _ % Anonymous variable (matches anything, not bound) _Unused % Named but intentionally unused ``` **Important:** Variables starting with `_` suppress singleton variable warnings. ### Numbers ```prolog theme={null} 42 % Integer -17 % Negative integer 3.14 % Float -0.5 % Negative float 1.0e10 % Scientific notation ``` ### Strings ```prolog theme={null} "hello world" % Double-quoted string "contains \"quotes\"" % Escaped quotes "line1\nline2" % Escape sequences ``` *** ## Terms Terms are the fundamental data structures in NSR-L. ### Constants ```prolog theme={null} atom % Atom constant 42 % Integer constant 3.14 % Float constant "string" % String constant ``` ### Variables ```prolog theme={null} X % Unbound variable _ % Anonymous variable ``` ### Compound Terms (Functors) ```prolog theme={null} person(john, 30) % Functor with arguments node(left(a), right(b)) % Nested structure pair(X, Y) % With variables address(city("NYC"), zip(10001)) % Complex nesting ``` ### Lists Lists use square bracket notation with `|` for head/tail decomposition. ```prolog theme={null} [] % Empty list [a, b, c] % List of atoms [1, 2, 3] % List of integers [X, Y, Z] % List of variables [Head | Tail] % Head/tail decomposition [A, B | Rest] % First two elements + rest [[1,2], [3,4]] % Nested lists ``` *** ## Logical Expressions ### Atomic Propositions ```prolog theme={null} predicate(arg1, arg2, ...) ``` Examples: ```prolog theme={null} human(socrates) parent(tom, mary) age(john, 30) product(wide_awake, eye_cream) ``` ### Conjunction (AND) Use `&` or `,` for conjunction: ```prolog theme={null} human(X) & mortal(X) % Using & human(X), mortal(X) % Using , parent(X, Y) & parent(Y, Z) % Grandparent pattern ``` ### Disjunction (OR) Use `|` or `;` for disjunction: ```prolog theme={null} male(X) | female(X) % Using | cat(X) ; dog(X) % Using ; ``` ### Implication ```prolog theme={null} Head :- Body % Prolog-style rule human(X) -> mortal(X) % Arrow notation A <-> B % Biconditional (iff) ``` ### Negation ```prolog theme={null} ~positive(X) % Classical negation (strong) \+ found(X) % Negation as failure (weak) not(present(X)) % Alternative NAF syntax ``` *** ## Statements NSR-L programs consist of three types of statements: ### Facts Facts are ground assertions (no variables, or universally quantified). ```prolog theme={null} human(socrates). product(wide_awake, eye_cream). return_window_days(30). prohibited_phrase("contact the manufacturer"). ~ships_internationally. % Negative fact ``` ### Rules Rules define logical implications with head and body. ```prolog theme={null} % Basic rule mortal(X) :- human(X). % Rule with conjunction grandparent(X, Z) :- parent(X, Y) & parent(Y, Z). % Rule with disjunction animal(X) :- cat(X) | dog(X) | bird(X). % Rule with negation eligible(X) :- member(X) & ~suspended(X). % Rule with comparison adult(X) :- age(X, Age) & Age >= 18. % Complex rule response_valid(R) :- ~response_invalid(R) & ~contains_internal_reasoning(R) & ~promises_replacement(R). ``` ### Queries Queries ask the system to prove or find solutions. ```prolog theme={null} ?- mortal(socrates). % Yes/no query ?- parent(X, mary). % Find X ?- ancestor(X, Y). % Find all pairs ?- age(john, Age), Age > 18. % Query with condition ``` *** ## Operators ### Logical Operators | Operator | Meaning | Example | | -------- | ------------------- | ----------------------- | | `&` | Conjunction (AND) | `a(X) & b(X)` | | `,` | Conjunction (AND) | `a(X), b(X)` | | `\|` | Disjunction (OR) | `a(X) \| b(X)` | | `;` | Disjunction (OR) | `a(X) ; b(X)` | | `~` | Classical negation | `~alive(X)` | | `\+` | Negation as failure | `\+ found(X)` | | `not` | Negation as failure | `not(found(X))` | | `->` | Implication | `human(X) -> mortal(X)` | | `:-` | Rule implication | `head :- body` | | `<->` | Biconditional | `a <-> b` | ### Comparison Operators | Operator | Meaning | Example | | ------------ | -------------------- | ------------- | | `=` | Unification | `X = foo` | | `\=` | Not unifiable | `X \= Y` | | `==` | Identical | `X == Y` | | `\==` | Not identical | `X \== Y` | | `<` | Less than | `X < 10` | | `>` | Greater than | `X > 0` | | `=<` or `<=` | Less or equal | `X =< 100` | | `>=` | Greater or equal | `X >= 0` | | `=:=` | Arithmetic equal | `X + 1 =:= Y` | | `=\=` | Arithmetic not equal | `X =\= 0` | ### Arithmetic Operators | Operator | Meaning | Example | | ------------ | ---------------- | --------- | | `+` | Addition | `X + Y` | | `-` | Subtraction | `X - Y` | | `*` | Multiplication | `X * Y` | | `/` | Division | `X / Y` | | `//` | Integer division | `X // Y` | | `mod` or `%` | Modulo | `X mod Y` | ### Operator Precedence (lowest to highest) 1. `:-`, `->`, `<->` 2. `;`, `|` 3. `,`, `&` 4. `\+`, `not`, `~` 5. `=`, `\=`, `<`, `>`, `=<`, `>=`, `=:=`, `=\=` 6. `+`, `-` 7. `*`, `/`, `//`, `mod` 8. Unary `-` *** ## Built-in Predicates ### Unification & Comparison ```prolog theme={null} X = Y % Unify X and Y X \= Y % X and Y do not unify X == Y % X and Y are identical X \== Y % X and Y are not identical ``` ### Type Checking ```prolog theme={null} atom(X) % X is an atom number(X) % X is a number integer(X) % X is an integer float(X) % X is a float compound(X) % X is a compound term is_list(X) % X is a list var(X) % X is unbound nonvar(X) % X is bound ground(X) % X contains no variables ``` ### Arithmetic Evaluation ```prolog theme={null} X is Expr % Evaluate Expr and bind to X % Examples: Sum is 2 + 3. % Sum = 5 Prod is X * Y. % Prod = X * Y Mod is 17 mod 5. % Mod = 2 ``` ### Arithmetic Functions ```prolog theme={null} abs(X) % Absolute value min(X, Y) % Minimum max(X, Y) % Maximum sqrt(X) % Square root X ** Y % Power (X^Y) sin(X), cos(X), tan(X) % Trigonometric log(X), exp(X) % Logarithm, exponential floor(X), ceiling(X) % Rounding round(X) % Round to nearest integer ``` ### Control ```prolog theme={null} ! % Cut (commit to current choice) true % Always succeeds false % Always fails fail % Always fails ``` *** ## List Operations NSR-L provides Prolog-standard list predicates. ### member/2 Check if element is in list, or enumerate elements. ```prolog theme={null} member(X, [a, b, c]) % X = a; X = b; X = c member(b, [a, b, c]) % true member(d, [a, b, c]) % false ``` ### append/3 Concatenate lists or split a list. ```prolog theme={null} append([1,2], [3,4], Result) % Result = [1,2,3,4] append(X, [4,5], [1,2,3,4,5]) % X = [1,2,3] append(X, Y, [a,b,c]) % Generate all splits ``` ### length/2 Get or check list length. ```prolog theme={null} length([a,b,c], N) % N = 3 length(L, 5) % L = [_,_,_,_,_] ``` ### reverse/2 Reverse a list. ```prolog theme={null} reverse([1,2,3], R) % R = [3,2,1] ``` ### nth0/3, nth1/3 Access element by index. ```prolog theme={null} nth0(0, [a,b,c], X) % X = a (0-indexed) nth1(1, [a,b,c], X) % X = a (1-indexed) nth0(Index, [a,b,c], b) % Index = 1 ``` ### last/2 Get last element. ```prolog theme={null} last([a,b,c], X) % X = c ``` ### sort/2, msort/2 Sort lists. ```prolog theme={null} sort([3,1,2,1], S) % S = [1,2,3] (removes duplicates) msort([3,1,2,1], S) % S = [1,1,2,3] (keeps duplicates) ``` ### sumlist/2 Sum numeric elements. ```prolog theme={null} sumlist([1,2,3,4], Sum) % Sum = 10 ``` ### flatten/2 Flatten nested lists. ```prolog theme={null} flatten([[1,2],[3,[4,5]]], F) % F = [1,2,3,4,5] ``` ### permutation/2 Generate or check permutations. ```prolog theme={null} permutation([1,2,3], P) % P = [1,2,3]; P = [1,3,2]; ... ``` *** ## Arithmetic ### The `is` Operator Evaluates arithmetic expressions and binds result. ```prolog theme={null} X is 2 + 3. % X = 5 Y is X * 2. % Y = 10 Z is sqrt(16). % Z = 4.0 ``` ### Arithmetic Comparisons ```prolog theme={null} X < Y % X less than Y X > Y % X greater than Y X =< Y % X less than or equal to Y X >= Y % X greater than or equal to Y X =:= Y % X arithmetically equal to Y X =\= Y % X arithmetically not equal to Y ``` ### Examples ```prolog theme={null} % Check if adult adult(Person) :- age(Person, Age), Age >= 18. % Calculate discount final_price(Product, Price) :- base_price(Product, Base), discount(Product, Percent), Price is Base * (100 - Percent) / 100. % Factorial (recursive) factorial(0, 1). factorial(N, F) :- N > 0, N1 is N - 1, factorial(N1, F1), F is N * F1. ``` *** ## Constraints NSR-L supports hard, soft, and weighted constraints for validation. ### Constraint Types | Type | Behavior | Use Case | | ------------ | ------------------------------ | ---------------------------------- | | **Hard** | Violation = rejection | Prohibited phrases, security rules | | **Soft** | Violation = confidence penalty | Style guidelines, recommendations | | **Weighted** | Contributes to score | Optimization objectives | ### Defining Constraints in Rules ```prolog theme={null} % Hard constraint: Never say prohibited phrases response_invalid(R) :- prohibited_phrase(P) & contains_text(R, P). % Soft preference: Include link when relevant should_include_link(R, Link) :- topic_detected(R, Topic) & required_link(Topic, Link) & ~contains_text(R, Link). ``` ### Constraint API (HTTP) ```json theme={null} { "id": "no_prohibited_phrases", "description": "Response must not contain prohibited phrases", "strength": {"type": "hard"}, "expression": "~violates_prohibited_phrase(Response, Phrase)", "source": "domain_rule" } ``` *** ## Negation NSR-L supports two forms of negation: ### Classical Negation (`~`) Strong negation that asserts the opposite is true. ```prolog theme={null} ~alive(X) % X is definitely not alive ~ships_internationally. % Definitely does not ship internationally ``` ### Negation as Failure (`\+` or `not`) Weak negation - true if the goal cannot be proven. ```prolog theme={null} \+ found(X) % X was not found (maybe doesn't exist) not(member(X, L)) % X is not provably in L ``` ### Difference ```prolog theme={null} % Classical: We know X is not alive ~alive(zombie). % NAF: We cannot prove X is alive (doesn't mean X is dead) \+ alive(X). ``` ### Closed World Assumption NAF follows the closed-world assumption: if something cannot be proven true, it is assumed false. ```prolog theme={null} % Database only has: employee(alice). employee(bob). % Query: Is carol an employee? ?- employee(carol). % Fails (no fact) ?- \+ employee(carol). % Succeeds (NAF) ?- ~employee(carol). % Fails (no explicit negative fact) ``` *** ## Quantifiers NSR-L supports first-order quantifiers. ### Universal Quantification (forall) ```prolog theme={null} forall X (human(X) -> mortal(X)) ``` Equivalent rule form: ```prolog theme={null} mortal(X) :- human(X). % Implicitly forall X ``` ### Existential Quantification (exists) ```prolog theme={null} exists X (person(X) & rich(X)) ``` Can be expressed as: ```prolog theme={null} has_rich_person :- person(X), rich(X). ``` ### Scoping ```prolog theme={null} % All humans have some parent forall X (human(X) -> exists Y parent(Y, X)) % There exists someone who is everyone's friend exists X forall Y friend(X, Y) ``` *** ## Comments ### Line Comments ```prolog theme={null} % This is a line comment human(socrates). % Inline comment ``` ### Multi-line Comments (block style in code) ```prolog theme={null} % ============================================================================== % SECTION HEADER % ============================================================================== % % Multiple lines of explanation. % Each line starts with %. % % ============================================================================== ``` *** ## Complete Grammar ### EBNF Grammar ```ebnf theme={null} program = { statement } ; statement = fact | rule | query ; fact = expression "." ; rule = expression ":-" expression "." ; query = "?-" expression "." ; expression = disjunction ; disjunction = conjunction { ( "|" | ";" ) conjunction } ; conjunction = unary { ( "&" | "," ) unary } ; unary = "~" unary | "\+" unary | "not" "(" expression ")" | "forall" variable "(" expression ")" | "exists" variable "(" expression ")" | comparison ; comparison = arithmetic [ comp_op arithmetic ] ; comp_op = "=" | "\=" | "==" | "\==" | "<" | ">" | "=<" | "<=" | ">=" | "=:=" | "=\=" | "is" ; arithmetic = term { ( "+" | "-" ) term } ; term = factor { ( "*" | "/" | "//" | "mod" | "%" ) factor } ; factor = [ "-" ] primary ; primary = atom [ "(" args ")" ] | variable | number | string | list | "(" expression ")" | "!" ; (* cut *) args = expression { "," expression } ; list = "[" [ list_items ] "]" ; list_items = expression { "," expression } [ "|" expression ] ; atom = lowercase { alphanumeric | "_" } | "'" { any_char } "'" ; variable = uppercase { alphanumeric | "_" } | "_" { alphanumeric | "_" } ; number = integer | float ; integer = [ "-" ] digit { digit } ; float = [ "-" ] digit { digit } "." digit { digit } [ exponent ] ; exponent = ( "e" | "E" ) [ "+" | "-" ] digit { digit } ; string = '"' { string_char } '"' ; string_char = any_char_except_quote | '\\"' | "\\n" | "\\t" | "\\\\" ; lowercase = "a" | ... | "z" ; uppercase = "A" | ... | "Z" | "_" ; digit = "0" | ... | "9" ; alphanumeric = lowercase | uppercase | digit ; ``` *** ## Examples ### Example 1: Family Relationships ```prolog theme={null} % Facts parent(tom, mary). parent(tom, jim). parent(mary, ann). parent(mary, pat). parent(jim, bob). male(tom). male(jim). male(bob). male(pat). female(mary). female(ann). % Rules father(X, Y) :- parent(X, Y) & male(X). mother(X, Y) :- parent(X, Y) & female(X). grandparent(X, Z) :- parent(X, Y) & parent(Y, Z). ancestor(X, Y) :- parent(X, Y). ancestor(X, Y) :- parent(X, Z) & ancestor(Z, Y). sibling(X, Y) :- parent(P, X) & parent(P, Y) & X \= Y. % Queries ?- father(tom, X). % X = mary; X = jim ?- grandparent(tom, X). % X = ann; X = pat; X = bob ?- sibling(mary, X). % X = jim ``` ### Example 2: Customer Service Rules ```prolog theme={null} % Products product(wide_awake, eye_cream). product(skin_glow_primer, primer). has_mini(skin_glow_primer). ~has_mini(wide_awake). % Prohibited phrases prohibited_phrase("contact the manufacturer"). prohibited_phrase("30-40 pumps"). % Validation rules response_invalid(R) :- prohibited_phrase(P) & contains_text(R, P). response_valid(R) :- ~response_invalid(R) & ~contains_internal_reasoning(R). % Escalation rules requires_escalation(allergic_reaction). requires_escalation(skin_irritation). should_escalate(Topic) :- requires_escalation(Topic) & detected_topic(Topic). % Topic detection topic_detected(Inquiry, returns) :- contains_text(Inquiry, "return") | contains_text(Inquiry, "refund"). topic_detected(Inquiry, allergic_reaction) :- contains_text(Inquiry, "allergic") | contains_text(Inquiry, "rash"). ``` ### Example 3: Arithmetic and Lists ```prolog theme={null} % Sum of list sum([], 0). sum([H|T], S) :- sum(T, S1), S is H + S1. % List length len([], 0). len([_|T], N) :- len(T, N1), N is N1 + 1. % Maximum in list max_list([X], X). max_list([H|T], Max) :- max_list(T, MaxT), Max is max(H, MaxT). % Filter positive numbers filter_positive([], []). filter_positive([H|T], [H|R]) :- H > 0, filter_positive(T, R). filter_positive([H|T], R) :- H =< 0, filter_positive(T, R). % Quicksort quicksort([], []). quicksort([H|T], Sorted) :- partition(H, T, Less, Greater), quicksort(Less, SortedLess), quicksort(Greater, SortedGreater), append(SortedLess, [H|SortedGreater], Sorted). partition(_, [], [], []). partition(Pivot, [H|T], [H|Less], Greater) :- H =< Pivot, partition(Pivot, T, Less, Greater). partition(Pivot, [H|T], Less, [H|Greater]) :- H > Pivot, partition(Pivot, T, Less, Greater). ``` ### Example 4: Belief Revision and Constraints ```prolog theme={null} % Initial beliefs with confidence belief(human(socrates), 1.0). belief(philosopher(socrates), 1.0). belief(lived_in(socrates, athens), 0.95). % Derived rules mortal(X) :- human(X). wise(X) :- philosopher(X). % Hard constraint: Cannot live in two places at once ~valid_kb :- lived_in(X, Place1) & lived_in(X, Place2) & Place1 \= Place2 & overlapping_time(Place1, Place2). % Soft constraint: Philosophers usually teach expected(teaches(X)) :- philosopher(X). % Query with explanation ?- mortal(socrates). % Result: true % Explanation: mortal(socrates) via human(socrates) ``` *** ## Error Messages NSR-L provides helpful error messages with source locations: ``` error: Unexpected ')' after expression --> 3:15 | 3 | mortal(X) :- human(X)). | ^^^^^^^^^ = help: Check for unbalanced parentheses ``` ### Common Errors | Error | Cause | Fix | | ------------------------ | ------------------------- | ------------------------------------------ | | `Singleton variable 'X'` | Variable used only once | Rename to `_X` or use it | | `Unexpected token` | Syntax error | Check operators and parentheses | | `Unbound variable` | Variable not instantiated | Ensure variable is bound before arithmetic | | `Division by zero` | Arithmetic error | Add guard: `Y \= 0` | | `Wrong arity` | Wrong number of arguments | Check predicate definition | *** ## API Endpoints | Endpoint | Method | Purpose | | ---------------------- | ------ | --------------------------------- | | `/api/v1/nsrl/parse` | POST | Parse NSR-L code (syntax check) | | `/api/v1/nsrl/assert` | POST | Add facts/rules to knowledge base | | `/api/v1/nsrl/execute` | POST | Execute queries | | `/api/v1/nsrl/prove` | POST | Prove entailment | | `/api/v1/nsrl/retract` | POST | Remove facts/rules | ### Example API Call ```bash theme={null} curl -X POST "$BASE_URL/api/v1/nsrl/execute" \ -H "X-API-Key: $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "human(socrates). mortal(X) :- human(X). ?- mortal(X).", "persist": false }' ``` *** ## Best Practices ### 1. Use Descriptive Predicate Names ```prolog theme={null} % Good customer_eligible_for_discount(C) :- ... % Avoid ced(C) :- ... ``` ### 2. Handle Edge Cases ```prolog theme={null} % Always handle empty list process([], []). process([H|T], Result) :- ... ``` ### 3. Use Anonymous Variables ```prolog theme={null} % When you don't need the value has_child(X) :- parent(X, _). ``` ### 4. Document with Comments ```prolog theme={null} % Calculate final price after applying all discounts % Precondition: base_price(Product, Price) exists % Returns: Final price after discounts final_price(Product, Final) :- ... ``` ### 5. Avoid Infinite Recursion ```prolog theme={null} % Bad: left recursion ancestor(X, Y) :- ancestor(X, Z), parent(Z, Y). % Good: base case first ancestor(X, Y) :- parent(X, Y). ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y). ``` *** ## Related Documentation * [YSE Beauty API Workflow](./yse_beauty_api_workflow.md) - Practical examples * [Temporal Agent Orchestration](./temporal_agent_orchestration.md) - Integration guide * [Recursive Policy Learning](./recursive_policy_learning.md) - Self-improving rules # StateSet Overview Source: https://docs.stateset.com/stateset-overview A comprehensive overview of the StateSet platform, its capabilities, and how it transforms business operations # StateSet: The Autonomous Operating System for Modern Business ## Executive Summary StateSet is revolutionizing how businesses operate by introducing an **AI-powered, agentic operating system** that automates and optimizes every aspect of business operations. Unlike traditional automation tools that simply execute predefined tasks, StateSet deploys **intelligent AI agents** that can think, learn, and act autonomously—transforming businesses from manual, linear operations to exponential, autonomous growth. **Key Insight**: StateSet doesn't just automate tasks—it empowers AI agents to make decisions, learn from experience, and continuously improve your business operations autonomously. ## What is StateSet? StateSet is a comprehensive platform that serves as the **autonomous nervous system** for modern businesses. It combines three core pillars: Autonomous entities that understand context, make decisions, and continuously improve A single system that orchestrates all business processes end-to-end Secure, scalable foundation built for mission-critical operations Think of StateSet as having a team of expert employees who work 24/7, never need breaks, and get smarter with every interaction—all while seamlessly integrating with your existing systems. ## The StateSet Ecosystem ### 1. StateSet ResponseCX **🎯 Intelligent Customer Experience Management** ResponseCX transforms every customer interaction with AI agents that provide: * **Omnichannel Support** across email, chat, voice, and social media * **Contextual Understanding** of customer history and preferences * **Proactive Resolution** before issues escalate * **Seamless Human Escalation** when needed ### 2. StateSet One **⚙️ The Autonomous Business Operating System** StateSet One serves as your business's command center: * End-to-end order management from placement to fulfillment - Automated order routing and allocation - Real-time order tracking and updates - Intelligent order modifications and cancellations * Predictive stocking and automated reordering - Real-time inventory visibility across all channels - Smart inventory allocation and optimization * Automated low-stock alerts and reorder triggers * Real-time reconciliation and fraud detection - Automated invoicing and payment processing - Intelligent financial reporting and analytics - Seamless integration with accounting systems * Complete visibility and optimization - Automated vendor management and purchasing - Real-time shipment tracking and coordination - Predictive demand forecasting ### 3. StateSet Cloud **☁️ Enterprise Infrastructure Platform** The robust foundation that powers everything: * **Global Scale** - Handle millions of operations per second * **99.99% Uptime** - Mission-critical reliability * **SOC 2 Certified** - Enterprise-grade security * **One-Click Deployment** - Instant infrastructure provisioning ## Core Capabilities ### 🤖 Autonomous AI Agents StateSet's agents go beyond simple automation: ```typescript theme={null} // Example: Creating a Customer Service Agent const agent = await client.agents.create({ name: "Support Specialist", role: "Senior Customer Success Manager", personality: { traits: ["empathetic", "solution-oriented", "professional"], tone: "friendly yet professional", }, capabilities: [ "order_management", "refund_processing", "subscription_management", "technical_support", ], knowledge_bases: ["product_docs", "support_playbook"], }); ``` ### 🔄 Event-Driven Architecture StateSet One emits events on every meaningful state transition (orders, inventory, returns, payouts). You can react using webhooks or GraphQL subscriptions and drive agents or workflows from those signals. ```typescript theme={null} // Pseudo-code: subscribe to business events and react autonomously client.events.subscribe({ events: ["order.*", "inventory.low_stock"], handler: async (event) => { await handleBusinessEvent(event); }, }); ``` > **See Also**: [Event‑Driven APIs](/api-reference/events) and [Webhooks Security](/guides/webhook-security) ### ⚡ Workflow Orchestration Long‑running operations (syncing channels, multi‑step fulfillment, refunds) run as durable workflows. StateSet Cloud provides built‑in orchestration, and you can also trigger your own workflows via events. ```typescript theme={null} // Pseudo-code: model an order‑fulfillment workflow const workflow = await client.workflows.create({ name: "Order Fulfillment", trigger: { event: "order.created" }, steps: [ { action: "inventory.check" }, { action: "payment.process" }, { action: "shipping.create_label" }, { action: "customer.notify" }, ], }); ``` ## Key Differentiators ### 1. Beyond Traditional Automation **Traditional Automation** * Scripts that follow rigid rules * Limited to predefined tasks * Requires manual updates for changes **StateSet AI Agents** * AI agents that understand context and adapt * Handles complex, multi-step decisions * Learns and improves autonomously ### 2. Unified Intelligence **Traditional Tools** * Fragmented tools and data silos * Disconnected workflows * Manual integration overhead **StateSet Platform** * Single platform with complete business understanding * Unified data model and operations * Seamless integrations out of the box ### 3. Exponential Scalability **Traditional Growth** * Linear growth requiring proportional resources * Manual processes limit capacity * High overhead costs **StateSet Scale** * 10x growth without 10x headcount * Autonomous processes scale effortlessly * Marginal cost of each additional operation ## Real-World Impact ### Measurable Results | Metric | Improvement | | ---------------- | ---------------------------------- | | **Speed** | 10x faster than manual processes | | **Cost** | 80% reduction in operational costs | | **Availability** | 24/7 autonomous operation | | **Capacity** | Infinite scalability potential | ### Use Cases by Industry **🛒 E-commerce** * Automated order management and fulfillment * AI-powered customer support at scale * Predictive inventory management * Dynamic pricing optimization * Streamlined returns processing **🏭 Manufacturing** * End-to-end supply chain visibility * Quality assurance automation * Predictive maintenance scheduling * Order-to-cash optimization * Production planning automation **💻 SaaS** * Intelligent user onboarding flows * Proactive churn prevention * Usage-based billing automation * Support ticket deflection * Feature adoption optimization **🏪 Marketplaces** * Multi-vendor orchestration * Automated dispute resolution * Commission and payout management * Quality control at scale * Trust and safety automation ## Technical Architecture StateSet is a **composable set of services** that work together as one operating system: ```mermaid theme={null} graph LR RCX[ResponseCX Agents] -->|tool calls| API[StateSet One API] RCX -->|explainable reasoning| NSR[NSR Engine] API --> Sync[Sync Server] Sync --> Ext[External Platforms] API --> Core[StateSet Core] ``` | Service | Purpose | Technology | | -------------------- | --------------------- | ---------------------------- | | **StateSet One API** | Commerce & Operations | Rust/Axum, REST + GraphQL | | **Sync Server** | Integration Layer | Rust, Pipeline Processing | | **ResponseCX** | Agents Runtime | Cloud-native, Tool-calling | | **Agents Framework** | Training Platform | Open-source RL Stack | | **NSR Engine** | Reasoning Engine | Rust, Neuro-symbolic | | **StateSet Core** | Blockchain Layer | Cosmos SDK, Commerce Modules | ### Developer‑First Design * **Clean APIs** - REST + GraphQL with OpenAPI specs * **Official SDKs** - Node.js, Python, Ruby, PHP, and Go * **Production CLI** - `stateset-cli` for local dev and ops * **Active Community** - Growing integration ecosystem ## Getting Started ### Quick Start Process Create your account in 30 seconds at [stateset.com/sign-up](https://stateset.com/sign-up) One-click integrations with Shopify, NetSuite, Amazon, and 100+ more tools Use pre-built templates or create custom AI agents for your use case Watch your operations transform in real-time with detailed analytics ### Implementation Example ```javascript theme={null} import { StateSetClient } from "stateset-node"; // Initialize client const client = new StateSetClient({ apiKey: process.env.STATESET_API_KEY, }); // Create and deploy your first agent const agent = await client.agents.create({ name: "Customer Success AI", role: "Support Specialist", goals: [ "Resolve customer issues quickly", "Identify upsell opportunities", "Collect product feedback", ], }); await agent.deploy(); // Your AI agent is now live! 🚀 ``` ## Pricing Model ### Flexible Plans for Every Stage **\$99/month** - Up to 1,000 operations/month - 3 AI agents - Core integrations - Community support [Get Started →](https://stateset.com/sign-up) **\$499/month** - Up to 10,000 operations/month - Unlimited AI agents - All integrations - Priority support [Get Started →](https://stateset.com/sign-up) **Custom Pricing** - Unlimited operations - Dedicated infrastructure - Custom AI models - 24/7 support with SLA [Contact Sales →](https://calendly.com/stateset/demo) ## Security & Compliance ### Enterprise-Grade Security Built In | Feature | Status | | ----------------------------- | --------------- | | **SOC 2 Type II** | ✅ Certified | | **GDPR** | ✅ Compliant | | **End-to-End Encryption** | ✅ Enabled | | **Role-Based Access Control** | ✅ Implemented | | **Audit Logging** | ✅ Comprehensive | | **99.99% Uptime SLA** | ✅ Guaranteed | ## Success Stories Companies using StateSet report: * **60% reduction** in response times * **80% decrease** in operational costs * **10x improvement** in processing capacity * **95% customer satisfaction** scores ## The StateSet Advantage ### For Developers 👨‍💻 * Modern tech stack with cutting-edge AI * Comprehensive documentation and examples * Active community support * Rapid deployment capabilities ### For Business Leaders 👔 * Immediate ROI with proven results * Scalability without complexity * Reduced operational overhead * Competitive advantage through AI ### For Operations Teams 📊 * Automated workflows across systems * Real-time visibility and control * Proactive issue resolution * Seamless system integration ## Future Vision StateSet is building towards a future where: * Every business operates with **AI-native efficiency** * Human creativity is **unleashed from repetitive tasks** * Companies can **scale infinitely without proportional costs** * Business operations are **as intelligent as the products they deliver** ## Next Steps Ready to transform your business operations? No credit card required - [stateset.com/sign-up](https://stateset.com/sign-up) See StateSet in action - [Schedule with our team](https://calendly.com/stateset/demo) Deep dive into capabilities - [Explore the docs](/development) Connect with 5,000+ builders - [Join Discord](https://discord.gg/stateset) *** ## Conclusion StateSet represents a **paradigm shift** in how businesses operate. By combining autonomous AI agents, unified operations management, and enterprise-grade infrastructure, StateSet enables companies to achieve **exponential growth without exponential complexity**. Whether you're a fast-growing startup or an established enterprise, StateSet provides the tools and intelligence to transform your operations from: * **Reactive → Proactive** * **Manual → Autonomous** * **Linear → Exponential** **The future of business is autonomous. The future is StateSet.** 🚀 # Response ChatGPT App Guide Source: https://docs.stateset.com/stateset-response/stateset-response-chatgpt-guide Step-by-step setup for ChatGPT Developer Mode. # Response ChatGPT App Guide This guide walks through building the widget, running the MCP server, and connecting it to ChatGPT. ## 1) Build the widget assets ```bash theme={null} git clone https://github.com/stateset/stateset-response-chatgpt-app.git cd stateset-response-chatgpt-app pnpm install pnpm run build ``` The build emits `stateset-response.html/js/css` inside `assets/`. ## 2) Run the MCP server ```bash theme={null} cd server pnpm install STATESET_API_BASE_URL=https://api.stateset.com \ STATESET_API_KEY=sk-... \ pnpm start ``` Without credentials, the server uses sample data for local testing. ## 3) Expose the MCP server Use a tunnel to expose the SSE endpoint: ```bash theme={null} ngrok http 3030 ``` The endpoint becomes `/mcp`. ## 4) Add the connector in ChatGPT 1. Open ChatGPT → **Settings → Developer Mode → Connectors**. 2. Click **Add connector**, choose **MCP via SSE**. 3. Name it `Stateset Response`. 4. Paste `/mcp` as the endpoint. 5. Save and confirm the connector is online. ## 5) Test the app ```text theme={null} @Stateset Response open the customer support workspace for org 1234. ``` ## Troubleshooting * Re-run `pnpm run build` if assets are missing. * Verify the tunnel is reachable and SSE is stable. * Confirm API credentials when using live data. ## Related Documentation * [App README](/stateset-response-chatgpt-app/README) # Response ChatGPT App Overview Source: https://docs.stateset.com/stateset-response/stateset-response-chatgpt-overview Widget + MCP server for ResponseCX inside ChatGPT. # Response ChatGPT App Overview The Response ChatGPT App pairs a React widget with a Node MCP server to render the StateSet Response workspace inside ChatGPT. ## What’s Included * **React widget** for ChatGPT Apps * **MCP server** that exposes the `stateset-response-chat` tool * **Integration guide** for ChatGPT Developer Mode ## How It Works 1. Build the widget assets. 2. Start the MCP server. 3. Expose the SSE endpoint to ChatGPT. 4. Add the connector and run a test conversation. ## Related Documentation * [ChatGPT Integration Guide](/stateset-response-chatgpt-guide) * [App README](/stateset-response-chatgpt-app/README) # Set up ResponseCX Source: https://docs.stateset.com/stateset-response/stateset-responsecx Configure ResponseCX to automate customer operations. # Set up ResponseCX Use ResponseCX to automate customer operations with AI agents and deterministic workflows. ## Prerequisites * StateSet account with API access * ResponseCX enabled for your workspace * Access to commerce/CX integrations ## Connect ResponseCX and run your first flow 1. Connect your commerce and CX integrations. 2. Configure agent settings and policies. 3. Run a test workflow (returns or order status). 4. Review results and traceability in the console. Start with read-only workflows before enabling write actions. ## Verify the result Confirm that the agent can retrieve customer context and return a response in a test conversation. ## Troubleshooting * **No context returned**: Verify integration credentials and permissions. * **Agent errors**: Check rate limits and policy configuration. ## Related tasks * [Response Quickstart](/guides/response-quickstart) * [Agents Quickstart](/guides/agents-quickstart) * [Agents API](/response-api-reference/agents/list) # ResponseCX Architecture Source: https://docs.stateset.com/stateset-response/stateset-responsecx-architecture Core components and data flow for StateSet ResponseCX. # ResponseCX Architecture ResponseCX combines AI agents with deterministic workflows to deliver reliable, auditable customer operations. ## Core Components * **Agent Orchestrator**: Routes tasks to specialized agents * **Workflow Engine**: Deterministic execution for critical steps * **Data Layer**: Unified commerce data for context and actions * **Trace & Audit**: End-to-end visibility for every action ## Data Flow 1. A customer request enters via chat, email, or voice. 2. The orchestrator selects an agent and pulls context. 3. The workflow engine executes required actions (returns, refunds, order updates). 4. Responses are generated with traceable reasoning. ## Integration Points * Commerce platforms for orders and fulfillment * CX tools for ticket ingestion * Identity systems for customer verification ## Related Documentation * [ResponseCX Overview](/stateset-responsecx) * [Response Quickstart](/guides/response-quickstart) # ResponseCX Workflows Source: https://docs.stateset.com/stateset-response/stateset-responsecx-workflows Common workflows for support, returns, and order actions. # ResponseCX Workflows ResponseCX is optimized for high-volume, outcome-driven customer operations. Below are common workflows teams automate first. ## Returns and Refunds 1. Validate eligibility and policy rules 2. Create return authorization 3. Trigger refund or exchange actions 4. Notify the customer with tracking ## Order Changes 1. Verify order state and payment status 2. Apply updates (address, quantity, substitutions) 3. Recalculate totals and validate constraints 4. Confirm changes with the customer ## WISMO (Where Is My Order) 1. Pull latest fulfillment and carrier status 2. Detect exceptions or delays 3. Provide proactive resolution options ## Escalations 1. Detect low-confidence outcomes or policy exceptions 2. Route to human review with full context 3. Resume automation after approval ## Related Documentation * [ResponseCX Overview](/stateset-responsecx) * [ResponseCX Architecture](/stateset-responsecx-architecture) # StateSet ResponseCX CLI Source: https://docs.stateset.com/stateset-responsecx-cli AI-powered CLI for managing the StateSet ResponseCX platform. # StateSet ResponseCX CLI AI-powered CLI for managing the [StateSet ResponseCX](https://response.cx) platform. Chat with an AI agent that can manage your agents, rules, skills, knowledge base, channels, messages, and more — all from the terminal. Includes optional WhatsApp and Slack gateways for connecting your agent to messaging platforms. ## Install ```bash theme={null} npm install -g stateset-response-cli ``` Or clone and build locally: ```bash theme={null} git clone https://github.com/stateset/stateset-response-cli.git cd stateset-response-cli npm install npm run build ``` ## Quick Start ```bash theme={null} # Authenticate with your StateSet organization response auth login # Start an interactive chat session response chat ``` ## Authentication The CLI supports two authentication methods: **Browser / Device Code (recommended)** ```bash theme={null} response auth login ``` Follow the prompts to authenticate via your browser. The CLI will receive a scoped token automatically. **Manual Setup** During `response auth login`, you can provide your GraphQL endpoint and admin secret directly. Credentials are stored in `~/.stateset/config.json` with restricted file permissions (600). ### Multiple Organizations ```bash theme={null} # Switch between configured organizations response auth switch # View current auth status response auth status ``` ## Usage ### Interactive Chat ```bash theme={null} response chat response chat --model haiku response chat --model opus ``` The agent understands natural language. Ask it to list your agents, create rules, search the knowledge base, etc. **Session commands:** | Command | Description | | ---------- | ---------------------------------- | | `/help` | Show available commands | | `/clear` | Reset conversation history | | `/history` | Show conversation turn count | | `/model` | Switch model (sonnet, haiku, opus) | | `exit` | End the session | Multi-line input is supported — end a line with `\` to continue on the next line. Press `Ctrl+C` to cancel the current request. ### WhatsApp Gateway Bridge incoming WhatsApp messages to your StateSet Response agent. ```bash theme={null} response-whatsapp ``` On first run, scan the QR code with WhatsApp (Settings > Linked Devices > Link a Device). Auth state is persisted in `~/.stateset/whatsapp-auth/`. **Options:** ``` --model Model to use (sonnet, haiku, opus) --allow Comma-separated allowlist of phone numbers --groups Allow messages from group chats --auth-dir WhatsApp auth credential directory --reset Clear stored auth and re-scan QR --verbose, -v Enable debug logging ``` **Examples:** ```bash theme={null} response-whatsapp --model haiku response-whatsapp --allow 14155551234,14155559999 response-whatsapp --reset ``` ### Slack Gateway Bridge Slack messages to your StateSet Response agent via Socket Mode. ```bash theme={null} response-slack ``` **Setup:** 1. Create a Slack app at [https://api.slack.com/apps](https://api.slack.com/apps) 2. Enable Socket Mode (Settings > Socket Mode) 3. Generate an app-level token (`xapp-...`) with `connections:write` scope 4. Add Bot Token Scopes: `chat:write`, `app_mentions:read`, `im:history`, `channels:history` 5. Install the app to your workspace 6. Set environment variables: ```bash theme={null} export SLACK_BOT_TOKEN=xoxb-... export SLACK_APP_TOKEN=xapp-... ``` **Behavior:** * In DMs: responds to all messages * In channels: responds when @mentioned or in threads the bot has participated in **Options:** ``` --model Model to use (sonnet, haiku, opus) --allow Comma-separated allowlist of Slack user IDs --verbose, -v Enable debug logging ``` ## Environment Variables | Variable | Required | Description | | --------------------------- | -------- | -------------------------------------------- | | `ANTHROPIC_API_KEY` | Yes | Anthropic API key for Claude | | `STATESET_INSTANCE_URL` | No | StateSet ResponseCX instance URL | | `STATESET_GRAPHQL_ENDPOINT` | No | GraphQL API endpoint | | `STATESET_KB_HOST` | No | Knowledge base (Qdrant) host URL | | `SLACK_BOT_TOKEN` | Slack | Bot User OAuth Token (`xoxb-...`) | | `SLACK_APP_TOKEN` | Slack | App-level token for Socket Mode (`xapp-...`) | | `OPENAI_API_KEY` | KB | OpenAI API key for knowledge base embeddings | ## Available Tools The AI agent has access to 80+ tools organized by resource type: ### Agents `list_agents` `get_agent` `create_agent` `update_agent` `delete_agent` `bootstrap_agent` `export_agent` ### Rules `list_rules` `get_agent_rules` `create_rule` `update_rule` `delete_rule` `import_rules` `bulk_update_rule_status` `bulk_assign_rules_to_agent` `bulk_delete_rules` ### Skills `list_skills` `get_agent_skills` `create_skill` `update_skill` `delete_skill` `import_skills` `bulk_update_skill_status` `bulk_delete_skills` ### Attributes `list_attributes` `create_attribute` `update_attribute` `delete_attribute` `import_attributes` ### Examples `list_examples` `create_example` `update_example` `delete_example` `import_examples` ### Evaluations `list_evals` `create_eval` `update_eval` `delete_eval` `export_evals_for_finetuning` ### Datasets `list_datasets` `get_dataset` `create_dataset` `update_dataset` `delete_dataset` `add_dataset_entry` `delete_dataset_entry` ### Functions `list_functions` `create_function` `update_function` `delete_function` `import_functions` ### Responses `list_responses` `get_response` `get_response_count` `bulk_update_response_ratings` `search_responses` ### Knowledge Base `kb_search` `kb_upsert` `kb_update` `kb_delete` `kb_get_collection_info` `kb_scroll` ### Channels `list_channels` `get_channel` `get_channel_with_messages` `create_channel` `update_channel` `delete_channel` `get_channel_count` ### Messages `list_messages` `get_message` `create_message` `update_message` `delete_message` `search_messages` `get_message_count` ### Settings `list_agent_settings` `get_agent_settings` `update_agent_settings` `get_channel_settings` ### Organizations `get_organization` `get_organization_overview` `update_organization` ## Architecture The CLI uses the [Model Context Protocol (MCP)](https://modelcontextprotocol.io) to expose platform tools to Claude. On startup, the CLI spawns an MCP server as a child process over stdio. Claude calls tools through this server, which executes GraphQL queries against the StateSet backend. ``` User <--> CLI (Anthropic SDK) <--> MCP Server <--> StateSet GraphQL API <--> Qdrant Vector DB ``` The WhatsApp and Slack gateways create per-user agent sessions with the same architecture. Sessions have a 30-minute TTL and are automatically cleaned up. ## Development ```bash theme={null} # Run in development mode (no build step) npm run dev # Build TypeScript npm run build # Run production build npm start ``` ## License [MIT](LICENSE) # StateSet Agents Source: https://docs.stateset.com/stateset-rl-agents Reinforcement‑learning framework for multi‑turn conversational AI agents. # StateSet Agents StateSet Agents is a production‑oriented RL stack for training and serving LLM‑backed agents that improve through **multi‑turn interaction**. The library provides: * Async‑first **agent APIs** (`MultiTurnAgent`, `ToolAgent`) with Hugging Face and stub backends. * **Environments** for conversational and task‑oriented episodes. * **Trajectories** and value/advantage utilities tailored to dialogue. * Composable **reward functions** (heuristic, domain, multi‑objective, neural). * A family of **group‑based policy‑optimization trainers** (GRPO, GSPO, GEPO, DAPO, VAPO) plus PPO and RLAIF. * **Offline RL algorithms** for learning from logged conversations (BCQ, BEAR, CQL, IQL, Decision Transformer). * **Sim‑to‑Real transfer** for training in simulation and deploying to real users (domain randomization, system identification, progressive transfer). * **Continual learning + long‑term planning** utilities (replay/LwF/EWC, plan context injection). * Optional **performance layers** (vLLM generation, Rust acceleration, distributed training, HPO, FastAPI service). If you want a framework that treats conversations as first‑class RL episodes (rather than single turns), this is it. *** ## Why group‑based optimization? Traditional RLHF/PPO trains on one sampled response at a time. In long conversations this leads to high‑variance updates and brittle behavior.\ StateSet Agents implements **group‑relative methods**: * **GRPO (Group Relative Policy Optimization)**: sample a group of trajectories per prompt, compute advantages relative to the group baseline, then apply clipped policy‑gradient updates. * **GSPO (Group Sequence Policy Optimization)**: a more stable sequence‑level variant (Alibaba Qwen team) that avoids token‑level collapse on long outputs and MoE models. The result is steadier learning for dialogue tasks. *** ## Core concepts * **Agent**: wraps a causal LM and exposes `initialize()` and `generate_response()`. * `MultiTurnAgent` handles conversation history and state. * `ToolAgent` adds function/tool calling. * **Environment**: defines episode reset/step logic and optional reward hooks. * `ConversationEnvironment` ships with scenario‑driven multi‑turn conversations. * `TaskEnvironment` is for goal‑oriented tasks. * **Trajectory**: a multi‑turn record of turns, rewards, and metadata (`MultiTurnTrajectory`). * **Rewards**: `RewardFunction` subclasses and factories; combined via `CompositeReward` or multi‑objective reward models. * **Training**: trainers in `stateset_agents.training` implement GRPO‑family updates, GAE/value heads, KL regularization, LoRA support, and optional distributed/vLLM execution. *** ## Installation ### Core (lightweight, stub‑ready) ```bash theme={null} pip install stateset-agents ``` ### Training / real models ```bash theme={null} pip install "stateset-agents[training]" ``` ### Optional extras ```bash theme={null} pip install "stateset-agents[trl]" # TRL GRPO integration + bitsandbytes pip install "stateset-agents[vllm]" # vLLM generation backend pip install "stateset-agents[hpo]" # Optuna/Ray Tune HPO pip install "stateset-agents[api]" # FastAPI service pip install "stateset-agents[distributed]"# DeepSpeed / multi‑GPU helpers pip install "stateset-agents[full]" # Most extras in one go ``` *** ## Quick start ### 1) Stub hello world (no downloads) Runs without Torch/transformers and is ideal for CI or prototyping. ```python theme={null} import asyncio from stateset_agents import MultiTurnAgent from stateset_agents.core.agent import AgentConfig async def main(): agent = MultiTurnAgent(AgentConfig(model_name="stub://demo")) await agent.initialize() reply = await agent.generate_response([{"role": "user", "content": "Hi!"}]) print(reply) asyncio.run(main()) ``` ### 2) Chat with a real model ```python theme={null} import asyncio from stateset_agents import MultiTurnAgent from stateset_agents.core.agent import AgentConfig async def main(): agent = MultiTurnAgent( AgentConfig(model_name="gpt2", max_new_tokens=128, temperature=0.7) ) await agent.initialize() messages = [{"role": "user", "content": "What is GRPO?"}] print(await agent.generate_response(messages)) asyncio.run(main()) ``` *** ## Train a multi‑turn agent with GRPO The high‑level `train(...)` helper chooses single‑turn vs multi‑turn GRPO automatically. ```python theme={null} import asyncio from stateset_agents import ( MultiTurnAgent, ConversationEnvironment, CompositeReward, HelpfulnessReward, SafetyReward, train, ) from stateset_agents.core.agent import AgentConfig async def main(): # 1) Agent agent = MultiTurnAgent(AgentConfig(model_name="gpt2")) await agent.initialize() # 2) Environment scenarios = [ { "id": "refund", "topic": "refunds", "context": "User wants a refund for a delayed order.", "user_responses": [ "My order is late.", "I'd like a refund.", "Thanks for your help.", ], } ] env = ConversationEnvironment(scenarios=scenarios, max_turns=6) # 3) Reward reward_fn = CompositeReward( [HelpfulnessReward(weight=0.7), SafetyReward(weight=0.3)] ) # 4) Train trained_agent = await train( agent=agent, environment=env, reward_fn=reward_fn, num_episodes=50, profile="balanced", save_path="./outputs/refund_agent", ) # 5) Try the trained model resp = await trained_agent.generate_response( [{"role": "user", "content": "My order was delayed, what can you do?"}] ) print(resp) asyncio.run(main()) ``` More end‑to‑end scripts live in `examples/complete_grpo_training.py` and `examples/production_ready_customer_service.py`. *** ## Continual learning + long‑term planning (optional) Enable planning context and replay/LwF in the trainer with config overrides: ```python theme={null} agent = MultiTurnAgent( AgentConfig( model_name="gpt2", enable_planning=True, planning_config={"max_steps": 4}, ) ) trained_agent = await train( agent=agent, environment=env, reward_fn=reward_fn, num_episodes=50, # resume_from_checkpoint="./outputs/checkpoint-100", config_overrides={ "continual_strategy": "replay_lwf", "continual_kl_beta": 0.1, "replay_buffer_size": 500, "replay_ratio": 0.3, "replay_sampling": "balanced", "task_id_key": "task_id", "task_schedule": ["task_a", "task_b"], "task_switch_steps": 25, }, ) context = {"conversation_id": "demo-trip", "goal": "Plan a 4-day trip to Kyoto"} resp = await trained_agent.generate_response( [{"role": "user", "content": "Can you draft a plan?"}], context=context, ) followup = await trained_agent.generate_response( [{"role": "user", "content": "Great. What should we do next?"}], context={"conversation_id": "demo-trip", "plan_update": {"action": "advance"}}, ) # To update the plan goal explicitly: # context={"conversation_id": "demo-trip", "plan_goal": "Plan a 4-day trip to Osaka"} ``` *** ## Other training algorithms All algorithms are available under `stateset_agents.training` when training deps are installed: * **GSPO**: stable sequence‑level GRPO variant (`GSPOTrainer`, `GSPOConfig`, `train_with_gspo`) * **GEPO**: expectation‑based group optimization for heterogeneous/distributed setups * **DAPO**: decoupled clip + dynamic sampling for reasoning‑heavy tasks * **VAPO**: value‑augmented group optimization (strong for math/reasoning) * **PPO baseline**: standard PPO trainer for comparison * **RLAIF**: RL from AI feedback via judge/reward models Minimal GSPO sketch: ```python theme={null} from stateset_agents.training import get_config_for_task, GSPOConfig, train_with_gspo from stateset_agents.rewards.multi_objective_reward import create_customer_service_reward base_cfg = get_config_for_task("customer_service", model_name="gpt2") gspo_cfg = GSPOConfig.from_training_config(base_cfg, num_outer_iterations=5) trained_agent = await train_with_gspo( config=gspo_cfg, agent=agent, environment=env, reward_model=create_customer_service_reward(), ) ``` See `docs/GSPO_GUIDE.md`, `docs/ADVANCED_RL_ALGORITHMS.md`, and `examples/train_with_gspo.py` for full configs. *** ## Offline RL: Learn from logged conversations Train agents from historical conversation logs without online interaction. Useful when: * You have existing customer service transcripts * Online training is expensive or risky * You want to bootstrap before online fine‑tuning ### Available Algorithms | Algorithm | Best For | Key Innovation | | ------------------------ | --------------------- | ------------------------------- | | **BCQ** | Conservative learning | VAE‑constrained action space | | **BEAR** | Distribution matching | MMD kernel regularization | | **CQL** | Pessimistic Q‑values | Conservative Q‑function penalty | | **IQL** | Expectile regression | Implicit value learning | | **Decision Transformer** | Sequence modeling | Return‑conditioned generation | ### Quick Start ```python theme={null} from stateset_agents.data import ConversationDataset, ConversationDatasetConfig from stateset_agents.training import BCQTrainer, BCQConfig # Load historical conversations config = ConversationDatasetConfig(quality_threshold=0.7) dataset = ConversationDataset.from_jsonl("conversations.jsonl", config) # Train with BCQ bcq_config = BCQConfig( hidden_dim=256, latent_dim=64, num_epochs=100, ) trainer = BCQTrainer(bcq_config) await trainer.train(dataset) ``` ### Hybrid Offline + Online Training Combine offline pretraining with online GRPO fine‑tuning: ```python theme={null} from stateset_agents.training import OfflineGRPOTrainer, OfflineGRPOConfig config = OfflineGRPOConfig( offline_algorithm="cql", offline_pretrain_steps=1000, online_ratio=0.3, # 30% online, 70% offline ) trainer = OfflineGRPOTrainer(config) trained = await trainer.train(agent, env, reward_fn, offline_dataset=dataset) ``` See `docs/OFFLINE_RL_SIM_TO_REAL_GUIDE.md` for complete documentation. *** ## Sim‑to‑Real Transfer Train in simulation, deploy to real users. The framework provides: ### Domain Randomization Generate diverse training scenarios with randomized user personas: ```python theme={null} from stateset_agents.training import DomainRandomizer, DomainRandomizationConfig config = DomainRandomizationConfig( persona_variation=0.3, topic_variation=0.2, style_variation=0.2, ) randomizer = DomainRandomizer(config) # Randomize during training persona = randomizer.sample_persona() scenario = randomizer.sample_scenario(topic="returns") ``` ### Conversation Simulator Calibratable simulator with adjustable realism: ```python theme={null} from stateset_agents.environments import ConversationSimulator, ConversationSimulatorConfig simulator = ConversationSimulator(ConversationSimulatorConfig( base_model="gpt2", realism_level=0.8, )) # Calibrate to real data await simulator.calibrate(real_conversations) # Measure sim‑to‑real gap gap = simulator.compute_sim_real_gap(real_data, sim_data) ``` ### Progressive Transfer Gradually transition from simulation to real interactions: ```python theme={null} from stateset_agents.training import SimToRealTransfer, SimToRealConfig transfer = SimToRealTransfer(SimToRealConfig( transfer_schedule="cosine", # linear, exponential, step warmup_steps=100, total_steps=1000, )) # Get current sim/real mixing ratio sim_ratio = transfer.get_sim_ratio(current_step) ``` See `docs/OFFLINE_RL_SIM_TO_REAL_GUIDE.md` for complete documentation. *** ## Hyperparameter optimization (HPO) Install with `stateset-agents[hpo]`, then: ```python theme={null} from stateset_agents.training import TrainingConfig, TrainingProfile from stateset_agents.training.hpo import quick_hpo base_cfg = TrainingConfig.from_profile( TrainingProfile.BALANCED, num_episodes=100 ) summary = await quick_hpo( agent=agent, environment=env, reward_function=reward_fn, base_config=base_cfg, n_trials=30, ) print(summary.best_params) ``` See `docs/HPO_GUIDE.md` and `examples/hpo_training_example.py`. *** ## Custom rewards Use the decorator for quick experiments: ```python theme={null} from stateset_agents.core.reward import reward_function @reward_function(weight=0.5) async def politeness_reward(turns, context=None) -> float: return 1.0 if any("please" in t.content.lower() for t in turns) else 0.0 ``` Combine with built‑ins via `CompositeReward`. *** ## Custom environments Subclass `Environment` for task‑specific dynamics: ```python theme={null} from stateset_agents.core.environment import Environment, EnvironmentState from stateset_agents.core.trajectory import ConversationTurn class MyEnv(Environment): async def reset(self, scenario=None) -> EnvironmentState: ... async def step( self, state: EnvironmentState, action: ConversationTurn ): ... ``` *** ## Checkpoints * `train(..., save_path="...")` saves an agent checkpoint. * Load later: ```python theme={null} from stateset_agents.core.agent import load_agent_from_checkpoint agent = await load_agent_from_checkpoint("./outputs/refund_agent") ``` *** ## CLI The CLI is a thin wrapper around the Python API: ```bash theme={null} stateset-agents version stateset-agents doctor stateset-agents train --stub stateset-agents train --config ./config.yaml --dry-run false --save ./outputs/ckpt stateset-agents evaluate --checkpoint ./outputs/ckpt --message "Hello" stateset-agents serve --host 0.0.0.0 --port 8001 ``` For complex runs prefer the Python API and the examples folder. *** ## Examples and docs Good starting points: * `examples/hello_world.py` – stub mode walkthrough * `examples/quick_start.py` – basic agent + environment * `examples/complete_grpo_training.py` – end‑to‑end GRPO training * `examples/train_with_gspo.py` – GSPO + GSPO‑token training * `examples/train_with_trl_grpo.py` – Hugging Face TRL GRPO integration Key docs: * `docs/USAGE_GUIDE.md` * `docs/RL_FRAMEWORK_GUIDE.md` * `docs/GSPO_GUIDE.md` * `docs/OFFLINE_RL_SIM_TO_REAL_GUIDE.md` * `docs/HPO_GUIDE.md` * `docs/CLI_REFERENCE.md` * `docs/ARCHITECTURE.md` *** ## Related Projects * [stateset-nsr](https://github.com/stateset/stateset-nsr) - Neuro‑symbolic reasoning engine for explainable tools. * [stateset-api](https://github.com/stateset/stateset-api) - Commerce/operations API that agents can drive. * [stateset-sync-server](https://github.com/stateset/stateset-sync-server) - Multi‑tenant orchestration and integrations. * [core](https://github.com/stateset/core) - Cosmos SDK blockchain for on‑chain commerce. * Public API docs: [https://docs.stateset.com](https://docs.stateset.com) *** ## Contributing See `CONTRIBUTING.md`. Please run `pytest -q` and format with `black`/`isort` before opening a PR. *** ## License Business Source License 1.1. Non‑production use permitted until **2029‑09‑03**, then transitions to Apache 2.0. See `LICENSE`. # null Source: https://docs.stateset.com/stateset-sandbox-skill Self-hosted Kubernetes sandbox for running AI agents with full code execution in isolated containers # StateSet Sandbox Self-hosted Kubernetes sandbox infrastructure for running AI agents and code execution workloads in isolated containers. REST and WebSocket APIs for creating sandboxes, streaming command output, and managing files. ## Skill Files | File | URL | | ------------------------ | ---------------------------------------------------- | | **SKILL.md** (this file) | `https://doc.stateset.com/stateset-sandbox-skill.md` | **Check for updates:** Re-fetch these files anytime to see new features! *** ## API Base URL | Service | Base URL | Purpose | | --------------- | ----------------------------------------- | ------------------------------------ | | **Sandbox API** | `https://api.sandbox.stateset.app/api/v1` | Sandbox management, execution, files | | **WebSocket** | `wss://api.sandbox.stateset.app/ws` | Real-time streaming | **Environment Variables:** ```bash theme={null} export STATESET_SANDBOX_API_KEY=sk_sandbox_xxx export STATESET_SANDBOX_URL=https://api.sandbox.stateset.app ``` *** ## Architecture Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Your App / Agent │ └─────────────────────┬───────────────────────────────────────┘ │ HTTP / WebSocket ▼ ┌─────────────────────────────────────────────────────────────┐ │ Sandbox Controller │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ REST API │ │ WebSocket │ │ Warm Pod Pool │ │ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ └─────────────────────┬───────────────────────────────────────┘ │ Kubernetes API ▼ ┌─────────────────────────────────────────────────────────────┐ │ Sandbox Pods │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ /workspace/ - Your code and files │ │ │ │ Node.js, Python, Go, Rust, Git, Docker CLI │ │ │ │ Isolated network, resource limits, timeouts │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` **Key Capabilities:** * Isolated execution per sandbox pod with resource limits * REST and WebSocket APIs for command execution and streaming * File read/write APIs for workspace workflows * Prebuilt runtime with Node.js, Python, Go, Rust, and CLI tools * Automatic cleanup with per-sandbox timeouts * Warm pool support for sub-100ms startup *** ## Agent Registration AI agents must register to receive an API key for authentication. ### Register a New Agent ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/register \ -H "Content-Type: application/json" \ -d '{ "first_name": "Commerce", "last_name": "Agent", "organization_name": "My AI Company", "email": "agent@example.com" }' ``` **Response:** ```json theme={null} { "success": true, "user": { "id": "user_xxx", "email": "agent@example.com" }, "organization": { "id": "org_xxx", "name": "My AI Company" }, "api_key": "sk_sandbox_xxx_xxxxxxxxxxxxxxxxxxxxxxxx", "message": "Registration successful. Store your API key securely." } ``` **Important:** Store the `api_key` securely. It is only returned once. ### Authentication All API requests require authentication: ```bash theme={null} curl https://api.sandbox.stateset.app/api/v1/sandboxes \ -H "Authorization: ApiKey YOUR_API_KEY" ``` Or with Bearer token (JWT): ```bash theme={null} curl https://api.sandbox.stateset.app/api/v1/sandboxes \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` *** ## Quick Start ### 1. Create a Sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/create \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "cpus": "2", "memory": "2Gi", "timeout_seconds": 300 }' ``` **Response:** ```json theme={null} { "sandbox_id": "sandbox-a1b2c3d4", "org_id": "org_xxx", "status": "running", "pod_ip": "10.0.1.42", "created_at": "2026-01-30T10:00:00Z", "expires_at": "2026-01-30T10:05:00Z", "startup_metrics": { "total_ms": 87, "pod_creation_ms": 12, "pod_ready_ms": 75 } } ``` ### 2. Write Files ```bash theme={null} # Base64 encode your content CONTENT=$(echo 'console.log("Hello from sandbox!");' | base64) curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/files \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"files\": [{ \"path\": \"/workspace/hello.js\", \"content\": \"$CONTENT\" }] }" ``` ### 3. Execute Commands ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/execute \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command": "node /workspace/hello.js"}' ``` **Response:** ```json theme={null} { "exit_code": 0, "stdout": "Hello from sandbox!\n", "stderr": "" } ``` ### 4. Read Files ```bash theme={null} curl "https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/files?path=/workspace/output.txt" \ -H "Authorization: ApiKey YOUR_API_KEY" ``` **Response:** ```json theme={null} { "path": "/workspace/output.txt", "content": "SGVsbG8gV29ybGQh", "size": 12 } ``` ### 5. Stop Sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/stop \ -H "Authorization: ApiKey YOUR_API_KEY" ``` *** ## TypeScript SDK ### Installation ```bash theme={null} npm install @stateset/sandbox-sdk ``` ### Basic Usage ```typescript theme={null} import { StateSetSandbox } from "@stateset/sandbox-sdk"; const sandbox = new StateSetSandbox({ baseUrl: "https://api.sandbox.stateset.app", authToken: "sk_sandbox_xxx", timeout: 120000, }); // Create sandbox const instance = await sandbox.create({ cpus: "2", memory: "4Gi", timeout_seconds: 600, }); // Write file await sandbox.writeFile( instance.sandbox_id, "/workspace/app.py", 'print("Hello from Python!")' ); // Execute command const result = await sandbox.execute(instance.sandbox_id, { command: "python3 /workspace/app.py", }); console.log(result.stdout); // "Hello from Python!" // Cleanup await sandbox.stop(instance.sandbox_id); ``` ### Streaming Execution ```typescript theme={null} await sandbox.executeStream( instance.sandbox_id, { command: "npm install", stream: true }, { onStdout: (data) => console.log("stdout:", data), onStderr: (data) => console.error("stderr:", data), onExit: (code) => console.log("exit code:", code), } ); ``` ### Extended SDK (Advanced Features) ```typescript theme={null} import { StateSetSandboxExtended } from "@stateset/sandbox-sdk"; const sdk = new StateSetSandboxExtended({ baseUrl: "https://api.sandbox.stateset.app", authToken: "sk_sandbox_xxx", }); // Create checkpoint const checkpoint = await sdk.checkpoints.create(sandboxId, { name: "baseline", include_paths: ["/workspace"], include_env: true, }); // Restore from checkpoint await sdk.checkpoints.restore(sandboxId, checkpoint.id); // Upload artifact to cloud storage const artifact = await sdk.artifacts.upload(sandboxId, { path: "/workspace/report.pdf", remote_path: "reports/2026/report.pdf", }); // Start MCP server const mcpServer = await sdk.startMCPServer(sandboxId, { name: "postgres", command: "npx", args: ["@modelcontextprotocol/server-postgres"], env: { DATABASE_URL: "postgresql://..." }, }); ``` *** ## Python SDK ### Installation ```bash theme={null} pip install stateset-sandbox ``` ### Basic Usage ```python theme={null} from stateset_sandbox import StateSetSandbox client = StateSetSandbox( base_url="https://api.sandbox.stateset.app", auth_token="sk_sandbox_xxx", timeout=30000 ) # Context manager for automatic cleanup with client.create(cpus="2", memory="4Gi") as sandbox: # Write file client.write_file( sandbox.sandbox_id, "/workspace/script.py", "print('Hello from Python!')" ) # Execute result = client.execute(sandbox.sandbox_id, "python3 /workspace/script.py") print(result.stdout) # Sandbox automatically stopped on exit ``` ### Running Claude Code Agent ```python theme={null} sandbox = client.create(cpus="4", memory="8Gi", timeout_seconds=1800) result = client.execute(sandbox.sandbox_id, command=[ "claude", "-p", "Create a REST API with Express.js that has CRUD endpoints for users", "--allowedTools", "Write,Bash,Read,Edit" ]) print(result.stdout) client.stop(sandbox.sandbox_id) ``` *** ## WebSocket API Connect for real-time streaming: ```javascript theme={null} const ws = new WebSocket('wss://api.sandbox.stateset.app/ws?token=YOUR_JWT'); // Execute with streaming ws.send(JSON.stringify({ type: 'execute', sandboxId: 'sandbox-xxx', command: 'npm run build', stream: true })); ws.onmessage = (event) => { const msg = JSON.parse(event.data); switch (msg.type) { case 'stdout': console.log(msg.data); break; case 'stderr': console.error(msg.data); break; case 'exit': console.log('Exit code:', msg.code); break; case 'done': console.log('Complete'); break; } }; ``` *** ## API Reference ### Sandbox Lifecycle | Method | Endpoint | Description | | ------ | ---------------------------- | ------------------- | | POST | `/api/v1/sandbox/create` | Create new sandbox | | GET | `/api/v1/sandbox/:id` | Get sandbox details | | GET | `/api/v1/sandbox/:id/status` | Get sandbox status | | GET | `/api/v1/sandboxes` | List all sandboxes | | POST | `/api/v1/sandbox/:id/stop` | Stop sandbox | | DELETE | `/api/v1/sandbox/:id` | Delete sandbox | ### File Operations | Method | Endpoint | Description | | ------ | --------------------------------------------- | ---------------------- | | POST | `/api/v1/sandbox/:id/files` | Write files (base64) | | GET | `/api/v1/sandbox/:id/files?path=...` | Read file (base64) | | GET | `/api/v1/sandbox/:id/files/download?path=...` | Download file (binary) | ### Command Execution | Method | Endpoint | Description | | ------ | ----------------------------- | --------------- | | POST | `/api/v1/sandbox/:id/execute` | Execute command | **Execute Request:** ```json theme={null} { "command": "npm run build", "working_dir": "/workspace", "env": {"NODE_ENV": "production"}, "stream": false, "timeout": 30000 } ``` ### Checkpoints | Method | Endpoint | Description | | ------ | ----------------------------------------------- | -------------------- | | POST | `/api/v1/sandbox/:id/checkpoints` | Create checkpoint | | GET | `/api/v1/sandbox/:id/checkpoints` | List checkpoints | | POST | `/api/v1/sandbox/:id/checkpoints/:cpId/restore` | Restore checkpoint | | POST | `/api/v1/sandbox/:id/checkpoints/:cpId/clone` | Clone to new sandbox | | DELETE | `/api/v1/sandbox/:id/checkpoints/:cpId` | Delete checkpoint | ### Artifacts (Cloud Storage) | Method | Endpoint | Description | | ------ | ---------------------------------------- | ---------------------- | | POST | `/api/v1/sandbox/:id/artifacts/upload` | Upload to S3/GCS/Azure | | POST | `/api/v1/sandbox/:id/artifacts/download` | Download from storage | | GET | `/api/v1/artifacts` | List artifacts | | GET | `/api/v1/artifacts/:id/url` | Get pre-signed URL | | DELETE | `/api/v1/artifacts/:id` | Delete artifact | ### MCP Servers | Method | Endpoint | Description | | ------ | --------------------------------- | ---------------------- | | POST | `/api/v1/sandbox/:id/mcp/start` | Start MCP server | | POST | `/api/v1/sandbox/:id/mcp/stop` | Stop MCP server | | GET | `/api/v1/sandbox/:id/mcp/servers` | List running servers | | GET | `/api/v1/sandbox/:id/mcp/presets` | List available presets | ### Agent Sessions | Method | Endpoint | Description | | ------ | ----------------------------------- | -------------------- | | POST | `/api/v1/agent-sessions` | Create agent session | | GET | `/api/v1/agent-sessions/:id` | Get session details | | POST | `/api/v1/agent-sessions/:id/start` | Start session | | POST | `/api/v1/agent-sessions/:id/exec` | Execute in session | | POST | `/api/v1/agent-sessions/:id/pause` | Pause session | | POST | `/api/v1/agent-sessions/:id/resume` | Resume session | | POST | `/api/v1/agent-sessions/:id/stop` | Stop session | | GET | `/api/v1/agent-sessions/:id/events` | Get session events | ### API Keys | Method | Endpoint | Description | | ------ | ----------------------------- | ------------------ | | POST | `/api/v1/api-keys` | Create new API key | | GET | `/api/v1/api-keys` | List API keys | | DELETE | `/api/v1/api-keys/:id` | Revoke API key | | POST | `/api/v1/api-keys/:id/rotate` | Rotate API key | ### Webhooks | Method | Endpoint | Description | | ------ | ---------------------- | ---------------- | | POST | `/api/v1/webhooks` | Register webhook | | GET | `/api/v1/webhooks` | List webhooks | | PUT | `/api/v1/webhooks/:id` | Update webhook | | DELETE | `/api/v1/webhooks/:id` | Delete webhook | ### Tunnels (Port Forwarding) | Method | Endpoint | Description | | ------ | --------------------------------------- | ------------- | | POST | `/api/v1/sandbox/:id/tunnels` | Create tunnel | | GET | `/api/v1/sandbox/:id/tunnels` | List tunnels | | DELETE | `/api/v1/sandbox/:id/tunnels/:tunnelId` | Delete tunnel | *** ## Create Sandbox Options | Field | Type | Default | Description | | ----------------- | ------ | ------------- | ------------------------------------------- | | `cpus` | string | `"2"` | CPU limit ("1", "2", "500m") | | `memory` | string | `"2Gi"` | Memory limit ("1Gi", "2Gi", "512Mi") | | `timeout_seconds` | number | `600` | Sandbox lifetime (60-86400) | | `env` | object | `{}` | Environment variables | | `isolation` | string | `"container"` | Isolation level: container, gvisor, microvm | | `gpu.count` | number | - | GPU count (1-8) | | `gpu.type` | string | - | GPU type ("nvidia.com/gpu") | | `gpu.memory_gb` | number | - | GPU memory (1-256) | *** ## Agent Sessions Long-running agent sessions with automatic sandbox rotation: ```typescript theme={null} // Create session with budget controls const session = await sdk.sessions.create({ name: "code-review-agent", budget: { cost_cap_cents: 1000, iteration_limit: 50, duration_limit_seconds: 3600, }, sandbox: { cpus: "4", memory: "8Gi", timeout_seconds: 600, }, rotation: { pre_rotate_buffer_seconds: 60, include_process_state: true, }, }); // Start session await sdk.sessions.start(session.id); // Execute commands (auto-rotates sandbox as needed) const result = await sdk.sessions.exec(session.id, { command: "claude -p 'Review the codebase' --allowedTools Write,Bash,Read", }); // Get session events const events = await sdk.sessions.getEvents(session.id); // Stop when done await sdk.sessions.stop(session.id); ``` **Session States:** * `pending` - Created, not started * `running` - Active execution * `rotating` - Sandbox rotation in progress * `paused` - Temporarily suspended * `completed` - Successfully finished * `failed` - Error occurred * `cancelled` - Manually stopped *** ## MCP Server Integration Start Model Context Protocol servers inside sandboxes: ```typescript theme={null} // Start filesystem MCP server await sdk.startMCPServer(sandboxId, { name: "filesystem", command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"], port: 3000, }); // Start PostgreSQL MCP server await sdk.startMCPServer(sandboxId, { name: "postgres", command: "npx", args: ["-y", "@modelcontextprotocol/server-postgres"], env: { DATABASE_URL: "postgresql://user:pass@host/db", }, port: 3001, }); // List running servers const servers = await sdk.listMCPServers(sandboxId); // Stop server await sdk.stopMCPServer(sandboxId, "postgres"); ``` **Built-in MCP Presets:** * `filesystem` - File operations * `github` - GitHub repository access * `postgres` - PostgreSQL queries * `slack` - Slack messaging * `brave-search` - Web search * `puppeteer` - Browser automation *** ## Checkpoints Save and restore sandbox state: ```typescript theme={null} // Create checkpoint const checkpoint = await sdk.checkpoints.create(sandboxId, { name: "after-setup", description: "Initial project setup complete", include_paths: ["/workspace"], exclude_paths: ["/workspace/node_modules"], include_env: true, }); // List checkpoints const checkpoints = await sdk.checkpoints.list(sandboxId); // Restore to checkpoint await sdk.checkpoints.restore(sandboxId, checkpointId); // Clone checkpoint to new sandbox const newSandbox = await sdk.checkpoints.clone(sandboxId, checkpointId); // Compare two checkpoints const diff = await sdk.checkpoints.compare(sandboxId, checkpointId1, checkpointId2); ``` *** ## Webhooks Subscribe to sandbox events: ```typescript theme={null} const webhook = await sdk.webhooks.create({ url: "https://your-app.com/webhooks/sandbox", events: [ "sandbox.created", "sandbox.ready", "sandbox.stopped", "command.completed", "checkpoint.created", ], secret: "whsec_your_webhook_secret", }); ``` **Webhook Events:** * `sandbox.created`, `sandbox.ready`, `sandbox.stopped`, `sandbox.error`, `sandbox.timeout` * `command.started`, `command.completed`, `command.failed` * `file.written`, `artifact.uploaded`, `artifact.deleted` * `checkpoint.created`, `checkpoint.restored`, `checkpoint.deleted` * `mcp.started`, `mcp.stopped` * `resource.warning`, `resource.critical` * `security.alert` *** ## Configuration ### Environment Variables | Variable | Default | Description | | ----------------------- | --------- | ----------------------------- | | `SANDBOX_IMAGE` | - | Docker image for sandbox pods | | `DEFAULT_CPUS` | `"2"` | Default CPU limit | | `DEFAULT_MEMORY` | `"2Gi"` | Default memory limit | | `DEFAULT_TIMEOUT` | `600` | Default timeout (seconds) | | `MAX_SANDBOXES_PER_ORG` | `5` | Max concurrent sandboxes | | `WARM_POOL_ENABLED` | `false` | Enable warm pod pool | | `WARM_POOL_SIZE` | `5` | Warm pool size | | `SANDBOX_EXEC_BACKEND` | `kubectl` | Exec backend: kubectl or k8s | *** ## Self-Hosted Deployment ### Prerequisites * Kubernetes cluster (1.24+) * kubectl configured * PostgreSQL database * Redis (optional, for warm pools) ### Deploy ```bash theme={null} # Clone repository git clone https://github.com/stateset/stateset-sandbox cd stateset-sandbox # Apply Kubernetes manifests kubectl apply -f k8s/namespace.yaml kubectl apply -f k8s/rbac.yaml kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/secret.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/deployment.yaml # Verify deployment kubectl get pods -n stateset-sandbox ``` ### Configure Secrets ```bash theme={null} kubectl create secret generic sandbox-secrets -n stateset-sandbox \ --from-literal=JWT_SECRET=your-jwt-secret \ --from-literal=DATABASE_URL=postgresql://user:pass@host/db \ --from-literal=REDIS_URL=redis://host:6379 ``` *** ## Security ### Container Isolation * **Non-root user:** Runs as UID 1001 * **Dropped capabilities:** ALL capabilities dropped * **Seccomp profile:** Enabled by default * **Read-only filesystem:** Only /workspace is writable * **Resource limits:** CPU, memory, ephemeral storage enforced ### Network Isolation * **Egress allowed:** HTTPS (443), DNS (53) * **Private ranges blocked:** 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 * **Network policies:** Restrictive by default ### Authentication * **API Keys:** Revocable, organization-scoped * **JWTs:** Signed with secret, expiring tokens * **Rate limiting:** Per-organization limits *** ## Preinstalled Tools Each sandbox includes: | Category | Tools | | -------------------- | ------------------------------------------- | | **Languages** | Node.js 20, Python 3.11, Go 1.21, Rust 1.75 | | **Package Managers** | npm, yarn, pnpm, pip, cargo | | **Version Control** | git, gh (GitHub CLI) | | **Build Tools** | make, cmake, gcc, g++ | | **Utilities** | curl, wget, jq, ripgrep, fd | | **Containers** | Docker CLI (socket mount optional) | *** ## Quick Reference ### CLI Commands (curl) ```bash theme={null} # Register curl -X POST https://api.sandbox.stateset.app/api/v1/register \ -H "Content-Type: application/json" \ -d '{"first_name":"...", "last_name":"...", "organization_name":"...", "email":"..."}' # Create sandbox curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/create \ -H "Authorization: ApiKey KEY" \ -H "Content-Type: application/json" \ -d '{"timeout_seconds": 300}' # Execute command curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/ID/execute \ -H "Authorization: ApiKey KEY" \ -H "Content-Type: application/json" \ -d '{"command": "echo hello"}' # Write file curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/ID/files \ -H "Authorization: ApiKey KEY" \ -H "Content-Type: application/json" \ -d '{"files": [{"path": "/workspace/file.txt", "content": "BASE64_CONTENT"}]}' # Read file curl "https://api.sandbox.stateset.app/api/v1/sandbox/ID/files?path=/workspace/file.txt" \ -H "Authorization: ApiKey KEY" # Stop sandbox curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/ID/stop \ -H "Authorization: ApiKey KEY" # List sandboxes curl https://api.sandbox.stateset.app/api/v1/sandboxes \ -H "Authorization: ApiKey KEY" ``` ### SDK Quick Reference ```typescript theme={null} // TypeScript const sandbox = new StateSetSandbox({ baseUrl, authToken }); await sandbox.create({ cpus, memory, timeout_seconds }); await sandbox.writeFile(id, path, content); await sandbox.execute(id, { command }); await sandbox.readFile(id, path); await sandbox.stop(id); ``` ```python theme={null} # Python client = StateSetSandbox(base_url, auth_token) sandbox = client.create(cpus="2", memory="4Gi") client.write_file(sandbox.sandbox_id, path, content) result = client.execute(sandbox.sandbox_id, command) content = client.read_file(sandbox.sandbox_id, path) client.stop(sandbox.sandbox_id) ``` *** ## Ideas to Try * Register and create your first sandbox * Run a Claude Code agent to generate and test code * Set up checkpoints to save and restore work * Use MCP servers for database or GitHub integration * Create agent sessions for long-running tasks * Set up webhooks for real-time notifications * Deploy self-hosted with warm pools for fast startup * Use GPU sandboxes for ML workloads *** *StateSet Sandbox v0.4.0* *January 2026* # Sandbox API Flow Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-api-flow Create, execute, manage files, and tear down a sandbox. # Sandbox API Flow This guide shows a typical end-to-end flow using the Sandbox API. ## 1) Register and get an API key ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/register \ -H "Content-Type: application/json" \ -d '{"first_name": "Your", "last_name": "Name", "organization_name": "Company", "email": "you@example.com"}' ``` ## 2) Create a sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/create \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"timeout_seconds": 300}' ``` ## 3) Execute a command ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/execute \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command": "python3 -c \"print(Hello World!)\""}' ``` ## 4) Write a file ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/files/write \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"path": "/workspace/hello.txt", "content": "SGVsbG8h", "encoding": "base64"}' ``` ## 5) Read a file ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/files/read \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"path": "/workspace/hello.txt"}' ``` ## 6) Stop the sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/stop \ -H "Authorization: ApiKey YOUR_API_KEY" ``` ## Related Documentation * [Sandbox Quickstart](/stateset-sandbox-quickstart) * [API Reference](/stateset-sandbox/API_REFERENCE) # Sandbox Architecture Overview Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-architecture-overview High-level design of the StateSet Sandbox platform. # Sandbox Architecture Overview StateSet Sandbox runs in Kubernetes with a controller that manages sandbox lifecycles, a warm pod pool for fast startup, and isolated execution runtimes. ## Core Components * **Controller**: Stateless API service that provisions and manages sandboxes * **Warm Pod Pool**: Pre-initialized pods to reduce startup latency * **State Stores**: Redis for coordination and Postgres/CloudSQL for persistence * **Isolated Runtimes**: gVisor, Kata, or container isolation by policy ## Request Flow 1. Client calls the Sandbox API. 2. Controller claims a warm pod (or creates one). 3. Pod is configured for the org and timeout. 4. Exec/WebSocket streams connect to the sandbox. ## Performance Model Warm pool provisioning keeps sandbox creation typically under 100ms for common profiles. ## Related Documentation * [Sandbox Architecture (Full)](/stateset-sandbox/ARCHITECTURE) * [Operations Guide](/stateset-sandbox/OPERATIONS) # Sandbox Deployments Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-deployments Deployment guides for AWS, GCP, and Azure. # Sandbox Deployments StateSet Sandbox can be deployed on major cloud providers. Use the provider-specific guides for step-by-step instructions and infrastructure requirements. ## Supported Providers * **AWS**: EKS-based deployment * **GCP**: GKE-based deployment * **Azure**: AKS-based deployment ## Guides * [AWS Deployment](/stateset-sandbox/DEPLOYMENT_AWS) * [GCP Deployment](/stateset-sandbox/DEPLOYMENT_GCP) * [Azure Deployment](/stateset-sandbox/DEPLOYMENT_AZURE) ## Related Documentation * [Operations Guide](/stateset-sandbox/OPERATIONS) * [Production Guide](/stateset-sandbox/PRODUCTION_GUIDE) # Sandbox Operations Overview Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-operations-overview Health checks, metrics, and production readiness. # Sandbox Operations Overview The Sandbox controller exposes health and metrics endpoints for monitoring and orchestration. ## Health Endpoints * `GET /health` basic health check * `GET /ready` readiness probe for Kubernetes * `GET /health/detailed` detailed component status ## Metrics * Prometheus metrics exposed at `GET /metrics` * Uses `stateset_sandbox_` metric prefix ## Production Readiness * Use readiness probes and health checks * Alert on sandbox creation and execution errors * Monitor warm pool availability and startup latency ## Related Documentation * [Operations Guide](/stateset-sandbox/OPERATIONS) * [Production Guide](/stateset-sandbox/PRODUCTION_GUIDE) # StateSet Sandbox Quickstart Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-quickstart Create, execute, and manage a sandbox in minutes. # StateSet Sandbox Quickstart This quickstart shows the minimal flow to create a sandbox and execute a command. ## 1) Register and get an API key ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/register \ -H "Content-Type: application/json" \ -d '{"first_name": "Your", "last_name": "Name", "organization_name": "Company", "email": "you@example.com"}' ``` ## 2) Create a sandbox ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/create \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"timeout_seconds": 300}' ``` ## 3) Execute a command ```bash theme={null} curl -X POST https://api.sandbox.stateset.app/api/v1/sandbox/SANDBOX_ID/execute \ -H "Authorization: ApiKey YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"command": "python3 -c \"print(Hello World!)\""}' ``` ## Next Steps * [Sandbox README](/stateset-sandbox/README) * [Sandbox API Reference](/stateset-sandbox/API_REFERENCE) # Sandbox SDK (Node.js) Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-sdk-node Node.js SDK usage for creating and managing sandboxes. # StateSet Sandbox StateSet Sandbox is a Kubernetes-based sandbox infrastructure for running code execution workloads inside isolated pods. It exposes REST and WebSocket APIs for creating sandboxes, streaming command output, and reading or writing files inside each sandbox workspace. Sign up for a free API Key at [sandbox.stateset.app](https://sandbox.stateset.app). # Sandbox SDK (Node.js) Use the Node.js SDK to create sandboxes, execute commands, and manage files. ## Install ```bash theme={null} npm install @stateset/sandbox-sdk ``` ## Initialize the Client ```typescript theme={null} import { StateSetSandbox } from '@stateset/sandbox-sdk'; const client = new StateSetSandbox({ baseUrl: 'https://api.sandbox.stateset.app', authToken: 'sk-sandbox-YOUR_API_KEY', orgId: 'org_YOUR_ORG_ID' }); ``` ## Create and Execute ```typescript theme={null} const sandbox = await client.create({ timeout_seconds: 300 }); const result = await client.execute(sandbox.sandbox_id, { command: ['python3', '-c', 'print("Hello from StateSet!")'] }); ``` ## File Operations ```typescript theme={null} await client.writeFiles(sandbox.sandbox_id, [ { path: '/workspace/hello.txt', content: Buffer.from('Hello!').toString('base64') } ]); const file = await client.readFiles(sandbox.sandbox_id, ['/workspace/hello.txt']); ``` ## Cleanup ```typescript theme={null} await client.stop(sandbox.sandbox_id); ``` ## Related Documentation * [Quickstart](/stateset-sandbox/QUICKSTART) * [API Reference](/stateset-sandbox/API_REFERENCE) # Sandbox SDK (Python) Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-sdk-python Python SDK usage for creating and managing sandboxes. # Sandbox SDK (Python) Use the Python SDK to create sandboxes, execute commands, and manage files. ## Install ```bash theme={null} pip install stateset-sandbox ``` ## Initialize the Client ```python theme={null} from stateset_sandbox import SandboxClient client = SandboxClient( base_url="https://api.sandbox.stateset.app", api_key="sk-sandbox-YOUR_API_KEY", org_id="org_YOUR_ORG_ID", ) ``` ## Create and Execute ```python theme={null} sandbox = client.create(timeout_seconds=300) result = client.execute( sandbox_id=sandbox["sandbox_id"], command=["python3", "-c", "print('Hello from StateSet!')"], ) ``` ## File Operations ```python theme={null} client.write_files( sandbox_id=sandbox["sandbox_id"], files=[{"path": "/workspace/hello.txt", "content": "SGVsbG8h", "encoding": "base64"}], ) file = client.read_files(sandbox_id=sandbox["sandbox_id"], paths=["/workspace/hello.txt"]) ``` ## Cleanup ```python theme={null} client.stop(sandbox_id=sandbox["sandbox_id"]) ``` ## Related Documentation * [Quickstart](/stateset-sandbox/QUICKSTART) * [API Reference](/stateset-sandbox/API_REFERENCE) # Sandbox Security Overview Source: https://docs.stateset.com/stateset-sandbox/stateset-sandbox-security-overview Isolation models, API key security, and best practices. # Sandbox Security Overview StateSet Sandbox provides layered security from the edge to execution runtimes. ## Security Layers * **API Gateway**: TLS, rate limiting, API key auth, and WAF * **Controller**: Input validation, authz, secret management, audit logging * **Runtime Isolation**: Container, gVisor, or microVMs (Kata/Firecracker) ## Isolation Modes * **Container**: Fastest, best for trusted workloads * **gVisor**: User-space kernel for untrusted code * **Kata/Firecracker**: MicroVM isolation for sensitive workloads ## Key Management * Generate strong API keys * Store keys in environment variables or secret managers * Rotate keys regularly ## Related Documentation * [Security Guide](/stateset-sandbox/SECURITY_GUIDE) * [Runtime Selection](/stateset-sandbox/runtime-selection) # About StateSet Sandboxes Source: https://docs.stateset.com/stateset-sandbox/stateset-sandboxes Understand how sandboxes provide secure agent execution. # About StateSet Sandboxes StateSet Sandboxes provide isolated execution environments for AI agents with controlled access to tools and data. ## How sandboxes work * A controller provisions a sandbox on demand. * Your agent executes commands and file operations in an isolated runtime. * Outputs stream back to your client for auditing and traceability. ## Why this design Isolation reduces risk while enabling agent workflows to run in production environments. ## When to use sandboxes * **Agent evaluation**: test workflows safely before production * **Production runs**: execute with clear audit trails * **Multi-tenant setups**: isolate workloads by org ## Relationship to other features Sandboxes power agent execution for ResponseCX, Console, and iCommerce workflows. ## Further reading * [Sandbox Quickstart](/stateset-sandbox-quickstart) * [Sandbox API Reference](/stateset-sandbox/API_REFERENCE) # StateSet Sequencer Architecture Source: https://docs.stateset.com/stateset-sequencer-architecture The high-level architecture of the StateSet Sequencer, a Verifiable Event Sync (VES) v1.0 implementation for deterministic event ordering, cryptographic verification, and agent-to-agent payment sequencing. # StateSet Sequencer Architecture This document describes the high-level architecture of the StateSet Sequencer, a Verifiable Event Sync (VES) v1.0 implementation for deterministic event ordering, cryptographic verification, and agent-to-agent payment sequencing. ## System Overview ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ StateSet Sequencer │ │ │ ┌──────────────────┐ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ HTTP / gRPC │ │ │ │ │ │ │ │ │ AI Agent 1 │──────────────▶│ │ Ingest │───▶│ Sequencer │───▶│ Event Store │ │ │ (Local SQLite) │ │ │ Service │ │ │ │ (PostgreSQL) │ │ │ │ │ │ │ │ │ │ │ │ └──────────────────┘ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │ │ │ │ │ │ ┌──────────────────┐ │ ▼ │ │ │ │ │ HTTP / gRPC │ ┌─────────────┐ ┌──────┴──────┐ │ │ │ AI Agent 2 │──────────────▶│ │ Agent Key │ │ Schema │ │ │ │ (Local SQLite) │ │ │ Registry │ │ Registry │ │ │ │ │ │ │ │ │ │ │ │ └──────────────────┘ │ └─────────────┘ └─────────────┘ │ │ │ ▼ │ ┌──────────────────┐ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ HTTP / gRPC │ │ Projector │ │ Commitment │ │ │ AI Agent N │──────────────▶│ │ │───▶│ Engine │ │ │ (Local SQLite) │ │ │ (Domain │ │ (Merkle) │ │ │ │ │ │ Handlers) │ │ │ │ └──────────────────┘ │ └──────┬──────┘ └────────┬────────┘ │ │ │ │ │ │ │ │ ┌─────────────┐ ┌──────┴──────┐ │ │ │ │ │ x402 │ │ Dead Letter │ │ │ │ │ │ Payment │ │ Queue │ │ │ │ │ │ Engine │ └─────────────┘ │ │ │ │ └──────┬──────┘ │ │ │ │ │ │ │ │ │ ┌──────┴──────────────────────────────────────┴────────────────┐ │ │ │ │ Operational Infrastructure │ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ │ │ │ │ │ Cache │ │ Circuit │ │ Pool │ │ Metrics & │ │ │ │ │ │ │ Manager │ │ Breaker │ │ Monitor │ │ Telemetry │ │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ │ Compliance Proof Engine │ │ │ │ │ (Verification + Storage) │ │ │ │ └──────────────────┬──────────────────────┘ │ │ │ │ │ │ │ ┌─────────────────────────────────────────┐ ┌─────────────────┐ │ │ │ │ Validity Proof Registry │ │ Anchor Service │ │ │ │ │ (External SNARK/ZK proofs) │ │ (Ethereum L2) │ │ │ │ └─────────────────────────────────────────┘ └────────┬────────┘ │ │ └────────────────────────────────────────────────────────┼────────────────┘ │ │ │ ┌────────────────────┐ ▼ │ │ │ ┌─────────────────┐ └─▶│ stateset-stark │ │ Set Chain │ │ (STARK Prover) │ │ (SetPaymentBatch│ │ │ │ + StateSetAnchor) └────────────────────┘ └─────────────────┘ ``` ### Component Relationships ``` ┌───────────────────────────────────────────────────────────────────────────────────────────────┐ │ Full Stack Architecture │ ├───────────────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │ │ AI Agent │────▶│ stateset-sequencer│────▶│ stateset-stark │────▶│ Set Chain │ │ │ │ (CLI) │ │ (Event Sync + │ │ (ZK Proofs) │ │ (L2: Anchors + │ │ │ │ │ │ Payments) │ │ │ │ Payments) │ │ │ └─────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │ │ SQLite │ │ PostgreSQL │ │ STARK Proofs │ │ On-Chain │ │ │ │ Outbox │ │ Event Store + │ │ (~100-200KB) │ │ Anchors + │ │ │ │ │ │ Payment Intents │ │ │ │ Settlements │ │ │ └─────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ │ │ │ Protocols: HTTP REST | gRPC v1+v2 (streaming) | x402 (payments) | VES v1.0 (events) │ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────┘ ``` ## Core Components ### 1. Ingest Service **Location:** `src/api/handlers/ingest.rs`, `src/server.rs` The entry point for all events via HTTP REST and gRPC. Responsible for: * **Authentication**: Validates API keys, JWT tokens, or agent Ed25519 signatures * **Schema Validation**: Validates payloads against registered JSON Schemas (configurable: disabled, warn, strict) * **Signature Verification**: Verifies Ed25519 agent signatures with domain-separated hashing * **Deduplication**: Rejects duplicate `event_id` and `command_id` values * **Batching**: Groups events for efficient processing with parallel partitioning * **Rate Limiting**: Sliding-window per-tenant rate limiting ``` Request → Auth → Rate Limit → Validate Schema → Verify Sig → Dedupe → Sequencer ``` ### 2. Agent Key Registry **Location:** `src/auth/agent_keys.rs`, `src/infra/postgres/agent_key_registry.rs` Manages agent public keys for signature verification: * **Key Registration**: `POST /api/v1/agents/keys` (REST) and `RegisterAgentKey` (gRPC) * **Key Lookup**: `(tenant_id, agent_id, key_id) -> public_key` with LRU caching * **Key Types**: Ed25519 (signing) and X25519 (encryption) * **Validity Windows**: Keys have `valid_from` and `valid_to` timestamps * **Revocation**: Keys can be revoked to invalidate future signatures * **Proof of Possession**: Registration requires a signature proving key ownership ```rust theme={null} pub struct AgentKeyEntry { pub public_key: [u8; 32], // Ed25519 or X25519 public key pub key_type: KeyType, // Signing or Encryption pub status: KeyStatus, // Active, Revoked, Expired pub valid_from: Option>, pub valid_to: Option>, } ``` ### 3. Sequencer **Location:** `src/infra/postgres/sequencer.rs`, `src/infra/postgres/ves_sequencer.rs` Assigns monotonic sequence numbers to events: * **Monotonic Ordering**: Each `(tenant_id, store_id)` has independent sequence counter * **Gap-Free**: Sequence numbers are contiguous with no gaps * **Atomic Assignment**: Uses a single PostgreSQL transaction with `SELECT ... FOR UPDATE` on the per-stream counter * **Receipt Generation**: Produces signed receipts for each sequenced event (configurable via `VES_SEQUENCER_SIGNING_KEY`) * **Sequencer Identity**: Optional pinned sequencer ID via `VES_SEQUENCER_ID` ```sql theme={null} -- Sequence counter table CREATE TABLE sequence_counters ( tenant_id UUID NOT NULL, store_id UUID NOT NULL, current_sequence BIGINT NOT NULL DEFAULT 0, PRIMARY KEY (tenant_id, store_id) ); ``` ### 4. Event Store **Location:** `src/infra/postgres/event_store.rs` Append-only storage for sequenced events: * **Immutability**: Events are never modified or deleted * **Encryption-at-Rest**: Optional AES-256-GCM payload encryption (modes: disabled, optional, required) * **Indexing**: Efficient queries by sequence, entity, and time * **Range Reads**: Fetch events by sequence number range * **Read/Write Splitting**: Reads served from replica pool when configured ```sql theme={null} CREATE TABLE events ( tenant_id UUID NOT NULL, store_id UUID NOT NULL, sequence_number BIGINT NOT NULL, event_id UUID UNIQUE NOT NULL, entity_type VARCHAR(64) NOT NULL, entity_id VARCHAR(256) NOT NULL, event_type VARCHAR(128) NOT NULL, payload JSONB NOT NULL, payload_hash BYTEA NOT NULL, created_at TIMESTAMPTZ NOT NULL, PRIMARY KEY (tenant_id, store_id, sequence_number) ); ``` ### 5. Projector **Location:** `src/projection/handlers.rs`, `src/projection/runner.rs` Applies events to domain projections: * **Domain Handlers**: Entity-specific projection logic * **Optimistic Concurrency**: Version checking prevents conflicts * **Invariant Validation**: Rejects events violating business rules * **Checkpoint Tracking**: Tracks last processed sequence per store * **Dead Letter Queue**: Failed projections are moved to DLQ for retry Supported entity types: * **Order**: `order.created`, `order.confirmed`, `order.shipped`, etc. * **Inventory**: `inventory.initialized`, `inventory.adjusted`, `inventory.reserved` * **Product**: `product.created`, `product.updated`, `product.deactivated` * **Customer**: `customer.created`, `customer.updated`, `customer.address_added` * **Return**: `return.requested`, `return.approved`, `return.refunded` * **x402 Payment**: `x402_payment.created`, `x402_payment.sequenced`, `x402_payment.settled` * **x402 Batch**: `x402_batch.created`, `x402_batch.committed`, `x402_batch.settled` ### 6. Commitment Engine **Location:** `src/infra/postgres/commitment.rs`, `src/infra/ves_commitment.rs` Creates Merkle tree commitments over event batches: * **Merkle Roots**: SHA-256 trees over event payload hashes * **State Roots**: Track state transitions (prev\_root -> new\_root) * **Inclusion Proofs**: Generate proofs for individual events * **Batch Storage**: Persist commitments for later verification * **VES Commitments**: Separate commitment engine for VES v1.0 events ```rust theme={null} pub struct BatchCommitment { pub batch_id: Uuid, pub tenant_id: TenantId, pub store_id: StoreId, pub prev_state_root: [u8; 32], pub new_state_root: [u8; 32], pub events_root: [u8; 32], // Merkle root of payload hashes pub event_count: u32, pub sequence_range: (u64, u64), pub committed_at: DateTime, pub chain_tx_hash: Option<[u8; 32]>, } ``` ### 7. Anchor Service **Location:** `src/anchor.rs` Submits commitments to Ethereum L2: * **StateSetAnchor Contract**: On-chain batch commitment storage * **SetPaymentBatch Contract**: On-chain x402 payment batch settlement * **Transaction Building**: Constructs and signs anchor transactions using Alloy * **Verification**: Confirms anchoring status on-chain * **Gas Management**: Handles gas estimation and pricing * **Circuit Breaker Protected**: External calls guarded by circuit breaker ### 8. Compliance Proof Engine **Location:** `src/domain/ves_compliance.rs`, `src/infra/ves_compliance.rs` Stores and verifies zero-knowledge compliance proofs generated by `stateset-stark`: * **Proof Storage**: Stores STARK proofs in `ves_compliance_proofs` table * **Public Input Validation**: Ensures canonical public inputs match event data * **Policy Verification**: Validates proof matches declared policy * **Idempotency**: Deduplicates by `(event_id, proof_type, policy_hash)` ```sql theme={null} CREATE TABLE ves_compliance_proofs ( id UUID PRIMARY KEY, event_id UUID NOT NULL REFERENCES ves_events(event_id), proof_type VARCHAR(64) NOT NULL, -- e.g., "stark.compliance.v1" proof_version INTEGER NOT NULL, policy_id VARCHAR(128) NOT NULL, -- e.g., "aml.threshold" policy_params JSONB NOT NULL, -- e.g., {"threshold": 10000} policy_hash BYTEA NOT NULL, -- SHA256 of policy proof_hash BYTEA NOT NULL, -- SHA256 of proof bytes proof_bytes BYTEA, -- Full STARK proof (~100-200KB) public_inputs JSONB NOT NULL, -- Canonical JCS format witness_commitment BYTEA, -- Rescue hash of private witness verified_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL, UNIQUE (event_id, proof_type, proof_version, policy_hash) ); ``` ### 9. Validity Proof Registry **Location:** `src/domain/ves_validity.rs`, `src/infra/ves_validity.rs` External proof registry for SNARK/ZK proofs attesting to batch properties: * **Proof Submission**: External provers submit validity proofs for committed batches * **Proof Storage**: Persists proof bytes and public inputs * **Proof Hashing**: SHA-256 hash of proof for integrity * **Stream Matching**: Trigger enforces proofs reference valid batches ```sql theme={null} CREATE TABLE ves_validity_proofs ( id UUID PRIMARY KEY, batch_id UUID NOT NULL REFERENCES ves_commitments(batch_id), proof_type VARCHAR(64) NOT NULL, proof_version INTEGER NOT NULL, proof_hash BYTEA NOT NULL, proof_bytes BYTEA, public_inputs JSONB NOT NULL, verified_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL ); ``` ### 10. x402 Payment Engine **Location:** `src/domain/x402_payment.rs`, `src/infra/postgres/x402_repository.rs`, `src/infra/x402_batch_worker.rs`, `src/api/handlers/x402.rs` Implements the x402 protocol for agent-to-agent payment sequencing and batched L2 settlement: * **Payment Intent Sequencing**: Signed payment intents assigned sequence numbers * **Signature Verification**: Ed25519 signatures with `X402_PAYMENT_V1` domain separator * **Nonce-Based Replay Protection**: Per-agent nonce tracking * **Idempotency**: Optional idempotency keys for at-most-once delivery * **Batch Assembly**: Configurable batch size (default 100, max 1000) and time thresholds * **Merkle Commitments**: Merkle root computation over batched payment intents * **Multi-Chain Settlement**: Settlement on Set Chain L2 via `SetPaymentBatch` contract * **Multi-Asset Support**: USDC, USDT, ssUSD, wssUSD, DAI, ETH ``` AI Agent | | Creates X402PaymentIntent (signed) v Sequencer | | 1. Validates signature | 2. Checks nonce (replay protection) | 3. Assigns sequence number | 4. Batches into X402PaymentBatch v Set Chain L2 (SetPaymentBatch contract) | | Executes aggregated transfers v Settlement complete (receipt with Merkle inclusion proof) ``` **Supported Networks:** | Network | Chain ID | Type | | ----------------- | -------- | ------- | | Set Chain | 84532001 | Mainnet | | Set Chain Testnet | 84532002 | Testnet | | Arc | 5042001 | Mainnet | | Base | 8453 | Mainnet | | Ethereum | 1 | Mainnet | | Arbitrum | 42161 | Mainnet | | Optimism | 10 | Mainnet | **Supported Assets:** | Asset | Decimals | Description | | ------ | -------- | ------------------------------- | | USDC | 6 | USD Coin | | USDT | 6 | Tether | | ssUSD | 6 | StateSet USD (yield-bearing) | | wssUSD | 6 | Wrapped StateSet USD (ERC-4626) | | DAI | 18 | DAI stablecoin | | ETH | 18 | Native ETH | **Payment Intent Lifecycle:** ``` Pending -> Sequenced -> Batched -> Settled -> Failed -> Expired ``` ### 11. Schema Registry **Location:** `src/domain/schema.rs`, `src/infra/postgres/schema_store.rs`, `src/api/handlers/schemas.rs` JSON Schema validation system for event payloads: * **Schema Versioning**: Monotonically increasing version per `(tenant_id, event_type)` * **Compatibility Modes**: Forward, Backward, Full, or None * **Validation Modes**: Disabled, Optional (warn), Required, Strict * **Status Lifecycle**: Active -> Deprecated -> Archived * **LRU Caching**: Configurable cache size and TTL for hot schemas * **Detailed Errors**: Validation errors include JSON paths and messages ```rust theme={null} pub struct Schema { pub id: SchemaId, pub tenant_id: TenantId, pub event_type: EventType, pub version: u32, pub schema_json: serde_json::Value, pub status: SchemaStatus, // Active, Deprecated, Archived pub compatibility: SchemaCompatibility, // Forward, Backward, Full, None pub description: Option, pub created_at: DateTime, } ``` ## gRPC API (v1 + v2) **Location:** `src/grpc/`, `proto/sequencer.proto`, `proto/sequencer_v2.proto` The sequencer exposes dual gRPC services alongside the REST API: ### gRPC v2 Service (Full VES v1.0 Protocol) | RPC | Type | Description | | ------------------- | ----------------------- | -------------------------------------- | | `Push` | Unary | Push a batch of events for sequencing | | `PullEvents` | Unary | Pull events (simple polling) | | `GetSyncState` | Unary | Get current sync state for store | | `GetInclusionProof` | Unary | Get Merkle inclusion proof | | `GetCommitment` | Unary | Get batch commitment | | `GetEntityHistory` | Unary | Get entity event history | | `GetHealth` | Unary | Health check | | `StreamEvents` | Server streaming | Continuous event delivery with filters | | `SyncStream` | Bidirectional streaming | Full-duplex agent sync | | `SubscribeEntity` | Server streaming | Subscribe to entity updates | ### Key Management Service (gRPC) | RPC | Description | | ------------------ | ---------------------------------------------------- | | `RegisterAgentKey` | Register Ed25519/X25519 key with proof of possession | | `GetAgentKeys` | List agent keys with optional filters | | `RevokeAgentKey` | Revoke an agent key | ### Bidirectional Sync Protocol The `SyncStream` RPC enables full-duplex communication: ``` Client -> Server: Push, Pull, EventAck, Heartbeat Server -> Client: PushResponse, PullResponse, SequencedEvent, SyncState, Heartbeat ``` Agents can push events, receive real-time updates, and acknowledge processing in a single persistent connection with heartbeat-based liveness detection. ## Operational Infrastructure ### Authentication System **Location:** `src/auth/` Multi-method authentication with composable validators: | Method | Description | | ------------- | ------------------------------------------------------------ | | API Keys | SHA-256 hashed, scoped to tenant/store, stored in PostgreSQL | | JWT Tokens | HS256/HS384/HS512 with configurable issuer/audience | | Agent Keys | Ed25519 signature verification for VES events | | Bootstrap Key | Initial admin key from `BOOTSTRAP_ADMIN_API_KEY` env var | * **Rate Limiting**: Sliding-window algorithm, configurable per-minute limit * **Permissions Model**: Read, Write, Admin scopes per key * **gRPC Auth Interceptor**: Shared authenticator for gRPC services ### Cache Manager **Location:** `src/infra/cache.rs` Multi-layer LRU caching with configurable TTL per cache type: | Cache | Default Max | Description | | --------------- | ------------ | ------------------------- | | Commitments | configurable | Merkle commitment lookups | | Proofs | configurable | Inclusion proof results | | VES Commitments | configurable | VES-specific commitments | | VES Proofs | configurable | VES-specific proofs | | Agent Keys | configurable | Agent public key lookups | | Schemas | configurable | JSON Schema definitions | ### Pool Monitor **Location:** `src/infra/pool_monitor.rs` Real-time database connection pool health tracking (15-second polling): * **Health States**: Healthy (\< 50%), Moderate (50-80%), Stressed (80-95%), Critical (> 95%) * **Metrics**: Active/idle connections, acquisition latency, slow acquisition tracking * **Integrated**: Exposed via `/health/detailed` endpoint and Prometheus metrics ### Circuit Breaker Registry **Location:** `src/infra/circuit_breaker.rs` Failure resilience for external service calls (L2 anchoring, chain settlement): * **States**: Closed (normal) -> Open (fail-fast) -> HalfOpen (testing recovery) * **Exponential Backoff**: Configurable multiplier with jitter * **Slow Call Detection**: Configurable threshold for degraded performance * **Per-Service Tracking**: Independent breaker per external service ### Dead Letter Queue **Location:** `src/infra/dead_letter.rs` Handles events that fail projection processing: * **Auto-Retry**: Exponential backoff (1 min initial, 1 hour max, 10 retries) * **Categorized Reasons**: Schema validation, invariant violation, state transition errors * **Non-Retryable**: Invariant violations and invalid state transitions skip retry * **Admin Operations**: Retry, purge, and inspect via admin CLI ### Payload Encryption-at-Rest **Location:** `src/infra/payload_encryption.rs`, `src/crypto/encrypt.rs` Automatic event payload encryption in the database: * **Modes**: Disabled, Optional, Required * **Algorithm**: AES-256-GCM * **HPKE Support**: Multi-recipient encryption via X25519-HKDF-SHA256 * **Key Rotation**: Supports key versioning and rotation ### Audit Logging **Location:** `src/infra/audit.rs` Comprehensive audit trail for administrative operations: * API key management (create, revoke, update) * Schema registry changes (register, deprecate, delete) * Agent key operations (register, rotate, revoke) * Authentication events (login, failure, token refresh) * Dead letter queue operations (retry, purge) ### Metrics & Telemetry **Location:** `src/metrics/`, `src/telemetry/` * **Prometheus Export**: `/metrics` endpoint with 40+ predefined metric names * **Component Metrics**: Background collection every 15 seconds (pool, circuit breaker stats) * **OpenTelemetry**: OTLP export for distributed tracing (`OTEL_EXPORTER_OTLP_ENDPOINT`) * **Structured Logging**: JSON or text format (`LOG_FORMAT`) * **Counters, Gauges, Histograms**: Full metric type support with labels ### Graceful Shutdown **Location:** `src/infra/graceful_shutdown.rs` Coordinated shutdown with request draining: * **Request Tracking**: Guard-based in-flight request monitoring * **Shutdown Signals**: Coordinated signal propagation to background tasks * **Deadline Enforcement**: Configurable drain timeout ## stateset-stark (ZK Compliance Proofs) **Repository:** `stateset-stark` A STARK proving system that enables cryptographic verification of compliance policies on encrypted event payloads without revealing the underlying data. ### Purpose When events contain encrypted payloads (e.g., order amounts), compliance rules (e.g., AML thresholds) need verification without exposing sensitive data. `stateset-stark` generates zero-knowledge proofs that: 1. The prover knows the plaintext payload 2. The payload satisfies the compliance policy 3. The payload matches the encrypted ciphertext hash ### Architecture ``` stateset-stark/ ├── crates/ │ ├── ves-stark-primitives/ # Goldilocks field, Rescue hash │ ├── ves-stark-air/ # AIR constraint definitions (167 constraints) │ ├── ves-stark-prover/ # Proof generation │ ├── ves-stark-verifier/ # Proof verification │ ├── ves-stark-batch/ # Batch proofs (Phase 2) │ ├── ves-stark-client/ # HTTP client for sequencer │ └── ves-stark-cli/ # Command-line tool ``` ### Cryptographic Foundation | Component | Choice | Notes | | ---------- | -------------------------------- | ----------------------------- | | Field | Goldilocks (p = 2^64 - 2^32 + 1) | 64-bit efficient arithmetic | | Hash | Rescue-Prime | STARK-friendly algebraic hash | | Commitment | Blake3-256 Merkle | Vector commitments | | Security | \~100 bits | Default proof options | ### Supported Policies | Policy ID | Constraint | Use Case | | ----------------- | -------------------- | --------------------------------- | | `aml.threshold` | `amount < threshold` | AML compliance (strict less-than) | | `order_total.cap` | `amount <= cap` | Order limits (less-than-or-equal) | ### Proof Generation Flow ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ Compliance Proof Generation │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ 1. Agent decrypts VES event payload (ephemeral, off-chain) │ │ │ │ │ ▼ │ │ 2. Extract witness data (e.g., order amount = 5000) │ │ │ │ │ ▼ │ │ 3. Fetch canonical public inputs from sequencer │ │ GET /api/v1/ves/compliance/{event_id}/inputs │ │ │ │ │ ▼ │ │ 4. Build ComplianceWitness + CompliancePublicInputs │ │ │ │ │ ▼ │ │ 5. Generate STARK proof (ves-stark-prover) │ │ - Build execution trace (105 columns, 128+ rows) │ │ - Apply AIR constraints (167 total) │ │ - Produce proof (~100-200KB) │ │ │ │ │ ▼ │ │ 6. Submit proof to sequencer │ │ POST /api/v1/ves/compliance/{event_id}/proofs │ │ │ │ │ ▼ │ │ 7. Sequencer verifies and stores proof │ │ │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### Public Inputs (Canonical JCS Format) ```json theme={null} { "eventId": "550e8400-e29b-41d4-a716-446655440000", "tenantId": "tenant-uuid", "storeId": "store-uuid", "sequenceNumber": 42, "payloadKind": 1, "payloadPlainHash": "abc123...", "payloadCipherHash": "def456...", "eventSigningHash": "789abc...", "policyId": "aml.threshold", "policyParams": { "threshold": 10000 }, "policyHash": "computed-sha256..." } ``` ### CLI Usage ```bash theme={null} # Generate a compliance proof ves-stark prove --amount 5000 --limit 10000 --policy aml.threshold # Verify a proof ves-stark verify --proof proof.stark --inputs inputs.json --limit 10000 # Benchmark proving performance ves-stark benchmark -n 10 --max-amount 10000 --limit 10000 ``` ### Integration Points | Sequencer Endpoint | Purpose | | ----------------------------------------------------- | ----------------------------- | | `GET /api/v1/ves/compliance/{event_id}/inputs` | Fetch canonical public inputs | | `POST /api/v1/ves/compliance/{event_id}/proofs` | Submit generated proof | | `GET /api/v1/ves/compliance/{event_id}/proofs` | List proofs for event | | `GET /api/v1/ves/compliance/proofs/{proof_id}` | Get proof by ID | | `GET /api/v1/ves/compliance/proofs/{proof_id}/verify` | Verify proof | ## REST API Reference ### Event Ingestion | Method | Endpoint | Description | | ------ | --------------------------- | ---------------------------------------- | | `POST` | `/api/v1/events/ingest` | Legacy event ingestion | | `POST` | `/api/v1/ves/events/ingest` | VES v1.0 event ingestion with signatures | ### VES Commitments | Method | Endpoint | Description | | ------ | ----------------------------------- | ----------------------- | | `GET` | `/api/v1/ves/commitments` | List VES commitments | | `POST` | `/api/v1/ves/commitments` | Create VES commitment | | `POST` | `/api/v1/ves/commitments/anchor` | Commit and anchor | | `GET` | `/api/v1/ves/commitments/:batch_id` | Get specific commitment | ### VES Proofs & Anchoring | Method | Endpoint | Description | | ------ | ------------------------------------- | ------------------------- | | `GET` | `/api/v1/ves/proofs/:sequence_number` | Get VES inclusion proof | | `POST` | `/api/v1/ves/proofs/verify` | Verify VES proof | | `POST` | `/api/v1/ves/anchor` | Anchor VES commitment | | `GET` | `/api/v1/ves/anchor/:batch_id/verify` | Verify on-chain anchoring | ### VES Validity Proofs | Method | Endpoint | Description | | ------ | ---------------------------------------------- | --------------------- | | `GET` | `/api/v1/ves/validity/:batch_id/inputs` | Get public inputs | | `GET` | `/api/v1/ves/validity/:batch_id/proofs` | List validity proofs | | `POST` | `/api/v1/ves/validity/:batch_id/proofs` | Submit validity proof | | `GET` | `/api/v1/ves/validity/proofs/:proof_id` | Get proof by ID | | `GET` | `/api/v1/ves/validity/proofs/:proof_id/verify` | Verify validity proof | ### VES Compliance Proofs | Method | Endpoint | Description | | ------ | ------------------------------------------------ | ----------------------- | | `POST` | `/api/v1/ves/compliance/:event_id/inputs` | Get public inputs | | `GET` | `/api/v1/ves/compliance/:event_id/proofs` | List compliance proofs | | `POST` | `/api/v1/ves/compliance/:event_id/proofs` | Submit compliance proof | | `GET` | `/api/v1/ves/compliance/proofs/:proof_id` | Get proof by ID | | `GET` | `/api/v1/ves/compliance/proofs/:proof_id/verify` | Verify compliance proof | ### x402 Payment Protocol | Method | Endpoint | Description | | ------ | ------------------------------------------ | --------------------- | | `POST` | `/api/v1/x402/payments` | Submit payment intent | | `GET` | `/api/v1/x402/payments` | List payment intents | | `GET` | `/api/v1/x402/payments/:intent_id` | Get payment intent | | `GET` | `/api/v1/x402/payments/:intent_id/receipt` | Get payment receipt | | `POST` | `/api/v1/x402/batches` | Create payment batch | | `GET` | `/api/v1/x402/batches/:batch_id` | Get batch | | `POST` | `/api/v1/x402/batches/settle` | Settle batch on-chain | ### Schema Registry | Method | Endpoint | Description | | -------- | ----------------------------------------------- | ------------------------- | | `GET` | `/api/v1/schemas` | List schemas | | `POST` | `/api/v1/schemas` | Register schema | | `POST` | `/api/v1/schemas/validate` | Validate payload | | `GET` | `/api/v1/schemas/:schema_id` | Get schema | | `PUT` | `/api/v1/schemas/:schema_id/status` | Update schema status | | `DELETE` | `/api/v1/schemas/:schema_id` | Delete schema | | `GET` | `/api/v1/schemas/event-type/:event_type` | Get schemas by event type | | `GET` | `/api/v1/schemas/event-type/:event_type/latest` | Get latest schema | ### Legacy Events & Commitments | Method | Endpoint | Description | | ---------- | ------------------------------------------ | ------------------------- | | `GET` | `/api/v1/events` | List events | | `GET` | `/api/v1/head` | Get current head sequence | | `GET` | `/api/v1/entities/:entity_type/:entity_id` | Get entity history | | `GET/POST` | `/api/v1/commitments` | List/create commitments | | `GET` | `/api/v1/commitments/:batch_id` | Get commitment | | `GET` | `/api/v1/proofs/:sequence_number` | Get inclusion proof | | `POST` | `/api/v1/proofs/verify` | Verify proof | ### Health & Observability | Method | Endpoint | Description | | ------ | ------------------ | ---------------------------------------- | | `GET` | `/health` | Basic health check | | `GET` | `/health/detailed` | Detailed health (pool, circuit breakers) | | `GET` | `/ready` | Readiness probe | | `GET` | `/metrics` | Prometheus metrics | ## Data Flow ### Event Ingestion Flow ``` 1. Agent creates event locally (SQLite outbox) 2. Agent signs event with Ed25519 private key 3. Agent POSTs to /api/v1/ves/events/ingest (or pushes via gRPC) 4. Sequencer authenticates request (API key, JWT, or agent signature) 5. Schema validation (if configured) 6. Sequencer verifies Ed25519 signature against registered public key 7. Sequencer deduplicates by event_id and command_id 8. Sequencer assigns sequence number atomically 9. Event stored in PostgreSQL events table (encrypted-at-rest if configured) 10. Sequencer returns receipt with sequence number 11. Agent marks event as synced locally ``` ### x402 Payment Flow ``` 1. Agent creates X402PaymentIntent with payer/payee/amount/asset 2. Agent signs intent with Ed25519 key (X402_PAYMENT_V1 domain separator) 3. Agent POSTs to /api/v1/x402/payments 4. Sequencer validates signature, checks nonce, verifies expiration 5. Sequencer assigns x402 sequence number atomically 6. Intent stored with status=Sequenced 7. Batch worker assembles intents into X402PaymentBatch (configurable size/time) 8. Batch worker computes Merkle root over payment intents 9. Batch submitted to SetPaymentBatch contract on Set Chain L2 10. On confirmation, intents marked Settled with tx_hash and block_number 11. Payment receipt with Merkle inclusion proof available for verification ``` ### Commitment Flow ``` 1. Client requests commitment for sequence range 2. Commitment Engine reads events from Event Store 3. Engine builds Merkle tree from payload hashes 4. Engine computes state root transition 5. Commitment stored in commitments table 6. (Optional) Anchor Service submits to StateSetAnchor 7. Chain tx hash stored with commitment ``` ### Verification Flow ``` 1. Client requests inclusion proof for sequence N 2. Engine retrieves commitment containing N 3. Engine rebuilds Merkle tree for batch 4. Engine generates proof path for leaf N 5. Client verifies locally, then verifies the batch root is anchored on-chain ``` ### Compliance Proof Flow ``` 1. Agent creates encrypted VES event (payload encrypted with HPKE) 2. Agent syncs event to sequencer (receives sequence number) 3. Agent decrypts payload locally (ephemeral) 4. Agent extracts witness data (e.g., order.total = 5000) 5. Agent fetches canonical public inputs from sequencer 6. Agent generates STARK proof using stateset-stark: - Builds execution trace (witness decomposition, Rescue hash) - Applies 167 AIR constraints - Produces ~100-200KB proof 7. Agent submits proof to sequencer 8. Sequencer validates public inputs match event 9. Sequencer stores proof in ves_compliance_proofs 10. (Future) Sequencer cryptographically verifies proof ``` ## Database Schema ### Core Tables | Table | Purpose | | ------------------------ | --------------------------------------- | | `events` | Append-only event log (legacy) | | `ves_events` | VES v1.0 events with signatures | | `sequence_counters` | Per-store sequence tracking | | `ves_sequencer_receipts` | VES sequencer signed receipts | | `commitments` | Legacy Merkle commitment records | | `ves_commitments` | VES v1.0 Merkle commitments | | `ves_compliance_proofs` | STARK compliance proofs | | `ves_validity_proofs` | Batch validity proofs | | `agent_signing_keys` | Agent public key registry with rotation | | `entity_versions` | Entity version tracking (OCC) | | `projection_checkpoints` | Projector progress | | `agent_sync_state` | Agent sync state tracking | | `rejected_events_log` | Event rejection audit log | | `ves_rejections` | VES event rejection log | | `x402_payment_intents` | x402 payment authorizations | | `x402_payment_batches` | x402 aggregated payment batches | | `x402_sequence_counters` | Per-store x402 sequence tracking | | `x402_nonce_tracking` | x402 nonce replay protection | | `api_keys` | API key management | ### Migrations | Migration | Description | | ------------------------------- | ---------------------------------------------------- | | `001_production_postgres.sql` | Core event store, sequence counters, entity versions | | `002_ves_v1_tables.sql` | VES v1.0 events, receipts, commitments, agent keys | | `003_constraints.sql` | Unique indexes, chain TX hash validation | | `004_ves_validity_proofs.sql` | Validity proof registry with stream matching | | `005_ves_compliance_proofs.sql` | Compliance proof storage with stream matching | | `006_key_rotation_policies.sql` | Agent key rotation policies | | `007_encryption_groups.sql` | Encryption group management | | `008_command_dedupe.sql` | Command deduplication indexes | | `009_api_keys.sql` | API key management tables | | `010_ves_sequence_counters.sql` | VES-specific sequence counters | | `011_x402_payments.sql` | x402 payment intents and batches | ### Indexes ```sql theme={null} -- Fast event lookups CREATE INDEX idx_events_entity ON events(tenant_id, store_id, entity_type, entity_id); CREATE INDEX idx_events_type ON events(tenant_id, store_id, event_type); CREATE INDEX idx_events_created ON events(tenant_id, store_id, created_at); -- Agent key lookups CREATE INDEX idx_agent_keys_lookup ON agent_keys(tenant_id, agent_id, key_id); ``` ## Cryptographic Design ### Signing Hash Construction Per VES v1.0 Section 8.3: ``` signing_hash = SHA256( "VES_EVENTSIG_V1" || // Domain separator event_id || tenant_id || store_id || agent_id || entity_type || entity_id || event_type || payload_plain_hash || occurred_at ) agent_signature = Ed25519.Sign(agent_private_key, signing_hash) ``` ### x402 Payment Signing Hash ``` signing_hash = SHA256( "X402_PAYMENT_V1" || // Domain separator intent_id || payer_address || payee_address || amount || asset || network || chain_id || nonce || valid_until ) payer_signature = Ed25519.Sign(agent_private_key, signing_hash) ``` ### Merkle Tree Construction ``` [Root] / \ [H01] [H23] / \ / \ [H0] [H1] [H2] [H3] | | | | E0 E1 E2 E3 (Event payload hashes) Domain-separated hashing: - Leaf: SHA256("VES_LEAF_V1" || payload_hash) - Node: SHA256("VES_NODE_V1" || left || right) ``` ### Encryption (HPKE) Multi-recipient encryption for VES-ENC-1: | Parameter | Value | | --------- | ------------------ | | Mode | Base | | KEM | X25519-HKDF-SHA256 | | KDF | HKDF-SHA256 | | AEAD | AES-256-GCM | ## Offline-First Architecture Agents operate offline using SQLite: ``` ┌─────────────────────────────────────────┐ │ Local Agent │ │ │ │ ┌─────────────┐ ┌───────────────┐ │ │ │ Business │───▶│ Outbox │ │ │ │ Logic │ │ (SQLite) │ │ │ └─────────────┘ └───────┬───────┘ │ │ │ │ │ ▼ │ │ ┌───────────────┐ │ │ │ Sync State │ │ │ │ Tracker │ │ │ └───────┬───────┘ │ └─────────────────────────────┼───────────┘ │ ▼ (when online) ┌───────────────────┐ │ Remote Sequencer │ │ (HTTP or gRPC) │ └───────────────────┘ ``` **SQLite Tables:** ```sql theme={null} -- Local event outbox CREATE TABLE outbox ( local_seq INTEGER PRIMARY KEY, event_id TEXT UNIQUE NOT NULL, payload TEXT NOT NULL, signature TEXT NOT NULL, pushed_at TEXT, remote_seq INTEGER ); -- Sync state tracking CREATE TABLE sync_state ( key TEXT PRIMARY KEY, value TEXT NOT NULL ); ``` ## Scalability Considerations ### Horizontal Scaling * **Stateless API**: Multiple sequencer instances behind load balancer * **Read/Write Pool Splitting**: Separate connection pools for reads (replica) and writes (primary) * **Database Pooling**: Configurable pool size, acquire timeout, idle timeout, max lifetime * **Sequence Partitioning**: Each `(tenant_id, store_id)` is independent ### Performance Optimizations * **Batch Inserts**: Events ingested in batches with parallel partitioning * **Read Replicas**: Entity history and read queries served from replica pool * **Multi-Layer Caching**: LRU caches for commitments, proofs, schemas, and agent keys * **Proof Memoization**: Common proof paths cached with TTL * **Connection Pool Monitoring**: Automatic health degradation detection ### Resilience * **Circuit Breakers**: External service calls (L2 anchoring) protected with exponential backoff * **Dead Letter Queue**: Failed projections queued with automatic retry * **Graceful Shutdown**: Request draining on SIGTERM * **Rate Limiting**: Per-tenant sliding-window rate limiter ### Capacity Planning | Component | Recommended | | ---------- | ------------------------------------- | | PostgreSQL | 16+ GB RAM, SSD storage | | Sequencer | 2-4 CPU cores, 4 GB RAM | | Write Pool | 10-20 connections per instance | | Read Pool | 10-20 connections per instance | | Events/sec | \~1000-5000 depending on payload size | ## Security Model ### Trust Boundaries 1. **Agent -> Sequencer**: TLS + Ed25519 signatures + API key/JWT auth 2. **Sequencer -> Database**: Network isolation + credentials + session timeouts 3. **Sequencer -> L2 Chain**: Private key for signing + circuit breaker 4. **Agent -> Agent (payments)**: Ed25519 signed payment intents + nonce replay protection ### Key Management * Agent private keys: Never leave agent, stored securely * Sequencer signing key: For receipt signing (`VES_SEQUENCER_SIGNING_KEY`) * Sequencer anchor key: For L2 transactions (`SEQUENCER_PRIVATE_KEY`) * API keys: SHA-256 hashed, stored in PostgreSQL * Database credentials: Environment variables, not in code * Encryption keys: AES-256-GCM for payload encryption-at-rest ### Audit Trail All administrative operations logged via the audit system: * API key lifecycle (create, revoke, update) * Schema registry changes * Agent key operations * Authentication events * Dead letter queue operations See [SECURITY.md](docs/SECURITY.md) for detailed security guidance. ## Configuration ### Feature Flags (Cargo Features) | Feature | Default | Description | | ------------------- | ------- | ----------------------------------- | | `full` | Yes | Enables all features | | `grpc` | Yes | gRPC service (tonic/prost) | | `telemetry` | Yes | OpenTelemetry distributed tracing | | `anchoring` | Yes | L2 blockchain anchoring (alloy) | | `schema-validation` | Yes | JSON Schema validation (jsonschema) | | `sqlite` | No | SQLite backend for local agents | | `encryption` | No | Payload encryption at rest | ### Key Environment Variables | Variable | Description | | ----------------------------- | ---------------------------------------- | | `DATABASE_URL` | PostgreSQL connection URL (primary) | | `READ_DATABASE_URL` | PostgreSQL connection URL (read replica) | | `PORT` | HTTP listen port (default: 8080) | | `GRPC_PORT` | gRPC listen port (default: PORT + 1) | | `GRPC_DISABLED` | Disable gRPC server | | `AUTH_MODE` | `required` (default) or `disabled` | | `BOOTSTRAP_ADMIN_API_KEY` | Initial admin API key | | `JWT_SECRET` | JWT signing secret | | `VES_SEQUENCER_ID` | Pinned sequencer UUID | | `VES_SEQUENCER_SIGNING_KEY` | Ed25519 key for receipt signing | | `PAYLOAD_ENCRYPTION_MODE` | `disabled`, `optional`, `required` | | `SCHEMA_VALIDATION_MODE` | `disabled`, `warn`, `required`, `strict` | | `RATE_LIMIT_PER_MINUTE` | Request rate limit | | `L2_RPC_URL` | Ethereum L2 RPC endpoint | | `SET_REGISTRY_ADDRESS` | StateSetAnchor contract address | | `SEQUENCER_PRIVATE_KEY` | Anchor transaction signing key | | `OTEL_EXPORTER_OTLP_ENDPOINT` | OpenTelemetry OTLP endpoint | | `LOG_FORMAT` | `json` or `text` (default) | | `CORS_ALLOW_ORIGINS` | Comma-separated origins or `*` | | `DB_MIGRATE_ON_STARTUP` | Run migrations on boot (default: true) | | `CACHE_*` | Cache size and TTL overrides | | `MAX_DB_CONNECTIONS` | Write pool max connections | | `READ_MAX_DB_CONNECTIONS` | Read pool max connections | | `DB_STATEMENT_TIMEOUT_MS` | PostgreSQL statement timeout | | `DB_IDLE_IN_TX_TIMEOUT_MS` | Idle-in-transaction timeout | ## Technology Stack | Component | Technology | | ----------------- | --------------------------------------------------------- | | Language | Rust (Edition 2021) | | Web Framework | Axum 0.7 | | gRPC Framework | Tonic 0.12, Prost 0.13 | | Async Runtime | Tokio | | Database | PostgreSQL 16+ (sqlx 0.8) | | Local Storage | SQLite (sqlx) | | Cryptography | ed25519-dalek 2, sha2, aes-gcm | | Key Exchange | x25519-dalek 2, hpke 0.12 | | Merkle Trees | rs\_merkle (custom domain separation) | | Blockchain | Alloy 0.8 (Ethereum/EVM, Solidity ABI) | | Schema Validation | jsonschema 0.26 | | Authentication | jsonwebtoken 9 | | Serialization | serde, serde\_json, serde\_json\_canonicalizer (RFC 8785) | | Observability | OpenTelemetry 0.24, tracing, Prometheus export | | Testing | proptest, mockall, criterion, fake | ## Binaries | Binary | Path | Description | | -------------------------- | ------------------ | ------------------------------------- | | `stateset-sequencer` | `src/main.rs` | Main sequencer server (HTTP + gRPC) | | `stateset-sequencer-admin` | `src/bin/admin.rs` | Admin CLI for key management, DLQ ops | ## Module Structure ``` src/ ├── main.rs # Entry point ├── lib.rs # Library exports ├── server.rs # HTTP + gRPC server bootstrap, config ├── anchor.rs # On-chain anchoring (Alloy/Ethereum) │ ├── api/ │ ├── mod.rs # REST router definition │ └── handlers/ │ ├── agent_keys.rs # Agent key registration │ ├── anchoring.rs # Commitment anchoring │ ├── commitments.rs # Commitment CRUD │ ├── events.rs # Event listing/retrieval │ ├── health.rs # Health, readiness, detailed checks │ ├── ingest.rs # Event ingestion pipeline │ ├── proofs.rs # Merkle proof generation/verification │ ├── schemas.rs # Schema registry management │ ├── x402.rs # x402 payment protocol │ └── ves/ │ ├── mod.rs # VES v1.0 handler organization │ ├── anchoring.rs # VES commitment anchoring │ ├── commitments.rs # VES commitment management │ ├── compliance_proofs.rs # VES compliance proofs │ ├── inclusion_proofs.rs # VES inclusion proofs │ └── validity_proofs.rs # VES validity proofs │ ├── auth/ │ ├── mod.rs # Auth module (Authenticator, ApiKeyValidator, JwtValidator) │ ├── agent_keys.rs # Agent key registry │ └── middleware.rs # Axum auth middleware + gRPC interceptor │ ├── crypto/ │ ├── hash.rs # Domain-separated SHA-256 hashing │ ├── signing.rs # Ed25519 operations │ └── encrypt.rs # HPKE + AES-256-GCM encryption │ ├── domain/ │ ├── types.rs # Core types (TenantId, StoreId, AgentId, etc.) │ ├── event.rs # EventEnvelope │ ├── commitment.rs # BatchCommitment, MerkleProof │ ├── schema.rs # Schema, SchemaId, SchemaCompatibility │ ├── ves_event.rs # VES v1.0 events │ ├── ves_commitment.rs # VES batch commitments │ ├── ves_compliance.rs # VES compliance proof types │ ├── ves_validity.rs # VES validity proof types │ └── x402_payment.rs # x402 payment intents, batches, receipts │ ├── grpc/ │ ├── mod.rs # gRPC module │ ├── service.rs # gRPC v1 service implementation │ ├── service_v2.rs # gRPC v2 service (streaming, key management) │ └── interceptor.rs # gRPC auth interceptor │ ├── infra/ │ ├── mod.rs # Infrastructure module + trait exports │ ├── traits.rs # Core service traits (EventStore, Sequencer, etc.) │ ├── error.rs # SequencerError, contextual errors │ ├── audit.rs # Audit logging │ ├── batch.rs # Batch operations, deduplication │ ├── cache.rs # Multi-layer LRU caching │ ├── circuit_breaker.rs # Circuit breaker pattern │ ├── dead_letter.rs # Dead letter queue │ ├── graceful_shutdown.rs # Graceful shutdown coordination │ ├── payload_encryption.rs # Encryption-at-rest configuration │ ├── pool_monitor.rs # Connection pool health monitoring │ ├── retry.rs # Exponential backoff retry │ ├── schema_validation.rs # Schema validation mode handling │ ├── x402_batch_worker.rs # x402 batch assembly background worker │ ├── ves_commitment.rs # PgVesCommitmentEngine │ ├── ves_compliance.rs # PgVesComplianceProofStore │ ├── ves_validity.rs # PgVesValidityProofStore │ ├── postgres/ │ │ ├── sequencer.rs # PgSequencer (legacy) │ │ ├── ves_sequencer.rs # VesSequencer (VES v1.0) │ │ ├── event_store.rs # PgEventStore │ │ ├── commitment.rs # PgCommitmentEngine │ │ ├── agent_key_registry.rs # PgAgentKeyRegistry │ │ ├── schema_store.rs # PgSchemaStore │ │ └── x402_repository.rs # PgX402Repository │ └── sqlite/ │ └── outbox.rs # SqliteOutbox (local agents) │ ├── metrics/ │ └── mod.rs # MetricsRegistry, ComponentMetrics, Prometheus export │ ├── migrations/ │ ├── mod.rs # Migration runner │ ├── postgres/ # 11 PostgreSQL migrations │ └── sqlite/ # 1 SQLite migration │ ├── projection/ │ ├── runner.rs # Projection executor │ └── handlers.rs # Domain projection handlers │ ├── proto/ # Generated protobuf code │ ├── mod.rs # Proto module (v1 + v2) │ └── v2/ # gRPC v2 generated code │ ├── telemetry/ │ └── mod.rs # OpenTelemetry setup, OTLP export │ └── bin/ └── admin.rs # Admin CLI binary ``` ## Related Documentation * [Getting Started](GETTING_STARTED.md) - Quick start guide * [System Overview](SYSTEM_OVERVIEW.md) - High-level system overview * [VES Specification](docs/VES_SPEC.md) - Full protocol spec * [API Reference](docs/API_REFERENCE.md) - REST API documentation * [Event Types](docs/EVENT_TYPES.md) - Supported event types * [Deployment Guide](docs/DEPLOYMENT.md) - Production deployment * [Runbook](docs/RUNBOOK.md) - Operational runbook * [Security Guide](docs/SECURITY.md) - Security best practices * [ZK Integration Guide](docs/ZK_INTEGRATION_GUIDE.md) - STARK proof integration * [Agent Integration](docs/AGENT_INTEGRATION.md) - Agent SDK integration guide * [Anchoring Overview](docs/ANCHORING_OVERVIEW.md) - On-chain anchoring details ## Related Repositories | Repository | Purpose | | ---------------- | ------------------------------------------------------------ | | `stateset-stark` | STARK proving system for compliance proofs | | `@stateset/cli` | AI agent CLI with local SQLite outbox | | `set-chain` | Ethereum L2 for anchoring commitments and payment settlement | # StateSet VES System Overview Source: https://docs.stateset.com/stateset-sequencer/stateset-sequencer The world's first operating system for autonomous agents with native USDC wallets and cross-web state management # Verifiable Event Sync (VES) System Overview A complete zero-knowledge commerce infrastructure enabling AI agents to interact with cryptographic verification, STARK proofs, and on-chain anchoring. ## System Architecture ``` ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ AI Agent Commerce Platform │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ AI Agent │ │ AI Agent │ │ AI Agent │ │ AI Agent │ │ │ │ (Orders) │ │ (Inventory) │ │ (Payments) │ │ (Returns) │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ │ └──────────────────┴────────┬─────────┴──────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ StateSet CLI (MCP Server) │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ │ │ Outbox │ │ Ed25519 │ │ HPKE │ │ Event Capture │ │ │ │ │ │ (SQLite) │ │ Signing │ │ Encryption │ │ & Serialization │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │ │ └────────────────────────────────────┬────────────────────────────────────────┘ │ │ │ │ └───────────────────────────────────────┼────────────────────────────────────────────┘ │ VES Protocol v1.0 ▼ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ stateset-sequencer (Rust) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌───────────────┐ │ │ │ Event Ingest │ │ Sequencing │ │ Merkle Trees │ │ Commitments │ │ │ │ (REST/gRPC) │ │ (Deterministic)│ │ (rs_merkle) │ │ (Batches) │ │ │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ └───────┬───────┘ │ │ │ │ │ │ │ │ └────────────────────┴────────────────────┴───────────────────┘ │ │ │ │ │ ┌──────────────────────────────────────┴──────────────────────────────────────┐ │ │ │ Event Store (PostgreSQL/SQLite) │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ └─────────────────────────────────────────┼──────────────────────────────────────────┘ │ Batch Events ▼ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ stateset-stark (Rust) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ STARK Prover │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ │ │ Witness │ │ Trace │ │ AIR │ │ Winterfell │ │ │ │ │ │ Builder │ │ Generator │ │ Constraints │ │ Prover │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ Supported Policies │ │ │ │ • aml.threshold - Proves amount < threshold (AML compliance) │ │ │ │ • order_total.cap - Proves amount <= cap (Order limits) │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ STARK Proofs │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ STARK Verifier │ │ │ │ • Proof verification in ~600µs │ │ │ │ • Public inputs validation │ │ │ │ • Policy compliance checking │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ └─────────────────────────────────────────┼──────────────────────────────────────────┘ │ Verified Proofs ▼ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ set/anchor (Rust) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ Sequencer │ │ Registry │ │ Health │ │ │ │ API Client │ │ Client │ │ Monitoring │ │ │ └────────┬────────┘ └────────┬────────┘ └─────────────────┘ │ │ │ │ │ │ └────────────────────┴─────────────────────────┐ │ │ │ │ └──────────────────────────────────────────────────────────┼─────────────────────────┘ │ On-chain TX ▼ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ Set L2 (EVM-Compatible Chain) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ SetRegistry.sol │ │ │ │ │ │ │ │ struct BatchCommitment { │ │ │ │ bytes32 eventsRoot; // Merkle root of events │ │ │ │ bytes32 prevStateRoot; // Previous state │ │ │ │ bytes32 newStateRoot; // New state after batch │ │ │ │ uint64 sequenceStart; // First sequence number │ │ │ │ uint64 sequenceEnd; // Last sequence number │ │ │ │ uint32 eventCount; // Events in batch │ │ │ │ } │ │ │ │ │ │ │ │ struct StarkProofCommitment { │ │ │ │ bytes32 proofHash; // Hash of STARK proof │ │ │ │ bytes32 policyHash; // Policy used │ │ │ │ bool allCompliant; // Compliance status │ │ │ │ } │ │ │ │ │ │ │ │ Functions: │ │ │ │ • commitBatch() - Anchor batch commitment │ │ │ │ • commitStarkProof() - Anchor STARK proof │ │ │ │ • verifyInclusion() - Verify event in batch │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` ## Data Flow ### Step 1: AI Agent Creates Event ```javascript theme={null} // AI Agent creates a commerce event through the CLI const event = { entityType: 'order', entityId: 'order-001', eventType: 'OrderCreated', payload: { orderId: 'order-001', customerId: 'customer-001', items: [{ sku: 'WIDGET-001', quantity: 2, price: 29.99 }], total: 59.98 } }; // CLI captures, signs, and encrypts the event outbox.append(event); ``` ### Step 2: Event Signing & Encryption (CLI) The CLI performs VES v1.0 protocol operations: 1. **Payload Hash**: `SHA-256(domain_prefix || canonical_json(payload))` 2. **Ed25519 Signature**: Signs event envelope with agent's private key 3. **HPKE Encryption**: Encrypts payload for authorized recipients 4. **Cipher Hash**: `SHA-256(domain_prefix || ciphertext)` ``` Event Envelope: ├── eventId: UUID ├── vesVersion: 1 ├── payloadKind: 1 (encrypted) ├── payloadPlainHash: "0x..." ├── payloadCipherHash: "0x..." ├── agentKeyId: 1 ├── agentSignature: "0x..." └── payloadEncrypted: { ... } ``` ### Step 3: Sequencing (stateset-sequencer) The sequencer: 1. Validates agent signature 2. Assigns deterministic sequence number 3. Adds event to Merkle tree 4. Creates batch when threshold reached ``` Sequenced Event: ├── envelope: { ... } ├── sequenceNumber: 42 ├── sequencedAt: "2024-12-22T20:15:00Z" └── receiptHash: "0x..." ``` ### Step 4: STARK Proof Generation (stateset-stark) For each batch, generate a STARK proof: ```bash theme={null} # Prove compliance: amount < 10000 (AML threshold) ves-stark prove \ --amount 5000 \ --limit 10000 \ --policy aml.threshold \ --inputs public_inputs.json \ --output proof.json ``` **Proof Characteristics:** * Proof Size: \~36KB (individual), \~53KB (batch) * Proving Time: \~20-25ms * Verification Time: \~600µs * Security Level: 128-bit ### Step 5: On-Chain Anchoring (set/anchor → SetRegistry) The anchor service submits to Set L2: ```solidity theme={null} // SetRegistry.commitBatch() commitBatch( batchId, // Unique batch identifier tenantId, // Tenant UUID as bytes32 storeId, // Store UUID as bytes32 eventsRoot, // Merkle root of events prevStateRoot, // State before batch newStateRoot, // State after batch sequenceStart, // 0 sequenceEnd, // 7 eventCount // 8 ); // SetRegistry.commitStarkProof() commitStarkProof( batchId, proofHash, // SHA-256 of STARK proof policyHash, // Policy identifier hash policyLimit, // 10000 allCompliant, // true proofSize, // 53074 provingTimeMs // 25 ); ``` ### Step 6: Verification by Other Agents Any AI agent can verify: 1. **Event Inclusion**: Merkle proof against on-chain root 2. **Compliance**: STARK proof verification 3. **State Transition**: Verify prev\_state → new\_state ```bash theme={null} # Verify a STARK proof ves-stark verify \ --proof proof.json \ --inputs public_inputs.json \ --limit 10000 \ --policy aml.threshold # Output: Proof VALID (verified in 622.133µs) ``` ## Repository Structure | Repository | Path | Description | | ---------------------- | -------------------------------------------- | ------------------------- | | **stateset-sequencer** | `/home/dom/icommerce-app/stateset-sequencer` | VES protocol sequencer | | **stateset-stark** | `/home/dom/icommerce-app/stateset-stark` | STARK prover/verifier | | **set** | `/home/dom/icommerce-app/set` | L2 chain & anchor service | | **CLI** | `/home/dom/stateset-icommerce/cli` | AI agent MCP server | ## Crate Structure (stateset-stark) ``` stateset-stark/crates/ ├── ves-stark-primitives/ # Field arithmetic, Rescue hash ├── ves-stark-air/ # AIR constraints for policies ├── ves-stark-prover/ # Witness & proof generation ├── ves-stark-verifier/ # Proof verification ├── ves-stark-batch/ # zkRollup batch proofs ├── ves-stark-cli/ # Command-line interface └── ves-stark-client/ # HTTP client for sequencer ``` ## CLI Commands ### STARK Prover CLI ```bash theme={null} # Generate public inputs ves-stark gen-inputs --limit 10000 --policy aml.threshold -o inputs.json # Generate compliance proof ves-stark prove --amount 5000 --limit 10000 --policy aml.threshold \ --inputs inputs.json --output proof.json --json # Verify proof ves-stark verify --proof proof.json --inputs inputs.json \ --limit 10000 --policy aml.threshold # Inspect proof metadata ves-stark inspect --proof proof.json # Run benchmark ves-stark benchmark -n 10 --max-amount 10000 --limit 10000 # Generate batch proof (zkRollup style) ves-stark batch-prove -n 8 --limit 10000 --output batch_proof.json # Run sequencer simulation ves-stark sequencer -n 16 --batch-size 8 --limit 10000 \ --output-dir ./proofs ``` ### Sync CLI ```bash theme={null} # Initialize sync configuration stateset-sync init # Generate agent keys stateset-sync keys:generate # Push events to sequencer stateset-sync push # Pull events from sequencer stateset-sync pull # Show sync status stateset-sync status ``` ## Performance Metrics | Operation | Time | Size | | --------------------------- | ------- | ------ | | Individual Proof Generation | \~20ms | \~36KB | | Batch Proof (8 events) | \~25ms | \~53KB | | Proof Verification | \~600µs | - | | Merkle Proof Verification | 1ms | 1KB | ## Security Properties 1. **Privacy**: Event payloads encrypted with HPKE 2. **Authenticity**: Ed25519 signatures on all events 3. **Ordering**: Deterministic sequencing prevents reordering 4. **Compliance**: Zero-knowledge proofs for policy enforcement 5. **Finality**: On-chain anchoring provides immutability 6. **Verifiability**: Anyone can verify proofs without trusted setup ## Running the Demo ```bash theme={null} # Run the complete demonstration ./run-ves-demo.sh ``` See `run-ves-demo.sh` for the full demonstration script. # StateSet Sequencer Architecture Source: https://docs.stateset.com/stateset-sequencer/stateset-sequencer-architecture Core components and data flow for the Verifiable Event Sync (VES) sequencer. # StateSet Sequencer Architecture The StateSet Sequencer assigns deterministic sequence numbers to events, builds Merkle commitments, and batches events for proof generation and on-chain anchoring. ## Components * **Event ingest**: HTTP/gRPC endpoints for agent events * **Sequencing**: Deterministic ordering and receipt generation * **Merkle trees**: Batch commitments for event inclusion proofs * **Storage**: Durable event store for replay and verification ## Data Flow 1. Agents submit events via the sync CLI or API. 2. The sequencer validates signatures and assigns sequence numbers. 3. Events are added to a Merkle tree and batched. 4. Batch commitments are anchored on Set L2. ## Integration Points * **Sync CLI** for agent event capture * **STARK prover** for compliance proofs * **Set L2** for anchoring commitments and proof metadata ## Related Documentation * [Sequencer Overview](/stateset-sequencer) * [Sequencer Quickstart](/stateset-sequencer-quickstart) * [Set L2 Overview](/stateset-set-l2) # Sequencer Operations Source: https://docs.stateset.com/stateset-sequencer/stateset-sequencer-operations Operational guidance for running the VES sequencer. # Sequencer Operations This guide summarizes operational considerations for the StateSet Sequencer. ## Core Responsibilities * Validate and sequence incoming events * Build batch commitments for inclusion proofs * Persist event data for replay and verification ## Batch Lifecycle 1. Accept events and assign sequence numbers 2. Build Merkle trees for a batch 3. Emit commitments for anchoring on Set L2 4. Provide receipts and proofs to clients ## Monitoring Focus * Event ingest rate * Batch size and commit latency * Storage health and replay time ## Related Documentation * [Sequencer Overview](/stateset-sequencer) * [Sequencer Architecture](/stateset-sequencer-architecture) * [Set L2 Verification](/stateset-set-l2-verification) # StateSet Sequencer Quickstart Source: https://docs.stateset.com/stateset-sequencer/stateset-sequencer-quickstart Understand the VES flow and run the demo. # StateSet Sequencer Quickstart This quickstart introduces the Verifiable Event Sync (VES) sequencer flow and points to the demo in the sequencer documentation. ## 1) Review the Architecture * [Sequencer Overview](/stateset-sequencer) * [Set L2 Overview](/stateset-set-l2) ## 2) Run the Demo The sequencer documentation includes a full demo script you can run locally: * `run-ves-demo.sh` ## Next Steps Use the sequencer and Set L2 docs together to understand how events are sequenced, proven, and anchored. # x402 payments reference Source: https://docs.stateset.com/stateset-sequencer/stateset-sequencer-x402 Complete reference for sequencer x402 payment endpoints. # x402 payments reference Reference for the sequencer endpoints that handle x402 payment intents. ## Properties Tenant UUID that owns the payment intent. Store UUID used for sequencing and batching. Agent UUID that signed the payment intent. Payer address for the intent. Payee address for the intent. Amount in smallest units (e.g., 1,000,000 = 1 USDC). ## Examples ### Submit an intent ```bash theme={null} curl -X POST https://api.sequencer.stateset.app/api/v1/x402/payments \ -H "Content-Type: application/json" \ -d '{ "tenant_id": "uuid", "store_id": "uuid", "agent_id": "uuid", "payer_address": "0x...", "payee_address": "0x...", "amount": 1000000, "asset": "usdc", "network": "set_chain", "valid_until": 1705320000, "nonce": 42, "signing_hash": "0x...", "payer_signature": "0x..." }' ``` ## Response The ID of the sequenced payment intent. Current intent status (e.g., `sequenced`). ## Related references * [x402 Payments with iCommerce](/stateset-icommerce-x402-payments) * [Set L2 Verification](/stateset-set-l2-verification) # Sync Server API Basics Source: https://docs.stateset.com/stateset-sync-server-api-basics Base URLs, envelopes, error codes, and idempotency. # Sync Server API Basics This guide summarizes the core HTTP and gRPC contract for the Sync Server. ## Base URLs & Versioning * HTTP base path: `/v1` * OpenAPI: `/api-docs/openapi.json` * Docs UI: `/docs/` or `/swagger-ui/` * Responses include `x-api-version` and `x-api-supported-versions` ## Response Envelopes Success: ```json theme={null} { "meta": { "requestId": "..." }, "data": { "statesetOrderId": "..." } } ``` Error: ```json theme={null} { "meta": { "requestId": "..." }, "error": { "code": "validation_failed", "message": "..." } } ``` ## Error Codes (Common) * `validation_failed` * `rate_limit_exceeded` * `integration_missing` * `upstream_error` * `internal_error` ## Idempotency * Order creation is idempotent on `shopify_order_id` * Write endpoints accept `idempotency-key` (cached for 24h) * Retries return `idempotency-replayed: true` ## Related Documentation * [API Contract](/stateset-sync-server/API_CONTRACT) * [Sync Server README](/stateset-sync-server/README) # Sync Server gRPC Dispatch Flow Source: https://docs.stateset.com/stateset-sync-server-grpc-flow How StateSet API dispatches orders to the Sync Server via gRPC. # Sync Server gRPC Dispatch Flow This guide outlines how orders move from `stateset-api` to `stateset-sync-server` using the gRPC interface. ## High-Level Flow 1. An order is created in `stateset-api`. 2. The outbox worker claims the event and builds a gRPC request. 3. The Sync Server validates tenant + API key. 4. The Sync Server orchestrates downstream integrations. 5. The outbox row is marked delivered or retried. ## Key Interfaces * `stateset.sync.v1.OrderIntegrationService/SubmitOrder` * gRPC metadata header: `x-stateset-api-key` * Default port: `50051` ## Reliability Model * Use outbox-driven dispatch for at-least-once delivery * Retry transient errors (`UNAVAILABLE`, `DEADLINE_EXCEEDED`) * Avoid retries on permanent validation errors ## Related Documentation * [StateSet API → Sync Server Flow](/stateset-sync-server/STATESET_API_TO_SYNC_GRPC) * [API Contract](/stateset-sync-server/API_CONTRACT) # About the Universal Commerce Protocol Source: https://docs.stateset.com/stateset-ucp Understand how UCP standardizes discovery and checkout. # About the Universal Commerce Protocol UCP standardizes discovery and checkout so commerce apps can interoperate across platforms. ## How UCP works * Clients discover capabilities via `/.well-known/ucp`. * A standard checkout session lifecycle is used across apps. * Optional identity linking adds OAuth-based context. ## Why this design UCP reduces custom integrations and makes checkout portable between systems. ## When to use UCP * **Cross-platform commerce**: unify checkout behaviors * **Marketplace apps**: standardize discovery and capabilities * **Agent workflows**: predictable checkout flows ## Further reading * [UCP Handler README](/stateset-ucp-handler/README) * [UCP Integration Guide](/guides/universal-commerce-protocol-handler) # StateSet UCP Quickstart Source: https://docs.stateset.com/stateset-ucp-quickstart Run the UCP handler and verify discovery and checkout flows. # StateSet UCP Quickstart This quickstart helps you run the UCP handler locally and verify the discovery endpoint. ## 1) Run the server ```bash theme={null} git clone https://github.com/stateset/stateset-ucp-handler.git cd stateset-ucp-handler ``` ```bash theme={null} cd stateset-ucp-handler cargo run ``` By default the server listens on `http://0.0.0.0:8081`. ## 2) Verify discovery UCP exposes discovery at `/.well-known/ucp`: ```bash theme={null} curl http://localhost:8081/.well-known/ucp ``` ## 3) Create a checkout session Refer to the handler README for full request/response examples and optional extensions: * [UCP Handler README](/stateset-ucp-handler/README) ## Next Steps * [UCP Integration Guide](/guides/universal-commerce-protocol-handler) # StateSet Worker Source: https://docs.stateset.com/stateset-worker Run the StateSet iCommerce engine in a Cloudflare Sandbox # StateSet Worker Run the [StateSet](https://stateset.io/) iCommerce engine in a [Cloudflare Sandbox](https://developers.cloudflare.com/sandbox/) — `wrangler deploy` and you have a full commerce engine with messaging channels, MCP tools, and an admin UI. ## Architecture ``` Browser / AI Agent / Messaging Platform │ ┌───────┴──────────────────────────────────┐ │ Cloudflare Worker (Hono.js) │ │ - CF Access auth │ │ - Admin UI (React SPA) │ │ - HTTP/WebSocket proxy to container │ │ - Cron: SQLite backup to R2 │ └───────┬──────────────────────────────────┘ │ ┌───────┴──────────────────────────────────┐ │ CF Container (Durable Object) │ │ - @stateset/cli (stateset-channels.js) │ │ - @stateset/embedded (Rust/SQLite) │ │ - 6 messaging channels │ │ - MCP server (87 tools) │ │ - HTTP gateway on port 8080 │ │ - R2 mounted at /data/stateset │ └──────────────────────────────────────────┘ ``` ## Requirements * [Workers Paid plan](https://www.cloudflare.com/plans/developer-platform/) (\$5 USD/month) — required for Cloudflare Sandbox containers * [Anthropic API key](https://console.anthropic.com/) — or use [AI Gateway](https://developers.cloudflare.com/ai-gateway/) for routing and analytics Free-tier Cloudflare features used: * Cloudflare Access (authentication) * AI Gateway (optional, for API routing/analytics) * R2 Storage (optional, for persistence) ## Quick Start ```bash theme={null} # Install dependencies npm install # Set your API key npx wrangler secret put ANTHROPIC_API_KEY # Deploy npm run deploy ``` After deploying, your commerce engine is live at `https://stateset-sandbox.your-subdomain.workers.dev/`. The first request takes 1-2 minutes while the container boots. A loading page is shown during startup. To use the admin UI and protected routes, you'll need to: 1. [Set up Cloudflare Access](#setting-up-cloudflare-access) for authentication 2. [Enable R2 storage](#persistent-storage-r2) so commerce data persists (recommended) ## Setting Up Cloudflare Access The admin UI at `/_admin/` and all `/api/admin/*` routes require Cloudflare Access authentication. ### 1. Enable Access on workers.dev 1. Go to the [Workers & Pages dashboard](https://dash.cloudflare.com/?to=/:account/workers-and-pages) 2. Select your Worker (`stateset-sandbox`) 3. In **Settings** > **Domains & Routes**, click the `...` menu on the workers.dev row 4. Click **Enable Cloudflare Access** 5. Configure who can access (email allow list, Google, GitHub, etc.) 6. Copy the **Application Audience (AUD)** tag ### 2. Set Access Secrets ```bash theme={null} npx wrangler secret put CF_ACCESS_TEAM_DOMAIN # Enter: myteam.cloudflareaccess.com npx wrangler secret put CF_ACCESS_AUD # Enter: your-application-audience-tag ``` Find your team domain in the [Zero Trust Dashboard](https://one.dash.cloudflare.com/) under **Settings** > **Custom Pages**. ### 3. Redeploy ```bash theme={null} npm run deploy ``` Now `/_admin/` requires Cloudflare Access authentication. ## Persistent Storage (R2) By default, commerce data (SQLite database, config) is lost when the container restarts. R2 storage enables persistence. ### Setup 1. Go to **R2** > **Overview** in the [Cloudflare Dashboard](https://dash.cloudflare.com/) 2. Click **Manage R2 API Tokens** 3. Create a token with **Object Read & Write** permissions for the `stateset-data` bucket ```bash theme={null} npx wrangler secret put R2_ACCESS_KEY_ID npx wrangler secret put R2_SECRET_ACCESS_KEY npx wrangler secret put CF_ACCOUNT_ID ``` ### How It Works **SQLite backup** — The commerce database is backed up safely using SQLite's built-in `.backup` API, which handles concurrent writes correctly. A cron job runs every 5 minutes. **Config sync** — Gateway configuration is synced to R2 via rsync. **Restore on boot** — On container startup, data is restored from R2 if the backup is newer than local data. An integrity check verifies the database before restoring. **Manual backup** — Trigger an immediate backup from the admin UI Storage tab or via `POST /api/admin/storage/sync`. ## Admin UI Access the admin UI at `/_admin/` with three tabs: * **Overview** — Gateway status, commerce stats (customers, orders, returns, products), channel summary, restart controls * **Channels** — Per-channel status cards for all 6 messaging channels (Telegram, Discord, Slack, WhatsApp, Email, SMS) * **Storage** — R2 configuration status, last backup time, manual backup button, backup strategy info ## Messaging Channels Configure channels via environment secrets. Each channel is enabled automatically when its token is set. ### Telegram ```bash theme={null} npx wrangler secret put TELEGRAM_BOT_TOKEN ``` ### Discord ```bash theme={null} npx wrangler secret put DISCORD_BOT_TOKEN ``` ### Slack ```bash theme={null} npx wrangler secret put SLACK_BOT_TOKEN npx wrangler secret put SLACK_APP_TOKEN ``` ### WhatsApp ```bash theme={null} npx wrangler secret put WHATSAPP_TOKEN ``` ### Email ```bash theme={null} npx wrangler secret put EMAIL_SMTP_HOST ``` ### SMS (Twilio) ```bash theme={null} npx wrangler secret put TWILIO_ACCOUNT_SID ``` ## Commerce Settings ```bash theme={null} # Enable apply mode npx wrangler secret put ALLOW_APPLY # Enter: true # Override default AI model npx wrangler secret put DEFAULT_MODEL # Enter: claude-opus-4-5 ``` ## AI Gateway (Optional) Route API requests through [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) for caching, rate limiting, and analytics: ```bash theme={null} npx wrangler secret put AI_GATEWAY_API_KEY npx wrangler secret put AI_GATEWAY_BASE_URL # Enter: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/anthropic ``` AI Gateway variables take precedence over direct `ANTHROPIC_API_KEY` if both are set. ## Container Lifecycle By default, the container stays alive indefinitely. To sleep after inactivity (reduces cost, adds cold start latency): ```bash theme={null} npx wrangler secret put SANDBOX_SLEEP_AFTER # Enter: 10m (or 1h, 30m, etc.) ``` With R2 configured, data persists across restarts. ## Debug Endpoints Enable with `DEBUG_ROUTES=true` (requires Cloudflare Access): | Endpoint | Description | | ----------------------------- | ----------------------------------------------------- | | `GET /debug/version` | Container and stateset version info | | `GET /debug/processes` | All container processes (add `?logs=true` for output) | | `GET /debug/cli?cmd=...` | Run a CLI command in the container | | `GET /debug/logs?id=...` | Logs for a specific process | | `GET /debug/env` | Sanitized environment configuration | | `GET /debug/container-config` | Gateway config from inside the container | ## Local Development ```bash theme={null} cp .dev.vars.example .dev.vars # Edit .dev.vars with your ANTHROPIC_API_KEY npm install npm run dev ``` Set `DEV_MODE=true` in `.dev.vars` to skip Cloudflare Access auth. ## All Secrets Reference | Secret | Required | Description | | ------------------------ | -------- | -------------------------------------------------------- | | `ANTHROPIC_API_KEY` | Yes\* | Anthropic API key (or use AI Gateway) | | `AI_GATEWAY_API_KEY` | Yes\* | AI Gateway provider key (requires `AI_GATEWAY_BASE_URL`) | | `AI_GATEWAY_BASE_URL` | No | AI Gateway endpoint URL | | `OPENAI_API_KEY` | No | OpenAI API key (alternative provider) | | `CF_ACCESS_TEAM_DOMAIN` | Yes | Cloudflare Access team domain | | `CF_ACCESS_AUD` | Yes | Cloudflare Access application audience | | `STATESET_GATEWAY_TOKEN` | No | Gateway auth token | | `R2_ACCESS_KEY_ID` | No | R2 access key for persistent storage | | `R2_SECRET_ACCESS_KEY` | No | R2 secret key for persistent storage | | `CF_ACCOUNT_ID` | No | Cloudflare account ID (required for R2) | | `TELEGRAM_BOT_TOKEN` | No | Telegram channel | | `DISCORD_BOT_TOKEN` | No | Discord channel | | `SLACK_BOT_TOKEN` | No | Slack channel | | `SLACK_APP_TOKEN` | No | Slack channel (required with SLACK\_BOT\_TOKEN) | | `WHATSAPP_TOKEN` | No | WhatsApp channel | | `EMAIL_SMTP_HOST` | No | Email channel | | `TWILIO_ACCOUNT_SID` | No | SMS channel (Twilio) | | `ALLOW_APPLY` | No | Set to `true` to enable apply mode | | `DEFAULT_MODEL` | No | Override default AI model | | `DEV_MODE` | No | Set to `true` for local dev (skips auth) | | `DEBUG_ROUTES` | No | Set to `true` to enable `/debug/*` routes | | `SANDBOX_SLEEP_AFTER` | No | Container sleep timeout: `never` (default), `10m`, `1h` | \* One of `ANTHROPIC_API_KEY` or `AI_GATEWAY_API_KEY` is required. ## Troubleshooting **Container fails to start:** Check `npx wrangler tail` for logs. Verify `ANTHROPIC_API_KEY` is set. **R2 not mounting:** Ensure all three secrets are set (`R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `CF_ACCOUNT_ID`). R2 mounting only works in production. **Access denied on admin routes:** Verify `CF_ACCESS_TEAM_DOMAIN` and `CF_ACCESS_AUD` are set correctly. **Slow first request:** Cold starts take 1-2 minutes. A loading page is shown automatically. **Config changes not working:** Update the Dockerfile cache bust comment and redeploy. ## Links * [StateSet](https://stateset.io/) * [Cloudflare Sandbox Docs](https://developers.cloudflare.com/sandbox/) * [Cloudflare Access Docs](https://developers.cloudflare.com/cloudflare-one/policies/access/) * [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) # Complete an x402 payment Source: https://docs.stateset.com/stateset-x402-walkthrough Learn how to complete an x402 payment from 402 to receipt. # Complete an x402 payment This tutorial walks you through a full x402 payment from HTTP 402 to receipt verification. ## Prerequisites * Access to a paywalled endpoint that returns HTTP 402 * A signer capable of Ed25519 signatures * Sequencer endpoint URL ## Step 1: Request a protected resource Call the resource endpoint and capture the `X-Payment-Required` header. ## Step 2: Build and sign an intent Create an `X402PaymentIntent` with payer/payee, amount, network, and validity window. Sign with the `X402_PAYMENT_V1` domain separator. ## Step 3: Retry with X-Payment Retry the request with the signed intent in the `X-Payment` header. ## Step 4: Sequence the intent Submit the intent to the sequencer for batching and settlement. ## Step 5: Fetch receipt and verify Request the receipt and verify inclusion proof against the on-chain batch commitment. ## Next steps * [Sequencer x402 Payments](/stateset-sequencer-x402) * [Set L2 Verification](/stateset-set-l2-verification)