# Shop Developer API Documentation v1.0

Comprehensive API reference for integrating ERPs, storefronts, and third-party systems with the WACM Shop Module.

**Base URL:** `/api/v1/shop/`

---

## Authentication

API requests require a **Bearer Token** passed in the HTTP header:

```
Authorization: Bearer YOUR_API_TOKEN
```

There are two types of tokens:

| Token Type | Used For | Where to Find |
|---|---|---|
| **ERP Token** | `POST /api/shop/erp/sync` | Shop > Integrations > ERP / Custom API |
| **Sanctum Token** | All `/api/v1/shop/*` endpoints | Settings > API Tokens |

---

## Quick Start

1. **Obtain Your Token** - ERP Token (bulk sync) or Sanctum Token (REST API)
2. **Push Categories** - `POST /api/v1/shop/categories` — save the returned `id` values
3. **Push Products** - `POST /api/shop/erp/sync` for bulk, or `POST /api/v1/shop/products` for single
4. **Process Orders** - Poll `GET /api/v1/shop/orders` or use incoming webhooks
5. **Update Statuses** - `PUT /api/v1/shop/orders/{id}` with the new status

---

## Products

### GET /api/v1/shop/products

Returns all products for the authenticated company.

```json
{
  "data": [
    {
      "id": 105,
      "name": "Summer Dress",
      "description": "...",
      "price": "49.99",
      "compare_at_price": null,
      "currency": "INR",
      "stock_quantity": 50,
      "status": "Active",
      "image": "https://...",
      "category_id": 3,
      "external_id": "SKU-001",
      "external_source": "erp",
      "created_at": "2024-01-01T00:00:00Z"
    }
  ]
}
```

### POST /api/v1/shop/products

Create a new product.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | String | **Yes** | Product name (max 255 chars). |
| `price` | Number | **Yes** | Selling price (min: 0). |
| `description` | String | No | Full product description. |
| `compare_at_price` | Number | No | Original/strikethrough price. |
| `currency` | String | No | 3-letter currency code (e.g., INR, USD). |
| `stock_quantity` | Integer | No | Available inventory count. |
| `status` | String | No | One of: Active, Draft, Archived. Default: Active. |
| `external_id` | String | No | Your system's product ID. |
| `image` | URL | No | Product image URL. |
| `shop_category_id` | Integer | No | ID of the category to assign. |

### PUT /api/v1/shop/products/{id}

Update an existing product. Same fields as POST (all optional on update).

### DELETE /api/v1/shop/products/{id}

Delete a product. Returns `204 No Content` on success.

---

## Categories

### GET /api/v1/shop/categories

Returns all product categories for the authenticated company.

### POST /api/v1/shop/categories

Create a new category.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | String | **Yes** | Category name (max 255 chars). |
| `slug` | String | **Yes** | URL-friendly identifier (max 255 chars). |
| `description` | String | No | Category description. |
| `image` | URL | No | Category image URL. |

### PUT /api/v1/shop/categories/{id}

Update an existing category.

### DELETE /api/v1/shop/categories/{id}

Delete a category. Returns `204 No Content` on success.

---

## Orders

### GET /api/v1/shop/orders

Returns all orders for the authenticated company. Each order includes nested contact data.

### GET /api/v1/shop/orders/{id}

Returns a specific order by ID.

### PUT /api/v1/shop/orders/{id}

Update the status of an order.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `customer_phone` | String | **No** | Required if email is not provided |
| `status` | String | **Yes** | One of: Pending, Processing, Shipped, Fulfilled, Delivered, Cancelled, Refunded. |
| `items` | Array | **Yes** | Array of order items |

**Response:**

```json
{
  "data": {
    "id": 42,
    "order_number": "ORD-ABC123",
    "status": "Shipped",
    "total_amount": "99.99",
    "currency": "INR",
    "customer_name": "John Doe",
    "customer_phone": "1234567890",
    "tracking_number": "TRACK001",
    "tracking_url": "https://track.example.com/TRACK001"
  }
}
```

---

## ERP Bulk Sync

### POST /api/shop/erp/sync

Bulk-sync products from your ERP in a single request. Uses the **ERP Token** (not a Sanctum token).

**Token Location:** Find your ERP Token in **Shop > Integrations > ERP / Custom API** tab.

**Headers:**

```
Authorization: Bearer YOUR_ERP_TOKEN
Content-Type: application/json
```

**Request Body:**

