> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sync Server ACP Guide

> Agentic Commerce Protocol support in the StateSet Sync Server.

# Agent Commerce Protocol (ACP) Guide

The Agent Commerce Protocol (ACP) enables AI agents to place orders directly into your commerce infrastructure. With a single API call, an AI agent can create an order that automatically flows through to fulfillment and ERP systems.

## Overview

```
┌─────────────────────────────────────────────────────────────────────┐
│                         AI AGENT LAYER                              │
│   (ChatGPT, Claude, Custom Agents, Voice Assistants, Chatbots)     │
└─────────────────────────────────────────────────────────────────────┘
                                  │
                                  │ POST /acp/orders
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    STATESET SYNC SERVER                             │
│                                                                     │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐            │
│  │  Validate   │───▶│   Route     │───▶│   Track     │            │
│  │   Order     │    │   Order     │    │    Job      │            │
│  └─────────────┘    └─────────────┘    └─────────────┘            │
└─────────────────────────────────────────────────────────────────────┘
                                  │
                ┌─────────────────┼─────────────────┐
                ▼                 ▼                 ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│     STATESET      │ │    FULFILLMENT    │ │       ERP         │
│                   │ │                   │ │                   │
│  • Order Record   │ │  • DCL Warehouse  │ │  • NetSuite       │
│  • Line Items     │ │  • Cart.com       │ │  • Sales Order    │
│  • Status Track   │ │  • Ship to Cust.  │ │  • Revenue Rec.   │
└───────────────────┘ └───────────────────┘ └───────────────────┘
```

## Why ACP?

**Traditional e-commerce** requires customers to navigate websites, add items to carts, and go through checkout flows.

**Agent Commerce** allows AI assistants to handle the entire purchase flow conversationally:

* "I'd like to order 2 blue widgets shipped to my office"
* The AI collects details, confirms the order, and places it via ACP
* The order is fulfilled and tracked automatically

This enables:

* **Conversational Commerce** - Order via ChatGPT, Claude, Alexa, etc.
* **Automated Purchasing** - Agents that reorder supplies automatically
* **B2B Order Entry** - Sales reps using AI to place orders
* **Multi-channel Unification** - Single API for all agent-based ordering

***

## Quick Start

### 1. 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
      }
    ]
  }'
```

### 2. Response

```json theme={null}
{
  "data": {
    "accepted": true,
    "statesetOrderId": "550e8400-e29b-41d4-a716-446655440000",
    "fulfillment": {
      "provider": "dcl",
      "success": true,
      "externalId": "ORD-1001"
    },
    "erp": {
      "provider": "netsuite",
      "success": true,
      "netsuiteId": "12345",
      "tranId": "SO-12345"
    },
    "warnings": [],
    "requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
  },
  "meta": {
    "requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}
```

***

## API Reference

### 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

Include your API key in the Authorization header:

```
Authorization: Bearer your-api-key-here
```

Or use the `X-API-Key` header:

```
X-API-Key: your-api-key-here
```

***

## Request Schema

### 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

Control where the order is sent:

| 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 |

***

## Routing Options

### Full Integration (Default)

Order flows to all configured systems:

```json theme={null}
{
  "routing": {
    "sendToFulfillment": true,
    "sendToErp": true,
    "createInStateset": true
  }
}
```

### Fulfillment Only

Skip ERP, just fulfill the order:

```json theme={null}
{
  "routing": {
    "sendToFulfillment": true,
    "sendToErp": false,
    "createInStateset": true
  }
}
```

### Record Only

Just create the record, don't fulfill yet:

```json theme={null}
{
  "routing": {
    "sendToFulfillment": false,
    "sendToErp": false,
    "createInStateset": true
  }
}
```

### Specific Fulfillment Provider

Force a specific fulfillment provider:

```json theme={null}
{
  "routing": {
    "fulfillmentProvider": "dcl",
    "dclLocation": "LA"
  }
}
```

***

## Async Processing

For high-volume or time-sensitive responses, use async processing:

### Submit 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" }
    }
  }
}
```

***

## Batch Processing

Process up to 100 orders in a single request:

```bash theme={null}
curl -X POST https://your-server.com/v1/tenants/{tenant_id}/acp/orders/batch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "orders": [
      { "orderId": "order-001", "orderNumber": "ORD-001", ... },
      { "orderId": "order-002", "orderNumber": "ORD-002", ... },
      { "orderId": "order-003", "orderNumber": "ORD-003", ... }
    ]
  }'
```

### Response

```json theme={null}
{
  "data": {
    "jobId": "550e8400-e29b-41d4-a716-446655440000",
    "status": "queued",
    "message": "Batch of 3 orders accepted for processing"
  }
}
```

### Batch Result

```json theme={null}
{
  "total": 3,
  "processed": 3,
  "succeeded": 2,
  "failed": 1,
  "results": [
    { "orderId": "order-001", "success": true, "statesetOrderId": "..." },
    { "orderId": "order-002", "success": true, "statesetOrderId": "..." },
    { "orderId": "order-003", "success": false, "fulfillment": { "error": "..." } }
  ]
}
```

***

## Integration Examples

### ChatGPT Function Calling

Define this function for ChatGPT to place orders:

```json theme={null}
{
  "name": "place_order",
  "description": "Place an order for products",
  "parameters": {
    "type": "object",
    "properties": {
      "customerEmail": { "type": "string" },
      "customerFirstName": { "type": "string" },
      "customerLastName": { "type": "string" },
      "shippingAddress": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "address1": { "type": "string" },
          "city": { "type": "string" },
          "state": { "type": "string" },
          "postalCode": { "type": "string" },
          "countryCode": { "type": "string" }
        }
      },
      "items": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "sku": { "type": "string" },
            "title": { "type": "string" },
            "quantity": { "type": "number" },
            "price": { "type": "number" }
          }
        }
      }
    },
    "required": ["customerEmail", "customerFirstName", "customerLastName", "shippingAddress", "items"]
  }
}
```

### Python Integration

```python theme={null}
import requests
import uuid

def place_acp_order(tenant_id: str, api_key: str, order_data: dict) -> dict:
    """Place an order via the ACP endpoint."""

    url = f"https://your-server.com/v1/tenants/{tenant_id}/acp/orders"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    # Ensure order has an ID
    if "orderId" not in order_data:
        order_data["orderId"] = f"agent-{uuid.uuid4()}"

    response = requests.post(url, json=order_data, headers=headers)
    response.raise_for_status()

    return response.json()


# Example usage
order = {
    "orderNumber": "ORD-1001",
    "customer": {
        "email": "customer@example.com",
        "firstName": "John",
        "lastName": "Doe"
    },
    "shippingAddress": {
        "name": "John Doe",
        "address1": "123 Main St",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "94102",
        "countryCode": "US"
    },
    "lineItems": [
        {"sku": "WIDGET-001", "title": "Blue Widget", "quantity": 2, "price": 29.99}
    ]
}

result = place_acp_order("my-tenant", "my-api-key", order)
print(f"Order accepted: {result['data']['accepted']}")
print(f"NetSuite ID: {result['data']['erp']['netsuiteId']}")
```

### Node.js Integration

```javascript theme={null}
const axios = require('axios');
const { v4: uuidv4 } = require('uuid');

async function placeAcpOrder(tenantId, apiKey, orderData) {
  const url = `https://your-server.com/v1/tenants/${tenantId}/acp/orders`;

  // Ensure order has an ID
  if (!orderData.orderId) {
    orderData.orderId = `agent-${uuidv4()}`;
  }

  const response = await axios.post(url, orderData, {
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    }
  });

  return response.data;
}

// Example usage
const order = {
  orderNumber: 'ORD-1001',
  customer: {
    email: 'customer@example.com',
    firstName: 'John',
    lastName: 'Doe'
  },
  shippingAddress: {
    name: 'John Doe',
    address1: '123 Main St',
    city: 'San Francisco',
    state: 'CA',
    postalCode: '94102',
    countryCode: 'US'
  },
  lineItems: [
    { sku: 'WIDGET-001', title: 'Blue Widget', quantity: 2, price: 29.99 }
  ]
};

placeAcpOrder('my-tenant', 'my-api-key', order)
  .then(result => {
    console.log('Order accepted:', result.data.accepted);
    console.log('NetSuite ID:', result.data.erp.netsuiteId);
  });