```json
{
  "products": [
    {
      "external_id": "SKU-1001",
      "name": "Summer T-Shirt",
      "description": "100% cotton blue shirt",
      "price": 19.99,
      "compare_at_price": 25.00,
      "stock_quantity": 50,
      "status": "Active",
      "image": "https://example.com/shirt.jpg"
    }
  ]
}
```

| Field | Required | Description |
|---|---|---|
| `external_id` | **Yes** | Unique ID from your ERP system. |
| `name` | **Yes** | Product name. |
| `description` | No | Product description. |
| `price` | No | Selling price. |
| `compare_at_price` | No | Original/strikethrough price. |
| `stock_quantity` | No | Available inventory. |
| `status` | No | One of: Active, Draft, Archived. Default: Active. |
| `image` | No | Product image URL. |

**Response:**

```json
{
  "success": true,
  "message": "Successfully synced 2 products."
}
```

Products synced via this endpoint are marked with `external_source: "erp"`. If a product with the same `external_id` already exists, it will be updated rather than duplicated.

---

## Incoming Webhooks (ERP)

### POST /api/shop/webhooks/custom/{token}

Receive real-time order events from third-party systems (Zapier, Make, custom ERPs). The ERP Token is used as the webhook token.

**New Order Event:**

```json
{
  "event": "order.placed",
  "data": {
    "order_number": "EXT-100",
    "customer_name": "John Doe",
    "customer_phone": "1234567890",
    "customer_email": "john@example.com",
    "total_amount": 45.00,
    "currency": "USD",
    "items": [
      { "name": "Item 1", "quantity": 1, "price": 45.00 }
    ]
  }
}
```

**Status Update Event:**

```json
{
  "event": "order.status_updated",
  "data": {
    "order_number": "EXT-100",
    "status": "Shipped",
    "tracking_url": "https://track.example.com/123",
    "tracking_number": "123"
  }
}
```

---

## Shopify Integration

WACM integrates with Shopify via the **Admin GraphQL API** and **webhooks**. Configure in **Shop > Integrations > Shopify**.

**Webhook Endpoint:** `/api/shop/webhooks/shopify/{webhook_token}`

The webhook token is auto-generated per company. Find it in **Shop > Integrations > Shopify**.

### Authentication Methods

WACM supports two authentication methods:

#### Method 1: Client Credentials (Recommended)

For apps created in the **Shopify Dev Dashboard**. Tokens are automatically refreshed every 24 hours — no manual token management needed.

1. Create an app in the Dev Dashboard or your store's Develop apps section
2. Copy **Client ID** and **Client Secret**
3. Configure required API scopes: `read_products, read_orders, write_orders, read_fulfillments, read_customers, read_checkouts, write_checkouts`
4. Enter credentials in WACM - tokens refresh automatically

#### Method 2: Legacy Static Token

For **existing admin-created custom apps** with a static `shpat_` token. No longer available for new apps.

> **Note:** You can no longer create new custom apps in Shopify Admin. If you have an existing admin-created custom app with an `shpat_` token, you can use it here.

> **Why did this change?** Shopify deprecated static tokens for Dev Dashboard apps on January 1, 2026. All new apps now use short-lived tokens (24 hours) that must be refreshed programmatically. WACM handles this automatically when using Client Credentials.

### Supported Webhooks

| Shopify Event | WACM Action |
|---|---|
| `products/create` | Create/update product |
| `products/update` | Update product |
| `products/delete` | Mark product as Draft |
| `orders/cancelled` | Update order to "Cancelled" |
| `orders/fulfilled` | Update order to "Fulfilled", save tracking |
| `app/uninstalled` | Log uninstall event |
| `checkouts/create` | Trigger abandoned cart Flow |
| `checkouts/update` | Trigger abandoned cart Flow |

### Product Data Mapping

| Shopify Field | WACM Product Field |
|---|---|
| `id` (GID) | `external_id` |
| `title` | `name` |
| `descriptionHtml` | `description` |
| `status` | `status` |
| `vendor` | `vendor` |
| `productType` | `product_type` |
| `variants[0].price` | `price` |
| `variants[0].compareAtPrice` | `compare_at_price` |
| `variants[0].inventoryQuantity` | `stock_quantity` |
| `variants[0].sku` | `sku` |
| `images[0].url` | `image` |

---

## Rate Limits & Best Practices

- The ERP Bulk Sync endpoint accepts up to hundreds of products per request.
- For large ERP catalogs, split into multiple batches of 100-500 products.
- Always handle HTTP 429 (rate limit) responses with exponential backoff.
- Verify webhook HMAC signatures before processing incoming payloads.