```

***

## Error Handling

### Validation Errors (422)

```json theme={null}
{
  "error": {
    "code": "validation_error",
    "message": "lineItems[0].sku is required; shippingAddress missing required fields: postalCode",
    "requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
  }
}
```

### Integration Not Configured (424)

```json theme={null}
{
  "error": {
    "code": "integration_not_configured",
    "message": "DCL integration not configured for this tenant",
    "requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
  }
}
```

### Partial Success (207)

When some integrations succeed but others fail:

```json theme={null}
{
  "data": {
    "accepted": false,
    "statesetOrderId": "550e8400-e29b-41d4-a716-446655440000",
    "fulfillment": {
      "provider": "dcl",
      "success": true
    },
    "erp": {
      "provider": "netsuite",
      "success": false,
      "error": "NetSuite API timeout"
    },
    "warnings": ["ERP submission failed but order was fulfilled"]
  }
}
```

***

## Configuration

### Tenant Configuration

Ensure your tenant has the required integrations configured in `app_config.json`:

```json theme={null}
{
  "tenants": [
    {
      "id": "my-tenant",
      "displayName": "My Store",
      "auth": {
        "apiKeys": ["your-api-key"]
      },
      "stateset": {
        "graphqlUrl": "https://your-hasura.com/v1/graphql",
        "adminSecret": "your-admin-secret"
      },
      "dcl": {
        "apiUrl": "https://api.dclcorp.com",
        "username": "dcl-user",
        "password": "dcl-pass",
        "accountNumber": "12345",
        "defaultLocation": "LA"
      },
      "netsuite": {
        "domain": "123456.suitetalk.api.netsuite.com",
        "consumerKey": "...",
        "consumerSecret": "...",
        "tokenKey": "...",
        "tokenSecret": "...",
        "defaultCustomerId": "14",
        "defaultSubsidiaryId": "1"
      }
    }
  ]
}
```

### Environment Variables

Sensitive values can be stored as environment variables:

```bash theme={null}
MY_TENANT_DCL_PASSWORD=dcl-password
MY_TENANT_NETSUITE_CONSUMER_SECRET=netsuite-secret
MY_TENANT_NETSUITE_TOKEN_SECRET=token-secret
```

***

## Best Practices

### 1. Use Idempotent Order IDs

Always provide a unique, deterministic `orderId` to prevent duplicate orders:

```json theme={null}
{
  "orderId": "chatgpt-session-abc123-order-1"
}
```

### 2. Validate Before Submitting

Have your AI agent confirm order details with the customer before calling ACP.

### 3. Handle Partial Failures

Check both `fulfillment.success` and `erp.success` in responses. An order might be fulfilled even if ERP entry fails.

### 4. Use Async for High Volume

For bulk imports or high-traffic scenarios, use `/acp/orders/async` or `/acp/orders/batch`.

### 5. Include Customer NetSuite ID

If you know the customer's NetSuite ID, include it to ensure proper customer linking:

```json theme={null}
{
  "customer": {
    "email": "customer@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "netsuiteId": "12345"
  }
}
```

### 6. Map SKUs to NetSuite Items

For fastest NetSuite processing, include NetSuite item IDs:

```json theme={null}
{
  "lineItems": [
    {
      "sku": "WIDGET-001",
      "title": "Blue Widget",
      "quantity": 2,
      "price": 29.99,
      "netsuiteItemId": "5678"
    }
  ]
}
```

***

## Glossary

| Term         | Description                                                          |
| ------------ | -------------------------------------------------------------------- |
| **ACP**      | Agent Commerce Protocol - API for AI agents to place orders          |
| **DCL**      | Distributed Commerce Logistics - 3PL fulfillment provider            |
| **ERP**      | Enterprise Resource Planning - Business management system (NetSuite) |
| **StateSet** | Order management and tracking system                                 |
| **Tenant**   | A configured merchant/store in the multi-tenant system               |

***

## Support

For issues or questions:

* GitHub Issues: [https://github.com/stateset/stateset-sync-server/issues](https://github.com/stateset/stateset-sync-server/issues)
* Documentation: [https://docs.stateset.com](https://docs.stateset.com)
