{
  "info": {
    "name": "myne Connect Brands API — Starter",
    "_postman_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "description": "Starter requests for the myne Connect Brands API.\n\nDocs: https://docs.myne.network/api/brands/index.html#tag/Authorisation\n\n**Setup**\n1. Import this collection and a companion environment.\n2. Set `client_id` / `client_secret` from **API Credentials**.\n3. Run **Get credential scope** (Basic `/v1/me`) or **Get an access token (this brand)**, then **Get credential scope with Bearer**.\n4. Other-brand authorize is a browser flow; then use **Get an access token (authorization code)** and **Refresh an access token**.\n\nFor the full route set, use `myne-connect-brands-api.postman_collection.json`.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "basic",
    "basic": [
      {
        "key": "username",
        "value": "{{client_id}}",
        "type": "string"
      },
      {
        "key": "password",
        "value": "{{client_secret}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://connect.myne.network"
    },
    {
      "key": "brand_id",
      "value": ""
    },
    {
      "key": "client_id",
      "value": ""
    },
    {
      "key": "client_secret",
      "value": ""
    },
    {
      "key": "customer_id",
      "value": ""
    },
    {
      "key": "external_id",
      "value": "crm-contact-1001"
    },
    {
      "key": "location_id",
      "value": ""
    },
    {
      "key": "location_external_id",
      "value": ""
    },
    {
      "key": "product_id",
      "value": ""
    },
    {
      "key": "product_external_id",
      "value": ""
    },
    {
      "key": "promotion_id",
      "value": ""
    },
    {
      "key": "business_id",
      "value": ""
    },
    {
      "key": "transaction_id",
      "value": ""
    },
    {
      "key": "task_id",
      "value": ""
    },
    {
      "key": "group_id",
      "value": ""
    },
    {
      "key": "category_id",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Authorisation",
      "item": [
        {
          "name": "Get credential scope and brand identity",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "me"
              ]
            },
            "description": "Confirm your API Credentials (HTTP Basic **or** Bearer from `POST /v1/token`) and discover `brand_id`, partner-safe brand display settings, **External source**, and—when this brand is in a Head office group—`brand.organisation` (role, Head office parent, sibling venues).\n\nCall this first when wiring a new integration. You do not pass `brand_id` on this path — the credential or access token selects the brand (creating brand for Basic / client_credentials; granted brand for authorization-code tokens).\n\nRead `response.brand.organisation` to understand multi-brand relationships. Paths on other routes stay scoped to `response.brand_id` — see **Brand** and **Organisation (Head office group)** in the glossary.\n\nSend `Authorization: Basic` **or** `Authorization: Bearer` on every request to the `connect.myne.network` `/v1` URL. Do not rely on following redirects for auth.\n\nSee glossary: Brand, Organisation (Head office group), API Credentials, External source.\n\nCollection auth is HTTP Basic. To call the same path with a token, use **Get credential scope with Bearer**."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code !== 200) { return; }",
                  "const json = pm.response.json();",
                  "const brandId = json.response && json.response.brand_id;",
                  "if (brandId != null) { pm.environment.set('brand_id', String(brandId)); }"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 Credential scope plus partner-safe brand display settings. Call the connect.myne.network /v1 URL directly with Authorization (Basic or Bearer) on every request; do not depend on following redirects.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/me",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "me"
                  ]
                },
                "description": "Confirm your API Credentials (HTTP Basic **or** Bearer from `POST /v1/token`) and discover `brand_id`, partner-safe brand display settings, **External source**, and—when this brand is in a Head office group—`brand.organisation` (role, Head office parent, sibling venues).\n\nCall this first when wiring a new integration. You do not pass `brand_id` on this path — the credential or access token selects the brand (creating brand for Basic / client_credentials; granted brand for authorization-code tokens).\n\nRead `response.brand.organisation` to understand multi-brand relationships. Paths on other routes stay scoped to `response.brand_id` — see **Brand** and **Organisation (Head office group)** in the glossary.\n\nSend `Authorization: Basic` **or** `Authorization: Bearer` on every request to the `connect.myne.network` `/v1` URL. Do not rely on following redirects for auth.\n\nSee glossary: Brand, Organisation (Head office group), API Credentials, External source.\n\nCollection auth is HTTP Basic. To call the same path with a token, use **Get credential scope with Bearer**."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Authenticated successfully\",\n  \"response\": {\n    \"brand_id\": 42,\n    \"client_id\": \"myne_api_7f3a2b1c\",\n    \"credential_kind\": \"brand_basic_auth\",\n    \"label\": \"CRM sync\",\n    \"source\": \"crm-sync\",\n    \"brand\": {\n      \"id\": 42,\n      \"name\": \"Harbour Cafe Co\",\n      \"description\": \"Neighbourhood cafe group\",\n      \"website\": \"https://harbour.example.com\",\n      \"industry\": \"hospitality\",\n      \"background_url\": null,\n      \"light_logo_url\": \"https://assets.dev.myne.network/demo/light-logo.png\",\n      \"dark_logo_url\": \"https://assets.dev.myne.network/demo/dark-logo.png\",\n      \"square_logo_url\": \"https://assets.dev.myne.network/demo/square-logo.png\",\n      \"primary_color\": \"#1A1A1A\",\n      \"contrast_color\": \"#FFFFFF\",\n      \"text_color\": \"#1A1A1A\",\n      \"button_color\": \"#C45C26\",\n      \"primary_heading\": \"Welcome back\",\n      \"subheading\": \"Earn rewards every visit\",\n      \"call_to_action\": \"Join now\",\n      \"redirect_url\": \"https://harbour.example.com/account\",\n      \"legal_name\": \"Harbour Cafe Co Pty Ltd\",\n      \"contact_email\": \"hello@harbour.example.com\",\n      \"business_address\": \"1 Harbour St, Sydney NSW 2000\",\n      \"governing_state\": \"NSW\",\n      \"organisation\": {\n        \"id\": 42,\n        \"name\": \"Harbour Group\",\n        \"role\": \"venue\",\n        \"head_office_brand\": {\n          \"id\": 100,\n          \"name\": \"Harbour Head Office\"\n        },\n        \"sibling_brands\": [\n          {\n            \"id\": 101,\n            \"name\": \"Harbour Bondi\"\n          },\n          {\n            \"id\": 102,\n            \"name\": \"Harbour Newtown\"\n          }\n        ]\n      }\n    }\n  }\n}"
            }
          ]
        },
        {
          "name": "Get an access token (authorization code)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "token"
              ]
            },
            "description": "Browser authorize cannot run in Postman. Open `https://app.myne.network/oauth/authorize?client_id={{client_id}}&redirect_uri={{redirect_uri}}&response_type=code&state=YOUR_STATE` (use app.dev on development), Allow as a brand admin, then paste the `code` into `authorization_code`. `redirect_uri` must match a saved API Credentials URL exactly.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"grant_type\": \"authorization_code\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\",\n  \"code\": \"{{authorization_code}}\",\n  \"redirect_uri\": \"{{redirect_uri}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code !== 200) { return; }",
                  "const json = pm.response.json();",
                  "if (json.access_token) { pm.environment.set('access_token', json.access_token); }",
                  "if (json.brand_id != null) { pm.environment.set('brand_id', String(json.brand_id)); }",
                  "if (json.refresh_token) { pm.environment.set('refresh_token', json.refresh_token); }"
                ]
              }
            }
          ],
          "response": []
        },
        {
          "name": "Refresh an access token",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "token"
              ]
            },
            "description": "Only authorization-code installs return a refresh token. The refresh token you send is rotated; other refresh tokens for the same brand stay valid. Saves `access_token`, `refresh_token`, and `brand_id` on HTTP 200.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"grant_type\": \"refresh_token\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\",\n  \"refresh_token\": \"{{refresh_token}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code !== 200) { return; }",
                  "const json = pm.response.json();",
                  "if (json.access_token) { pm.environment.set('access_token', json.access_token); }",
                  "if (json.brand_id != null) { pm.environment.set('brand_id', String(json.brand_id)); }",
                  "if (json.refresh_token) { pm.environment.set('refresh_token', json.refresh_token); }"
                ]
              }
            }
          ],
          "response": []
        },
        {
          "name": "Get credential scope with Bearer",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "me"
              ]
            },
            "description": "Same as Get credential scope, using `access_token` from a token request instead of collection Basic. `response.brand_id` is the creating brand (client_credentials) or the granted brand (authorization_code / refresh).",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{access_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code !== 200) { return; }",
                  "const json = pm.response.json();",
                  "const brandId = json.response && json.response.brand_id;",
                  "if (brandId != null) { pm.environment.set('brand_id', String(brandId)); }"
                ]
              }
            }
          ],
          "response": []
        }
      ]
    },
    {
      "name": "Brand",
      "item": [
        {
          "name": "Get brand bootstrap configuration",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/brand",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "brand"
              ]
            },
            "description": "Load partner-safe brand settings—display name, logos, colours, headings, contact fields, and organisation hierarchy when present.\n\nThis is the same brand object as `response.brand` on `GET …/me`. Use when you need brand config without credential metadata.\n\nWhen the brand is in a Head office group, inspect `organisation.role`, `organisation.head_office_brand`, and `organisation.sibling_brands`. Solo brands return `organisation: null`. Paths stay brand-scoped.\n\nReturns one brand object in `response` as a single-item array. Returns 404 when the brand is not found.\n\nSee glossary: Brand, Organisation (Head office group)."
          },
          "response": [
            {
              "name": "200 Brand bootstrap configuration. response contains exactly one ConnectBrand object.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/brand",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "brand"
                  ]
                },
                "description": "Load partner-safe brand settings—display name, logos, colours, headings, contact fields, and organisation hierarchy when present.\n\nThis is the same brand object as `response.brand` on `GET …/me`. Use when you need brand config without credential metadata.\n\nWhen the brand is in a Head office group, inspect `organisation.role`, `organisation.head_office_brand`, and `organisation.sibling_brands`. Solo brands return `organisation: null`. Paths stay brand-scoped.\n\nReturns one brand object in `response` as a single-item array. Returns 404 when the brand is not found.\n\nSee glossary: Brand, Organisation (Head office group)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Brands fetched successfully\",\n  \"response\": [\n    {\n      \"id\": 42,\n      \"name\": \"Harbour Cafe Co\",\n      \"description\": \"Neighbourhood cafe group\",\n      \"website\": \"https://harbour.example.com\",\n      \"industry\": \"hospitality\",\n      \"background_url\": null,\n      \"light_logo_url\": \"https://assets.dev.myne.network/demo/light-logo.png\",\n      \"dark_logo_url\": \"https://assets.dev.myne.network/demo/dark-logo.png\",\n      \"square_logo_url\": \"https://assets.dev.myne.network/demo/square-logo.png\",\n      \"primary_color\": \"#1A1A1A\",\n      \"contrast_color\": \"#FFFFFF\",\n      \"text_color\": \"#1A1A1A\",\n      \"button_color\": \"#C45C26\",\n      \"primary_heading\": \"Welcome back\",\n      \"subheading\": \"Earn rewards every visit\",\n      \"call_to_action\": \"Join now\",\n      \"redirect_url\": \"https://harbour.example.com/account\",\n      \"legal_name\": \"Harbour Cafe Co Pty Ltd\",\n      \"contact_email\": \"hello@harbour.example.com\",\n      \"business_address\": \"1 Harbour St, Sydney NSW 2000\",\n      \"governing_state\": \"NSW\",\n      \"organisation\": {\n        \"id\": 42,\n        \"name\": \"Harbour Group\",\n        \"role\": \"venue\",\n        \"head_office_brand\": {\n          \"id\": 100,\n          \"name\": \"Harbour Head Office\"\n        },\n        \"sibling_brands\": [\n          {\n            \"id\": 101,\n            \"name\": \"Harbour Bondi\"\n          },\n          {\n            \"id\": 102,\n            \"name\": \"Harbour Newtown\"\n          }\n        ]\n      }\n    }\n  ]\n}"
            },
            {
              "name": "404 Brand not found.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/brand",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "brand"
                  ]
                },
                "description": "Load partner-safe brand settings—display name, logos, colours, headings, contact fields, and organisation hierarchy when present.\n\nThis is the same brand object as `response.brand` on `GET …/me`. Use when you need brand config without credential metadata.\n\nWhen the brand is in a Head office group, inspect `organisation.role`, `organisation.head_office_brand`, and `organisation.sibling_brands`. Solo brands return `organisation: null`. Paths stay brand-scoped.\n\nReturns one brand object in `response` as a single-item array. Returns 404 when the brand is not found.\n\nSee glossary: Brand, Organisation (Head office group)."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Brand not found\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Integrations",
      "item": [
        {
          "name": "List connected integrations for a brand",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/integrations",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "integrations"
              ]
            },
            "description": "Return every app connected to the brand—the same integrations staff see in myne Settings.\n\nEach row includes `id`, `access_name`, `app_name`, `label`, `source`, `category`, and whether it matches your API credentials (`is_self`).\n\nSecrets, OAuth tokens, and raw integration payloads are never included.\n\nSee glossary: External source, API Credentials."
          },
          "response": [
            {
              "name": "200 Connected integrations for the brand. Secrets, OAuth tokens, and raw integration payloads are never included.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/integrations",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "integrations"
                  ]
                },
                "description": "Return every app connected to the brand—the same integrations staff see in myne Settings.\n\nEach row includes `id`, `access_name`, `app_name`, `label`, `source`, `category`, and whether it matches your API credentials (`is_self`).\n\nSecrets, OAuth tokens, and raw integration payloads are never included.\n\nSee glossary: External source, API Credentials."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Integrations fetched successfully\",\n  \"response\": [\n    {\n      \"id\": 42,\n      \"access_name\": \"monday\",\n      \"app_name\": \"monday\",\n      \"label\": \"Monday CRM\",\n      \"source\": \"monday-crm\",\n      \"state\": \"connected\",\n      \"category\": \"crm\",\n      \"is_self\": false\n    },\n    {\n      \"id\": 99,\n      \"access_name\": \"myne_api_abc123\",\n      \"app_name\": \"myne_api_abc123\",\n      \"label\": \"Partner sync\",\n      \"source\": \"partner-sync\",\n      \"state\": \"connected\",\n      \"category\": \"custom\",\n      \"is_self\": true\n    }\n  ]\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Location",
      "item": [
        {
          "name": "List locations for a brand",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "locations"
              ],
              "query": [
                {
                  "key": "updated_since",
                  "value": "",
                  "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Return every venue for the brand—the same rows staff see in myne.\n\nUse location IDs in customer browse filters, sync payloads, and promotion scoping.\n\nSee glossary: Location, Brand."
          },
          "response": [
            {
              "name": "200 All locations for the brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "locations"
                  ],
                  "query": [
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Return every venue for the brand—the same rows staff see in myne.\n\nUse location IDs in customer browse filters, sync payloads, and promotion scoping.\n\nSee glossary: Location, Brand."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Locations fetched successfully\",\n  \"response\": [\n    {\n      \"id\": 3,\n      \"brand_id\": 42,\n      \"name\": \"Harbour Cafe — Circular Quay\",\n      \"phone\": \"+61291234567\",\n      \"address\": \"1 Alfred St, Sydney NSW 2000\",\n      \"uuid\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n      \"valid\": true,\n      \"new_check_in_enabled\": true\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Get a location by id",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations/{{location_id}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "locations",
                "{{location_id}}"
              ]
            },
            "description": "Load one venue by `location_id` for the brand.\n\nReturns partner-safe fields such as name, phone, address, uuid, valid, and `new_check_in_enabled`.\n\nUse after listing locations or when resolving a venue from sync payloads. Returns 404 when the ID is not in this brand.\n\nSee glossary: Location."
          },
          "response": [
            {
              "name": "200 Single venue for the brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations/{{location_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "locations",
                    "{{location_id}}"
                  ]
                },
                "description": "Load one venue by `location_id` for the brand.\n\nReturns partner-safe fields such as name, phone, address, uuid, valid, and `new_check_in_enabled`.\n\nUse after listing locations or when resolving a venue from sync payloads. Returns 404 when the ID is not in this brand.\n\nSee glossary: Location."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Location fetched successfully\",\n  \"response\": {\n    \"id\": 3,\n    \"brand_id\": 42,\n    \"name\": \"Harbour Cafe — Circular Quay\",\n    \"phone\": \"+61291234567\",\n    \"address\": \"1 Alfred St, Sydney NSW 2000\",\n    \"uuid\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n    \"valid\": true,\n    \"new_check_in_enabled\": true\n  }\n}"
            },
            {
              "name": "400 Invalid brand_id or location_id.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations/{{location_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "locations",
                    "{{location_id}}"
                  ]
                },
                "description": "Load one venue by `location_id` for the brand.\n\nReturns partner-safe fields such as name, phone, address, uuid, valid, and `new_check_in_enabled`.\n\nUse after listing locations or when resolving a venue from sync payloads. Returns 404 when the ID is not in this brand.\n\nSee glossary: Location."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id or location_id\"\n}"
            },
            {
              "name": "404 Location not found.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations/{{location_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "locations",
                    "{{location_id}}"
                  ]
                },
                "description": "Load one venue by `location_id` for the brand.\n\nReturns partner-safe fields such as name, phone, address, uuid, valid, and `new_check_in_enabled`.\n\nUse after listing locations or when resolving a venue from sync payloads. Returns 404 when the ID is not in this brand.\n\nSee glossary: Location."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Location not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/locations/{{location_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "locations",
                    "{{location_id}}"
                  ]
                },
                "description": "Load one venue by `location_id` for the brand.\n\nReturns partner-safe fields such as name, phone, address, uuid, valid, and `new_check_in_enabled`.\n\nUse after listing locations or when resolving a venue from sync payloads. Returns 404 when the ID is not in this brand.\n\nSee glossary: Location."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Customer",
      "item": [
        {
          "name": "Get a customer by external id",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "by-external-id"
              ],
              "query": [
                {
                  "key": "external_id",
                  "value": "{{external_id}}",
                  "description": "Your integration's identifier for the customer.",
                  "disabled": false
                },
                {
                  "key": "source",
                  "value": "",
                  "description": "Origin system for the external_id. When omitted, defaults to your Custom API app name (Integrations label). Read-only filter for cross-integration lookups.",
                  "disabled": true
                }
              ]
            },
            "description": "Resolve a myne customer from your CRM or PMS `external_id` without scanning browse results.\n\nWhen `source` is omitted, lookup uses your Custom API app name (the label shown in Integrations)—the same source stamped when you synced or upserted the contact. Pass `source` explicitly only when you need IDs synced under another integration.\n\nReturns the customer with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime stats, and loyalty join status (`connection_type` — `connected` when the customer has joined loyalty, `known` when not, `unknown` for an anonymous website visitor), or 404 when no match exists for this brand. `connection_type` matches the customer list and the get-customer-by-id endpoint. Identities are not a single top-level source/external_id. Cashback here is the internal cashback ledger, not a live Wrapped or Giftit credit GET.\n\nEvaluate/apply use this same external_id path when you omit `customer_id`, but they do not load identities or loyalty.\n\nSee glossary: Customer, external_id and external_data, External source, Credit, Points."
          },
          "response": [
            {
              "name": "200 Customer, connected-system identities, loyalty balances, and lifetime stats.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Your integration's identifier for the customer.",
                      "disabled": false
                    },
                    {
                      "key": "source",
                      "value": "",
                      "description": "Origin system for the external_id. When omitted, defaults to your Custom API app name (Integrations label). Read-only filter for cross-integration lookups.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Resolve a myne customer from your CRM or PMS `external_id` without scanning browse results.\n\nWhen `source` is omitted, lookup uses your Custom API app name (the label shown in Integrations)—the same source stamped when you synced or upserted the contact. Pass `source` explicitly only when you need IDs synced under another integration.\n\nReturns the customer with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime stats, and loyalty join status (`connection_type` — `connected` when the customer has joined loyalty, `known` when not, `unknown` for an anonymous website visitor), or 404 when no match exists for this brand. `connection_type` matches the customer list and the get-customer-by-id endpoint. Identities are not a single top-level source/external_id. Cashback here is the internal cashback ledger, not a live Wrapped or Giftit credit GET.\n\nEvaluate/apply use this same external_id path when you omit `customer_id`, but they do not load identities or loyalty.\n\nSee glossary: Customer, external_id and external_data, External source, Credit, Points."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer fetched successfully\",\n  \"response\": {\n    \"customer\": {\n      \"id\": 104823,\n      \"brand_id\": 42,\n      \"location_id\": 3,\n      \"phone\": \"+61412345678\",\n      \"email\": \"jordan.lee@example.com\",\n      \"created_at\": \"2025-02-15T01:23:45.000Z\",\n      \"updated_at\": \"2026-06-21T03:15:00.000Z\",\n      \"accepts_marketing\": true,\n      \"first_name\": \"Jordan\",\n      \"last_name\": \"Lee\",\n      \"archived_at\": null,\n      \"frequency\": \"Frequent\",\n      \"engagement\": \"engaged\",\n      \"connection_type\": \"connected\",\n      \"pass_id\": \"ABC123XYZ\",\n      \"points\": 120,\n      \"cashback\": 18.5\n    },\n    \"stats\": {\n      \"transaction_count\": 17,\n      \"total_spent\": 542.5,\n      \"last_transaction_date\": \"2026-06-21T03:15:00.000Z\"\n    },\n    \"extended\": [\n      {\n        \"source\": \"lightspeed\",\n        \"external_id\": \"ext-abc123\",\n        \"json_data\": {\n          \"pos_id\": \"LS-98765\"\n        },\n        \"updated_at\": \"2026-06-21T03:15:00.000Z\"\n      },\n      {\n        \"source\": \"monday-crm\",\n        \"external_id\": \"crm-001\",\n        \"json_data\": {},\n        \"updated_at\": \"2026-05-01T00:00:00.000Z\"\n      }\n    ]\n  }\n}"
            },
            {
              "name": "400 external_id query parameter is missing.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Your integration's identifier for the customer.",
                      "disabled": false
                    },
                    {
                      "key": "source",
                      "value": "",
                      "description": "Origin system for the external_id. When omitted, defaults to your Custom API app name (Integrations label). Read-only filter for cross-integration lookups.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Resolve a myne customer from your CRM or PMS `external_id` without scanning browse results.\n\nWhen `source` is omitted, lookup uses your Custom API app name (the label shown in Integrations)—the same source stamped when you synced or upserted the contact. Pass `source` explicitly only when you need IDs synced under another integration.\n\nReturns the customer with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime stats, and loyalty join status (`connection_type` — `connected` when the customer has joined loyalty, `known` when not, `unknown` for an anonymous website visitor), or 404 when no match exists for this brand. `connection_type` matches the customer list and the get-customer-by-id endpoint. Identities are not a single top-level source/external_id. Cashback here is the internal cashback ledger, not a live Wrapped or Giftit credit GET.\n\nEvaluate/apply use this same external_id path when you omit `customer_id`, but they do not load identities or loyalty.\n\nSee glossary: Customer, external_id and external_data, External source, Credit, Points."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"external_id query parameter is required\"\n}"
            },
            {
              "name": "404 No customer matches the external id for this brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Your integration's identifier for the customer.",
                      "disabled": false
                    },
                    {
                      "key": "source",
                      "value": "",
                      "description": "Origin system for the external_id. When omitted, defaults to your Custom API app name (Integrations label). Read-only filter for cross-integration lookups.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Resolve a myne customer from your CRM or PMS `external_id` without scanning browse results.\n\nWhen `source` is omitted, lookup uses your Custom API app name (the label shown in Integrations)—the same source stamped when you synced or upserted the contact. Pass `source` explicitly only when you need IDs synced under another integration.\n\nReturns the customer with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime stats, and loyalty join status (`connection_type` — `connected` when the customer has joined loyalty, `known` when not, `unknown` for an anonymous website visitor), or 404 when no match exists for this brand. `connection_type` matches the customer list and the get-customer-by-id endpoint. Identities are not a single top-level source/external_id. Cashback here is the internal cashback ledger, not a live Wrapped or Giftit credit GET.\n\nEvaluate/apply use this same external_id path when you omit `customer_id`, but they do not load identities or loyalty.\n\nSee glossary: Customer, external_id and external_data, External source, Credit, Points."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            }
          ]
        },
        {
          "name": "Upsert extended customer data by external id",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/extended",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "by-external-id",
                "extended"
              ]
            },
            "description": "Merge JSON extended fields for a customer identified by `external_id`.\n\nUse this when you want partner metadata or alternate source ids stored under your Custom API app without relying only on top-level email/phone/name. Data is stored under your app source only—do not send `source` in the body.\n\nIf no customer exists for that `external_id` yet, one is created. You may optionally pass email, phone, first_name, and last_name on create.\n\nSee glossary: Customer, Extended profile, External source, external_id and external_data.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"data\": {\n    \"preferred_venue\": \"Sydney CBD\",\n    \"notes\": \"VIP\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Extended data merged for the customer under your API app source. Creates the customer when missing.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "extended"
                  ]
                },
                "description": "Merge JSON extended fields for a customer identified by `external_id`.\n\nUse this when you want partner metadata or alternate source ids stored under your Custom API app without relying only on top-level email/phone/name. Data is stored under your app source only—do not send `source` in the body.\n\nIf no customer exists for that `external_id` yet, one is created. You may optionally pass email, phone, first_name, and last_name on create.\n\nSee glossary: Customer, Extended profile, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"data\": {\n    \"preferred_venue\": \"Sydney CBD\",\n    \"notes\": \"VIP\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer extended data upserted successfully\",\n  \"response\": {\n    \"customer_id\": 104823,\n    \"external_id\": \"crm-001\",\n    \"source\": \"monday-crm\",\n    \"created_customer\": true\n  }\n}"
            },
            {
              "name": "400 Invalid JSON body or missing external_id/data.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "extended"
                  ]
                },
                "description": "Merge JSON extended fields for a customer identified by `external_id`.\n\nUse this when you want partner metadata or alternate source ids stored under your Custom API app without relying only on top-level email/phone/name. Data is stored under your app source only—do not send `source` in the body.\n\nIf no customer exists for that `external_id` yet, one is created. You may optionally pass email, phone, first_name, and last_name on create.\n\nSee glossary: Customer, Extended profile, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"data\": {\n    \"preferred_venue\": \"Sydney CBD\",\n    \"notes\": \"VIP\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"data must be a JSON object\"\n}"
            },
            {
              "name": "403 Request included source (or contact_source / business_source)—these are set from your API credentials.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "extended"
                  ]
                },
                "description": "Merge JSON extended fields for a customer identified by `external_id`.\n\nUse this when you want partner metadata or alternate source ids stored under your Custom API app without relying only on top-level email/phone/name. Data is stored under your app source only—do not send `source` in the body.\n\nIf no customer exists for that `external_id` yet, one is created. You may optionally pass email, phone, first_name, and last_name on create.\n\nSee glossary: Customer, Extended profile, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"data\": {\n    \"preferred_venue\": \"Sydney CBD\",\n    \"notes\": \"VIP\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 403,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"source is managed by your API credentials and cannot be set on write requests\"\n}"
            },
            {
              "name": "404 No customer matches the external id for this brand and source.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "extended"
                  ]
                },
                "description": "Merge JSON extended fields for a customer identified by `external_id`.\n\nUse this when you want partner metadata or alternate source ids stored under your Custom API app without relying only on top-level email/phone/name. Data is stored under your app source only—do not send `source` in the body.\n\nIf no customer exists for that `external_id` yet, one is created. You may optionally pass email, phone, first_name, and last_name on create.\n\nSee glossary: Customer, Extended profile, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"data\": {\n    \"preferred_venue\": \"Sydney CBD\",\n    \"notes\": \"VIP\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "extended"
                  ]
                },
                "description": "Merge JSON extended fields for a customer identified by `external_id`.\n\nUse this when you want partner metadata or alternate source ids stored under your Custom API app without relying only on top-level email/phone/name. Data is stored under your app source only—do not send `source` in the body.\n\nIf no customer exists for that `external_id` yet, one is created. You may optionally pass email, phone, first_name, and last_name on create.\n\nSee glossary: Customer, Extended profile, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"data\": {\n    \"preferred_venue\": \"Sydney CBD\",\n    \"notes\": \"VIP\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Upsert a customer by external id",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers"
              ]
            },
            "description": "Create or update a customer from your website, CRM, or PMS using `external_id`.\n\nSend top-level profile fields when you have them (email, phone, name). Source is always your Custom API app—do not send `source`.\n\nSend `connection_type: \"connected\"` when the person is already a loyalty member in your app — myne marks them as joined (requires an email or phone on the request, or one already stored for the customer). Omitting it, or sending `known` / `unknown`, never changes their connection status.\n\nThat `external_id` is what you use later for promotion evaluate/apply and by-external-id lookups under your **External source**. For additional partner ids or opaque metadata, also write extended data (`POST …/customers/by-external-id/extended` or sync `contact_extended`).\n\nPrefer this for single registrations; use **Sync batch** for bulk imports.\n\nSee glossary: Customer, external_id and external_data, Sync batch.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"phone\": \"+61400000000\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"traits\": {\n    \"loyalty_tier\": \"gold\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Customer created or updated under your External source.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ]
                },
                "description": "Create or update a customer from your website, CRM, or PMS using `external_id`.\n\nSend top-level profile fields when you have them (email, phone, name). Source is always your Custom API app—do not send `source`.\n\nSend `connection_type: \"connected\"` when the person is already a loyalty member in your app — myne marks them as joined (requires an email or phone on the request, or one already stored for the customer). Omitting it, or sending `known` / `unknown`, never changes their connection status.\n\nThat `external_id` is what you use later for promotion evaluate/apply and by-external-id lookups under your **External source**. For additional partner ids or opaque metadata, also write extended data (`POST …/customers/by-external-id/extended` or sync `contact_extended`).\n\nPrefer this for single registrations; use **Sync batch** for bulk imports.\n\nSee glossary: Customer, external_id and external_data, Sync batch.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"phone\": \"+61400000000\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"traits\": {\n    \"loyalty_tier\": \"gold\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer upserted successfully\",\n  \"response\": {\n    \"customer_id\": 104823,\n    \"external_id\": \"web-user-001\",\n    \"source\": \"monday-crm\",\n    \"created\": true\n  }\n}"
            },
            {
              "name": "400 Invalid JSON, missing external_id, or connection_type=connected with no resolvable email or phone.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ]
                },
                "description": "Create or update a customer from your website, CRM, or PMS using `external_id`.\n\nSend top-level profile fields when you have them (email, phone, name). Source is always your Custom API app—do not send `source`.\n\nSend `connection_type: \"connected\"` when the person is already a loyalty member in your app — myne marks them as joined (requires an email or phone on the request, or one already stored for the customer). Omitting it, or sending `known` / `unknown`, never changes their connection status.\n\nThat `external_id` is what you use later for promotion evaluate/apply and by-external-id lookups under your **External source**. For additional partner ids or opaque metadata, also write extended data (`POST …/customers/by-external-id/extended` or sync `contact_extended`).\n\nPrefer this for single registrations; use **Sync batch** for bulk imports.\n\nSee glossary: Customer, external_id and external_data, Sync batch.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"phone\": \"+61400000000\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"traits\": {\n    \"loyalty_tier\": \"gold\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"external_id (or user_id) is required\"\n}"
            },
            {
              "name": "403 Request included a source field (not allowed on writes).",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ]
                },
                "description": "Create or update a customer from your website, CRM, or PMS using `external_id`.\n\nSend top-level profile fields when you have them (email, phone, name). Source is always your Custom API app—do not send `source`.\n\nSend `connection_type: \"connected\"` when the person is already a loyalty member in your app — myne marks them as joined (requires an email or phone on the request, or one already stored for the customer). Omitting it, or sending `known` / `unknown`, never changes their connection status.\n\nThat `external_id` is what you use later for promotion evaluate/apply and by-external-id lookups under your **External source**. For additional partner ids or opaque metadata, also write extended data (`POST …/customers/by-external-id/extended` or sync `contact_extended`).\n\nPrefer this for single registrations; use **Sync batch** for bulk imports.\n\nSee glossary: Customer, external_id and external_data, Sync batch.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"phone\": \"+61400000000\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"traits\": {\n    \"loyalty_tier\": \"gold\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 403,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"source is managed by your API credentials and cannot be set on write requests\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ]
                },
                "description": "Create or update a customer from your website, CRM, or PMS using `external_id`.\n\nSend top-level profile fields when you have them (email, phone, name). Source is always your Custom API app—do not send `source`.\n\nSend `connection_type: \"connected\"` when the person is already a loyalty member in your app — myne marks them as joined (requires an email or phone on the request, or one already stored for the customer). Omitting it, or sending `known` / `unknown`, never changes their connection status.\n\nThat `external_id` is what you use later for promotion evaluate/apply and by-external-id lookups under your **External source**. For additional partner ids or opaque metadata, also write extended data (`POST …/customers/by-external-id/extended` or sync `contact_extended`).\n\nPrefer this for single registrations; use **Sync batch** for bulk imports.\n\nSee glossary: Customer, external_id and external_data, Sync batch.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"email\": \"alex@example.com\",\n  \"phone\": \"+61400000000\",\n  \"first_name\": \"Alex\",\n  \"last_name\": \"Nguyen\",\n  \"traits\": {\n    \"loyalty_tier\": \"gold\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Browse customers for a brand",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "15",
                  "description": "Page size. Clamped to 1–100.",
                  "disabled": false
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "Opaque pagination cursor returned as `response.next_cursor` from the previous page. Omit for the first page.",
                  "disabled": true
                },
                {
                  "key": "query",
                  "value": "",
                  "description": "Free-text search across name, email, phone, and wallet/credit identifiers.",
                  "disabled": true
                },
                {
                  "key": "include_visitors",
                  "value": "false",
                  "description": "Accepts `true`, `1`, or `yes`. When truthy, include unidentified visitor records; otherwise only known customers are returned (default).",
                  "disabled": true
                },
                {
                  "key": "sort_by",
                  "value": "total_spent",
                  "description": "Sort key for ranking customers.",
                  "disabled": true
                },
                {
                  "key": "sort_direction",
                  "value": "desc",
                  "description": "Sort direction.",
                  "disabled": true
                },
                {
                  "key": "locations",
                  "value": "",
                  "description": "Comma-separated business/location IDs to restrict the browse to (e.g. `12,34`).",
                  "disabled": true
                },
                {
                  "key": "connection",
                  "value": "",
                  "description": "Filter by connection state.",
                  "disabled": true
                },
                {
                  "key": "frequency",
                  "value": "",
                  "description": "Filter by brand frequency bucket.",
                  "disabled": true
                },
                {
                  "key": "engagement",
                  "value": "",
                  "description": "Filter by engagement classification when available.",
                  "disabled": true
                },
                {
                  "key": "customer_group_id",
                  "value": "",
                  "description": "Restrict browse to members of one customer group.",
                  "disabled": true
                },
                {
                  "key": "search_fields",
                  "value": "",
                  "description": "Comma-separated search field keys to limit free-text `query` matching.",
                  "disabled": true
                },
                {
                  "key": "updated_since",
                  "value": "",
                  "description": "ISO-8601 timestamp. When set, only customers with updated_at on or after this instant are returned (compared in UTC).",
                  "disabled": true
                }
              ]
            },
            "description": "Search and page through customers for a brand. Use `cursor` from `response.next_cursor` for the next page.\n\nFilter by location, **Connection state**, or **Frequency**. Set `include_visitors=true` to include unidentified **Visitor** records.\n\nPass `updated_since` (ISO-8601, compared in UTC) to poll only customers changed on or after that timestamp.\n\nTypical first step before loading a single profile or extended timeline.\n\nSee glossary: Customer, Visitor, Connection state, Frequency, Engagement."
          },
          "response": [
            {
              "name": "200 A page of customers. `response.next_cursor` is null when there are no more pages.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Page size. Clamped to 1–100.",
                      "disabled": false
                    },
                    {
                      "key": "cursor",
                      "value": "",
                      "description": "Opaque pagination cursor returned as `response.next_cursor` from the previous page. Omit for the first page.",
                      "disabled": true
                    },
                    {
                      "key": "query",
                      "value": "",
                      "description": "Free-text search across name, email, phone, and wallet/credit identifiers.",
                      "disabled": true
                    },
                    {
                      "key": "include_visitors",
                      "value": "false",
                      "description": "Accepts `true`, `1`, or `yes`. When truthy, include unidentified visitor records; otherwise only known customers are returned (default).",
                      "disabled": true
                    },
                    {
                      "key": "sort_by",
                      "value": "total_spent",
                      "description": "Sort key for ranking customers.",
                      "disabled": true
                    },
                    {
                      "key": "sort_direction",
                      "value": "desc",
                      "description": "Sort direction.",
                      "disabled": true
                    },
                    {
                      "key": "locations",
                      "value": "",
                      "description": "Comma-separated business/location IDs to restrict the browse to (e.g. `12,34`).",
                      "disabled": true
                    },
                    {
                      "key": "connection",
                      "value": "",
                      "description": "Filter by connection state.",
                      "disabled": true
                    },
                    {
                      "key": "frequency",
                      "value": "",
                      "description": "Filter by brand frequency bucket.",
                      "disabled": true
                    },
                    {
                      "key": "engagement",
                      "value": "",
                      "description": "Filter by engagement classification when available.",
                      "disabled": true
                    },
                    {
                      "key": "customer_group_id",
                      "value": "",
                      "description": "Restrict browse to members of one customer group.",
                      "disabled": true
                    },
                    {
                      "key": "search_fields",
                      "value": "",
                      "description": "Comma-separated search field keys to limit free-text `query` matching.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only customers with updated_at on or after this instant are returned (compared in UTC).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Search and page through customers for a brand. Use `cursor` from `response.next_cursor` for the next page.\n\nFilter by location, **Connection state**, or **Frequency**. Set `include_visitors=true` to include unidentified **Visitor** records.\n\nPass `updated_since` (ISO-8601, compared in UTC) to poll only customers changed on or after that timestamp.\n\nTypical first step before loading a single profile or extended timeline.\n\nSee glossary: Customer, Visitor, Connection state, Frequency, Engagement."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer records fetched successfully (known only)\",\n  \"response\": {\n    \"data\": [\n      {\n        \"id\": 104823,\n        \"external_data\": null,\n        \"first_name\": \"Jordan\",\n        \"last_name\": \"Lee\",\n        \"email\": \"jordan.lee@example.com\",\n        \"phone\": \"+61412345678\",\n        \"location_id\": null,\n        \"brand_id\": 42,\n        \"uuid\": \"c0b1f7a4-2e3d-4f5a-9b6c-7d8e9f0a1b2c\",\n        \"predicted_name\": null,\n        \"type\": \"customer\",\n        \"transaction_count\": 17,\n        \"total_spent\": 542.5,\n        \"tenure\": 412,\n        \"latest_transaction\": \"2026-06-21T03:15:00.000Z\",\n        \"last_seen\": \"2026-06-21T03:15:00.000Z\",\n        \"frequency\": \"Frequent\",\n        \"engagement\": \"engaged\",\n        \"connection_type\": \"connected\"\n      }\n    ],\n    \"has_more\": true,\n    \"next_cursor\": \"1|0|2026-06-21T03:15:00.000Z|104823\",\n    \"total_count\": 1287\n  }\n}"
            },
            {
              "name": "400 brand_id is missing or not a positive integer.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Page size. Clamped to 1–100.",
                      "disabled": false
                    },
                    {
                      "key": "cursor",
                      "value": "",
                      "description": "Opaque pagination cursor returned as `response.next_cursor` from the previous page. Omit for the first page.",
                      "disabled": true
                    },
                    {
                      "key": "query",
                      "value": "",
                      "description": "Free-text search across name, email, phone, and wallet/credit identifiers.",
                      "disabled": true
                    },
                    {
                      "key": "include_visitors",
                      "value": "false",
                      "description": "Accepts `true`, `1`, or `yes`. When truthy, include unidentified visitor records; otherwise only known customers are returned (default).",
                      "disabled": true
                    },
                    {
                      "key": "sort_by",
                      "value": "total_spent",
                      "description": "Sort key for ranking customers.",
                      "disabled": true
                    },
                    {
                      "key": "sort_direction",
                      "value": "desc",
                      "description": "Sort direction.",
                      "disabled": true
                    },
                    {
                      "key": "locations",
                      "value": "",
                      "description": "Comma-separated business/location IDs to restrict the browse to (e.g. `12,34`).",
                      "disabled": true
                    },
                    {
                      "key": "connection",
                      "value": "",
                      "description": "Filter by connection state.",
                      "disabled": true
                    },
                    {
                      "key": "frequency",
                      "value": "",
                      "description": "Filter by brand frequency bucket.",
                      "disabled": true
                    },
                    {
                      "key": "engagement",
                      "value": "",
                      "description": "Filter by engagement classification when available.",
                      "disabled": true
                    },
                    {
                      "key": "customer_group_id",
                      "value": "",
                      "description": "Restrict browse to members of one customer group.",
                      "disabled": true
                    },
                    {
                      "key": "search_fields",
                      "value": "",
                      "description": "Comma-separated search field keys to limit free-text `query` matching.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only customers with updated_at on or after this instant are returned (compared in UTC).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Search and page through customers for a brand. Use `cursor` from `response.next_cursor` for the next page.\n\nFilter by location, **Connection state**, or **Frequency**. Set `include_visitors=true` to include unidentified **Visitor** records.\n\nPass `updated_since` (ISO-8601, compared in UTC) to poll only customers changed on or after that timestamp.\n\nTypical first step before loading a single profile or extended timeline.\n\nSee glossary: Customer, Visitor, Connection state, Frequency, Engagement."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id\"\n}"
            },
            {
              "name": "500 Unexpected server error. Details are logged server-side; the body is a generic message.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Page size. Clamped to 1–100.",
                      "disabled": false
                    },
                    {
                      "key": "cursor",
                      "value": "",
                      "description": "Opaque pagination cursor returned as `response.next_cursor` from the previous page. Omit for the first page.",
                      "disabled": true
                    },
                    {
                      "key": "query",
                      "value": "",
                      "description": "Free-text search across name, email, phone, and wallet/credit identifiers.",
                      "disabled": true
                    },
                    {
                      "key": "include_visitors",
                      "value": "false",
                      "description": "Accepts `true`, `1`, or `yes`. When truthy, include unidentified visitor records; otherwise only known customers are returned (default).",
                      "disabled": true
                    },
                    {
                      "key": "sort_by",
                      "value": "total_spent",
                      "description": "Sort key for ranking customers.",
                      "disabled": true
                    },
                    {
                      "key": "sort_direction",
                      "value": "desc",
                      "description": "Sort direction.",
                      "disabled": true
                    },
                    {
                      "key": "locations",
                      "value": "",
                      "description": "Comma-separated business/location IDs to restrict the browse to (e.g. `12,34`).",
                      "disabled": true
                    },
                    {
                      "key": "connection",
                      "value": "",
                      "description": "Filter by connection state.",
                      "disabled": true
                    },
                    {
                      "key": "frequency",
                      "value": "",
                      "description": "Filter by brand frequency bucket.",
                      "disabled": true
                    },
                    {
                      "key": "engagement",
                      "value": "",
                      "description": "Filter by engagement classification when available.",
                      "disabled": true
                    },
                    {
                      "key": "customer_group_id",
                      "value": "",
                      "description": "Restrict browse to members of one customer group.",
                      "disabled": true
                    },
                    {
                      "key": "search_fields",
                      "value": "",
                      "description": "Comma-separated search field keys to limit free-text `query` matching.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only customers with updated_at on or after this instant are returned (compared in UTC).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Search and page through customers for a brand. Use `cursor` from `response.next_cursor` for the next page.\n\nFilter by location, **Connection state**, or **Frequency**. Set `include_visitors=true` to include unidentified **Visitor** records.\n\nPass `updated_since` (ISO-8601, compared in UTC) to poll only customers changed on or after that timestamp.\n\nTypical first step before loading a single profile or extended timeline.\n\nSee glossary: Customer, Visitor, Connection state, Frequency, Engagement."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            },
            {
              "name": "503 The underlying browse query timed out. Narrow the search (e.g. add `query`, `locations`, or reduce `limit`) and retry.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Page size. Clamped to 1–100.",
                      "disabled": false
                    },
                    {
                      "key": "cursor",
                      "value": "",
                      "description": "Opaque pagination cursor returned as `response.next_cursor` from the previous page. Omit for the first page.",
                      "disabled": true
                    },
                    {
                      "key": "query",
                      "value": "",
                      "description": "Free-text search across name, email, phone, and wallet/credit identifiers.",
                      "disabled": true
                    },
                    {
                      "key": "include_visitors",
                      "value": "false",
                      "description": "Accepts `true`, `1`, or `yes`. When truthy, include unidentified visitor records; otherwise only known customers are returned (default).",
                      "disabled": true
                    },
                    {
                      "key": "sort_by",
                      "value": "total_spent",
                      "description": "Sort key for ranking customers.",
                      "disabled": true
                    },
                    {
                      "key": "sort_direction",
                      "value": "desc",
                      "description": "Sort direction.",
                      "disabled": true
                    },
                    {
                      "key": "locations",
                      "value": "",
                      "description": "Comma-separated business/location IDs to restrict the browse to (e.g. `12,34`).",
                      "disabled": true
                    },
                    {
                      "key": "connection",
                      "value": "",
                      "description": "Filter by connection state.",
                      "disabled": true
                    },
                    {
                      "key": "frequency",
                      "value": "",
                      "description": "Filter by brand frequency bucket.",
                      "disabled": true
                    },
                    {
                      "key": "engagement",
                      "value": "",
                      "description": "Filter by engagement classification when available.",
                      "disabled": true
                    },
                    {
                      "key": "customer_group_id",
                      "value": "",
                      "description": "Restrict browse to members of one customer group.",
                      "disabled": true
                    },
                    {
                      "key": "search_fields",
                      "value": "",
                      "description": "Comma-separated search field keys to limit free-text `query` matching.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only customers with updated_at on or after this instant are returned (compared in UTC).",
                      "disabled": true
                    }
                  ]
                },
                "description": "Search and page through customers for a brand. Use `cursor` from `response.next_cursor` for the next page.\n\nFilter by location, **Connection state**, or **Frequency**. Set `include_visitors=true` to include unidentified **Visitor** records.\n\nPass `updated_since` (ISO-8601, compared in UTC) to poll only customers changed on or after that timestamp.\n\nTypical first step before loading a single profile or extended timeline.\n\nSee glossary: Customer, Visitor, Connection state, Frequency, Engagement."
              },
              "status": "Error",
              "code": 503,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Service temporarily unavailable. Please narrow your search or try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Record a customer event",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "events"
              ]
            },
            "description": "Append an event to the customer timeline (for example a form submission or in-app action).\n\nRequires `event_name`. Optional: `event_data`, `event_time`, `location_id`, and `external_id` for idempotency.\n\nEvents are stamped with your **External source** from credentials. This is not the same as recording a CRM **Activity** (notes and calls).\n\nSee glossary: Activity, External source.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Event recorded on the customer timeline.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "events"
                  ]
                },
                "description": "Append an event to the customer timeline (for example a form submission or in-app action).\n\nRequires `event_name`. Optional: `event_data`, `event_time`, `location_id`, and `external_id` for idempotency.\n\nEvents are stamped with your **External source** from credentials. This is not the same as recording a CRM **Activity** (notes and calls).\n\nSee glossary: Activity, External source.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer event recorded successfully\",\n  \"response\": {\n    \"id\": 9001,\n    \"event_name\": \"form_submitted\",\n    \"event_time\": \"2026-07-10T08:00:00.000Z\",\n    \"source\": \"monday-crm\",\n    \"external_id\": \"evt-abc\"\n  }\n}"
            },
            {
              "name": "400 Invalid JSON or missing event_name.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "events"
                  ]
                },
                "description": "Append an event to the customer timeline (for example a form submission or in-app action).\n\nRequires `event_name`. Optional: `event_data`, `event_time`, `location_id`, and `external_id` for idempotency.\n\nEvents are stamped with your **External source** from credentials. This is not the same as recording a CRM **Activity** (notes and calls).\n\nSee glossary: Activity, External source.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"event_name is required\"\n}"
            },
            {
              "name": "403 Request included a source field (not allowed on writes).",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "events"
                  ]
                },
                "description": "Append an event to the customer timeline (for example a form submission or in-app action).\n\nRequires `event_name`. Optional: `event_data`, `event_time`, `location_id`, and `external_id` for idempotency.\n\nEvents are stamped with your **External source** from credentials. This is not the same as recording a CRM **Activity** (notes and calls).\n\nSee glossary: Activity, External source.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 403,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"source is managed by your API credentials and cannot be set on write requests\"\n}"
            },
            {
              "name": "404 Customer not found for this brand.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "events"
                  ]
                },
                "description": "Append an event to the customer timeline (for example a form submission or in-app action).\n\nRequires `event_name`. Optional: `event_data`, `event_time`, `location_id`, and `external_id` for idempotency.\n\nEvents are stamped with your **External source** from credentials. This is not the same as recording a CRM **Activity** (notes and calls).\n\nSee glossary: Activity, External source.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "events"
                  ]
                },
                "description": "Append an event to the customer timeline (for example a form submission or in-app action).\n\nRequires `event_name`. Optional: `event_data`, `event_time`, `location_id`, and `external_id` for idempotency.\n\nEvents are stamped with your **External source** from credentials. This is not the same as recording a CRM **Activity** (notes and calls).\n\nSee glossary: Activity, External source.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Record a customer event by external id",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "by-external-id",
                "events"
              ],
              "query": [
                {
                  "key": "external_id",
                  "value": "{{external_id}}",
                  "description": "Contact external_id. Prefer the body field; query is accepted for convenience.",
                  "disabled": false
                }
              ]
            },
            "description": "Same as recording a customer event, but resolve the person with your website `external_id` instead of `customer_id`.\n\nPass `external_id` (contact) plus `event_name`. Use `event_external_id` for the event’s own id.\n\nLookup uses your credential **External source**.\n\nSee glossary: external_id and external_data, External source, Activity.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Event recorded; response includes resolved customer_id.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "events"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Contact external_id. Prefer the body field; query is accepted for convenience.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Same as recording a customer event, but resolve the person with your website `external_id` instead of `customer_id`.\n\nPass `external_id` (contact) plus `event_name`. Use `event_external_id` for the event’s own id.\n\nLookup uses your credential **External source**.\n\nSee glossary: external_id and external_data, External source, Activity.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer event recorded successfully\",\n  \"response\": {\n    \"id\": 9001,\n    \"customer_id\": 104823,\n    \"event_name\": \"form_submitted\",\n    \"event_time\": \"2026-07-10T08:00:00.000Z\",\n    \"source\": \"monday-crm\",\n    \"external_id\": \"evt-abc\"\n  }\n}"
            },
            {
              "name": "400 Invalid JSON or missing external_id / event_name.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "events"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Contact external_id. Prefer the body field; query is accepted for convenience.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Same as recording a customer event, but resolve the person with your website `external_id` instead of `customer_id`.\n\nPass `external_id` (contact) plus `event_name`. Use `event_external_id` for the event’s own id.\n\nLookup uses your credential **External source**.\n\nSee glossary: external_id and external_data, External source, Activity.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"event_name is required\"\n}"
            },
            {
              "name": "403 Request included a source field (not allowed on writes).",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "events"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Contact external_id. Prefer the body field; query is accepted for convenience.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Same as recording a customer event, but resolve the person with your website `external_id` instead of `customer_id`.\n\nPass `external_id` (contact) plus `event_name`. Use `event_external_id` for the event’s own id.\n\nLookup uses your credential **External source**.\n\nSee glossary: external_id and external_data, External source, Activity.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 403,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"source is managed by your API credentials and cannot be set on write requests\"\n}"
            },
            {
              "name": "404 No customer for this external_id under your External source.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "events"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Contact external_id. Prefer the body field; query is accepted for convenience.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Same as recording a customer event, but resolve the person with your website `external_id` instead of `customer_id`.\n\nPass `external_id` (contact) plus `event_name`. Use `event_external_id` for the event’s own id.\n\nLookup uses your credential **External source**.\n\nSee glossary: external_id and external_data, External source, Activity.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/by-external-id/events",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "by-external-id",
                    "events"
                  ],
                  "query": [
                    {
                      "key": "external_id",
                      "value": "{{external_id}}",
                      "description": "Contact external_id. Prefer the body field; query is accepted for convenience.",
                      "disabled": false
                    }
                  ]
                },
                "description": "Same as recording a customer event, but resolve the person with your website `external_id` instead of `customer_id`.\n\nPass `external_id` (contact) plus `event_name`. Use `event_external_id` for the event’s own id.\n\nLookup uses your credential **External source**.\n\nSee glossary: external_id and external_data, External source, Activity.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"external_id\": \"crm-contact-1001\",\n  \"event_name\": \"form_submitted\",\n  \"event_time\": \"2026-08-05T06:00:00.000Z\",\n  \"event_data\": {\n    \"form\": \"newsletter\"\n  },\n  \"location_id\": {{location_id}},\n  \"is_visible_to_customer\": false\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Search customers with advanced filters",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/search",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "search"
              ]
            },
            "description": "Search and page through customers using a JSON body with the same filters as `GET …/customers` (cursor, limit, query, locations, sort_by, sort_direction, connection, frequency, engagement, customer_group_id, search_fields, updated_since, include_visitors).\n\nPrefer `GET …/customers` for simple query-string browse; use this when filters are easier to express in JSON.\n\nSee glossary: Customer, Visitor, Connection state.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"limit\": 15,\n  \"query\": \"alex\",\n  \"include_visitors\": false,\n  \"sort_by\": \"total_spent\",\n  \"sort_direction\": \"desc\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 A page of customers. response.next_cursor is null when there are no more pages.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/search",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "search"
                  ]
                },
                "description": "Search and page through customers using a JSON body with the same filters as `GET …/customers` (cursor, limit, query, locations, sort_by, sort_direction, connection, frequency, engagement, customer_group_id, search_fields, updated_since, include_visitors).\n\nPrefer `GET …/customers` for simple query-string browse; use this when filters are easier to express in JSON.\n\nSee glossary: Customer, Visitor, Connection state.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"limit\": 15,\n  \"query\": \"alex\",\n  \"include_visitors\": false,\n  \"sort_by\": \"total_spent\",\n  \"sort_direction\": \"desc\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer records fetched successfully (known only)\",\n  \"response\": {\n    \"data\": [\n      {\n        \"id\": 104823,\n        \"external_data\": null,\n        \"first_name\": \"Jordan\",\n        \"last_name\": \"Lee\",\n        \"email\": \"jordan.lee@example.com\",\n        \"phone\": \"+61412345678\",\n        \"location_id\": 3,\n        \"brand_id\": 42,\n        \"uuid\": \"c0b1f7a4-2e3d-4f5a-9b6c-7d8e9f0a1b2c\",\n        \"predicted_name\": null,\n        \"type\": \"customer\",\n        \"transaction_count\": 17,\n        \"total_spent\": 542.5,\n        \"tenure\": 412,\n        \"latest_transaction\": \"2026-06-21T03:15:00.000Z\",\n        \"last_seen\": \"2026-06-21T03:15:00.000Z\",\n        \"frequency\": \"Frequent\",\n        \"engagement\": \"engaged\",\n        \"connection_type\": \"connected\"\n      }\n    ],\n    \"has_more\": true,\n    \"next_cursor\": \"1|0|2026-06-21T03:15:00.000Z|104823\",\n    \"total_count\": 1287\n  }\n}"
            },
            {
              "name": "400 Invalid JSON body or updated_since.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/search",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "search"
                  ]
                },
                "description": "Search and page through customers using a JSON body with the same filters as `GET …/customers` (cursor, limit, query, locations, sort_by, sort_direction, connection, frequency, engagement, customer_group_id, search_fields, updated_since, include_visitors).\n\nPrefer `GET …/customers` for simple query-string browse; use this when filters are easier to express in JSON.\n\nSee glossary: Customer, Visitor, Connection state.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"limit\": 15,\n  \"query\": \"alex\",\n  \"include_visitors\": false,\n  \"sort_by\": \"total_spent\",\n  \"sort_direction\": \"desc\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"updated_since must be a valid ISO-8601 timestamp\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/search",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "search"
                  ]
                },
                "description": "Search and page through customers using a JSON body with the same filters as `GET …/customers` (cursor, limit, query, locations, sort_by, sort_direction, connection, frequency, engagement, customer_group_id, search_fields, updated_since, include_visitors).\n\nPrefer `GET …/customers` for simple query-string browse; use this when filters are easier to express in JSON.\n\nSee glossary: Customer, Visitor, Connection state.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"limit\": 15,\n  \"query\": \"alex\",\n  \"include_visitors\": false,\n  \"sort_by\": \"total_spent\",\n  \"sort_direction\": \"desc\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Get a customer by id",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}"
              ]
            },
            "description": "Load one customer profile with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime transaction stats, and loyalty join status (`connection_type`).\n\n`connection_type` is `connected` when the customer has joined loyalty, `known` when myne has the customer but they have not joined, and `unknown` for an anonymous website visitor. It matches the `connection_type` on the customer list.\n\nIdentities are listed in `extended[]`, not as a single top-level source/external_id. Cashback is the internal cashback ledger, not a live Wrapped or Giftit credit GET. Visit totals sit on `stats`.\n\nUse the `customer_id` from browse, sync batch, or your POS. Returns 404 when the ID is not in this brand.\n\nSee glossary: Customer, External source, Credit, Points."
          },
          "response": [
            {
              "name": "200 A customer returned with identities, loyalty balances, and lifetime stats.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}"
                  ]
                },
                "description": "Load one customer profile with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime transaction stats, and loyalty join status (`connection_type`).\n\n`connection_type` is `connected` when the customer has joined loyalty, `known` when myne has the customer but they have not joined, and `unknown` for an anonymous website visitor. It matches the `connection_type` on the customer list.\n\nIdentities are listed in `extended[]`, not as a single top-level source/external_id. Cashback is the internal cashback ledger, not a live Wrapped or Giftit credit GET. Visit totals sit on `stats`.\n\nUse the `customer_id` from browse, sync batch, or your POS. Returns 404 when the ID is not in this brand.\n\nSee glossary: Customer, External source, Credit, Points."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer fetched successfully\",\n  \"response\": {\n    \"customer\": {\n      \"id\": 104823,\n      \"brand_id\": 42,\n      \"location_id\": 3,\n      \"phone\": \"+61412345678\",\n      \"email\": \"jordan.lee@example.com\",\n      \"created_at\": \"2025-02-15T01:23:45.000Z\",\n      \"updated_at\": \"2026-06-21T03:15:00.000Z\",\n      \"accepts_marketing\": true,\n      \"first_name\": \"Jordan\",\n      \"last_name\": \"Lee\",\n      \"archived_at\": null,\n      \"frequency\": \"Frequent\",\n      \"engagement\": \"engaged\",\n      \"connection_type\": \"connected\",\n      \"pass_id\": \"ABC123XYZ\",\n      \"points\": 120,\n      \"cashback\": 18.5\n    },\n    \"stats\": {\n      \"transaction_count\": 17,\n      \"total_spent\": 542.5,\n      \"last_transaction_date\": \"2026-06-21T03:15:00.000Z\"\n    },\n    \"extended\": [\n      {\n        \"source\": \"lightspeed\",\n        \"external_id\": \"ext-abc123\",\n        \"json_data\": {\n          \"pos_id\": \"LS-98765\"\n        },\n        \"updated_at\": \"2026-06-21T03:15:00.000Z\"\n      },\n      {\n        \"source\": \"monday-crm\",\n        \"external_id\": \"crm-001\",\n        \"json_data\": {},\n        \"updated_at\": \"2026-05-01T00:00:00.000Z\"\n      }\n    ]\n  }\n}"
            },
            {
              "name": "400 brand_id or customer_id is missing or not a positive integer.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}"
                  ]
                },
                "description": "Load one customer profile with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime transaction stats, and loyalty join status (`connection_type`).\n\n`connection_type` is `connected` when the customer has joined loyalty, `known` when myne has the customer but they have not joined, and `unknown` for an anonymous website visitor. It matches the `connection_type` on the customer list.\n\nIdentities are listed in `extended[]`, not as a single top-level source/external_id. Cashback is the internal cashback ledger, not a live Wrapped or Giftit credit GET. Visit totals sit on `stats`.\n\nUse the `customer_id` from browse, sync batch, or your POS. Returns 404 when the ID is not in this brand.\n\nSee glossary: Customer, External source, Credit, Points."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id or customer_id\"\n}"
            },
            {
              "name": "404 No customer with the given id exists for this brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}"
                  ]
                },
                "description": "Load one customer profile with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime transaction stats, and loyalty join status (`connection_type`).\n\n`connection_type` is `connected` when the customer has joined loyalty, `known` when myne has the customer but they have not joined, and `unknown` for an anonymous website visitor. It matches the `connection_type` on the customer list.\n\nIdentities are listed in `extended[]`, not as a single top-level source/external_id. Cashback is the internal cashback ledger, not a live Wrapped or Giftit credit GET. Visit totals sit on `stats`.\n\nUse the `customer_id` from browse, sync batch, or your POS. Returns 404 when the ID is not in this brand.\n\nSee glossary: Customer, External source, Credit, Points."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error. Details are logged server-side.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}"
                  ]
                },
                "description": "Load one customer profile with connected-system identities (`extended[]`), pass id, Brand Points, myne cashback, lifetime transaction stats, and loyalty join status (`connection_type`).\n\n`connection_type` is `connected` when the customer has joined loyalty, `known` when myne has the customer but they have not joined, and `unknown` for an anonymous website visitor. It matches the `connection_type` on the customer list.\n\nIdentities are listed in `extended[]`, not as a single top-level source/external_id. Cashback is the internal cashback ledger, not a live Wrapped or Giftit credit GET. Visit totals sit on `stats`.\n\nUse the `customer_id` from browse, sync batch, or your POS. Returns 404 when the ID is not in this brand.\n\nSee glossary: Customer, External source, Credit, Points."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Get extended customer profile",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/extended",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "extended"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "15",
                  "description": "Maximum timeline records to return per collection (activities, transactions).",
                  "disabled": false
                },
                {
                  "key": "offset",
                  "value": "",
                  "description": "Zero-based offset into the timeline.",
                  "disabled": true
                },
                {
                  "key": "payments",
                  "value": "",
                  "description": "When true, include payment detail objects inside each transaction record. Defaults to false.",
                  "disabled": true
                }
              ]
            },
            "description": "Fetch a customer's timeline: external POS records, marketing activities, and transactions.\n\nPaginate with `limit` and `offset`. Set `payments=true` to include payment line items on each transaction.\n\nUse when you need history beyond the summary fields on the main customer endpoint.\n\nSee glossary: Extended profile, Customer."
          },
          "response": [
            {
              "name": "200 Customer extended profile with timeline.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "extended"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Maximum timeline records to return per collection (activities, transactions).",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "Zero-based offset into the timeline.",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail objects inside each transaction record. Defaults to false.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Fetch a customer's timeline: external POS records, marketing activities, and transactions.\n\nPaginate with `limit` and `offset`. Set `payments=true` to include payment line items on each transaction.\n\nUse when you need history beyond the summary fields on the main customer endpoint.\n\nSee glossary: Extended profile, Customer."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer extended data fetched successfully\",\n  \"response\": {\n    \"external_records\": [],\n    \"activities\": [\n      {\n        \"type\": \"event\",\n        \"source\": \"lightspeed\",\n        \"created_at\": \"2026-06-21T03:15:00.000Z\",\n        \"data\": {\n          \"name\": \"checkin\"\n        }\n      }\n    ],\n    \"transactions\": [\n      {\n        \"type\": \"transaction\",\n        \"id\": 5501,\n        \"amount\": 42.5,\n        \"transaction_date\": \"2026-06-21T03:15:00.000Z\",\n        \"payments\": []\n      }\n    ],\n    \"pagination\": {\n      \"limit\": 25,\n      \"offset\": 0\n    }\n  }\n}"
            },
            {
              "name": "400 brand_id or customer_id is missing or not a positive integer.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "extended"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Maximum timeline records to return per collection (activities, transactions).",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "Zero-based offset into the timeline.",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail objects inside each transaction record. Defaults to false.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Fetch a customer's timeline: external POS records, marketing activities, and transactions.\n\nPaginate with `limit` and `offset`. Set `payments=true` to include payment line items on each transaction.\n\nUse when you need history beyond the summary fields on the main customer endpoint.\n\nSee glossary: Extended profile, Customer."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id or customer_id\"\n}"
            },
            {
              "name": "404 No customer with the given id exists for this brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "extended"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Maximum timeline records to return per collection (activities, transactions).",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "Zero-based offset into the timeline.",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail objects inside each transaction record. Defaults to false.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Fetch a customer's timeline: external POS records, marketing activities, and transactions.\n\nPaginate with `limit` and `offset`. Set `payments=true` to include payment line items on each transaction.\n\nUse when you need history beyond the summary fields on the main customer endpoint.\n\nSee glossary: Extended profile, Customer."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error. Details are logged server-side.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/extended",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "extended"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "Maximum timeline records to return per collection (activities, transactions).",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "Zero-based offset into the timeline.",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail objects inside each transaction record. Defaults to false.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Fetch a customer's timeline: external POS records, marketing activities, and transactions.\n\nPaginate with `limit` and `offset`. Set `payments=true` to include payment line items on each transaction.\n\nUse when you need history beyond the summary fields on the main customer endpoint.\n\nSee glossary: Extended profile, Customer."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Customer groups",
      "item": [
        {
          "name": "List customer groups",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/filter-groups",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "filter-groups"
              ],
              "query": [
                {
                  "key": "updated_since",
                  "value": "",
                  "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Return every active customer group for the brand (id and name), including **Claimed - …** groups for live offers.\n\nUse customer group IDs when exporting membership or scoping customer browse (`customer_group_id`). Deleted customer groups are omitted. Membership may be maintained by dynamic refresh, scheduled refresh, import replace, or automation-driven changes—see glossary. Claimed-group membership is join-page claim, not an API write.\n\nSee glossary: Customer group."
          },
          "response": [
            {
              "name": "200 Active customer groups for the brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/filter-groups",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "filter-groups"
                  ],
                  "query": [
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Return every active customer group for the brand (id and name), including **Claimed - …** groups for live offers.\n\nUse customer group IDs when exporting membership or scoping customer browse (`customer_group_id`). Deleted customer groups are omitted. Membership may be maintained by dynamic refresh, scheduled refresh, import replace, or automation-driven changes—see glossary. Claimed-group membership is join-page claim, not an API write.\n\nSee glossary: Customer group."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Filter groups fetched successfully\",\n  \"response\": [\n    {\n      \"id\": 12,\n      \"group_name\": \"VIP\"\n    },\n    {\n      \"id\": 7,\n      \"group_name\": \"Recent visitors\"\n    }\n  ]\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Credit",
      "item": [
        {
          "name": "Get customer credit balance and wallet pass identifiers",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "credit"
              ]
            },
            "description": "Look up a customer's credit balance and **Wallet pass** identifiers (Apple Wallet and Google Wallet).\n\nBalance is fetched live from the loyalty partner when credit is linked. Otherwise `giftcard_code` is null and balance is 0.\n\nSee glossary: Credit, Wallet pass."
          },
          "response": [
            {
              "name": "200 Customer credit and wallet pass information. When no credit is linked, giftcard_code is null and balance is 0.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Look up a customer's credit balance and **Wallet pass** identifiers (Apple Wallet and Google Wallet).\n\nBalance is fetched live from the loyalty partner when credit is linked. Otherwise `giftcard_code` is null and balance is 0.\n\nSee glossary: Credit, Wallet pass."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"ok\",\n  \"response\": {\n    \"giftcard_code\": \"ABC123XYZ\",\n    \"balance\": 75,\n    \"balance_fetched_at\": \"2026-06-21T03:15:00.000Z\",\n    \"apple_wallet\": [\n      {\n        \"pass_type_identifier\": \"pass.com.myne.network.gift\",\n        \"serial_number\": \"abc123def456\"\n      }\n    ],\n    \"google_wallet\": [\n      {\n        \"issuer_id\": \"3388000000022345678\",\n        \"class_suffix\": \"giftcard_v1\",\n        \"object_suffix\": \"104823\"\n      }\n    ]\n  }\n}"
            },
            {
              "name": "400 brand_id or customer_id is missing or not a positive integer.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Look up a customer's credit balance and **Wallet pass** identifiers (Apple Wallet and Google Wallet).\n\nBalance is fetched live from the loyalty partner when credit is linked. Otherwise `giftcard_code` is null and balance is 0.\n\nSee glossary: Credit, Wallet pass."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id or customer_id\"\n}"
            },
            {
              "name": "404 No customer with the given id exists for this brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Look up a customer's credit balance and **Wallet pass** identifiers (Apple Wallet and Google Wallet).\n\nBalance is fetched live from the loyalty partner when credit is linked. Otherwise `giftcard_code` is null and balance is 0.\n\nSee glossary: Credit, Wallet pass."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error. Details are logged server-side.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Look up a customer's credit balance and **Wallet pass** identifiers (Apple Wallet and Google Wallet).\n\nBalance is fetched live from the loyalty partner when credit is linked. Otherwise `giftcard_code` is null and balance is 0.\n\nSee glossary: Credit, Wallet pass."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Add credit to a customer",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "credit"
              ]
            },
            "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Credit successfully added.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"ok\",\n  \"response\": {\n    \"giftcard_code\": \"ABC123XYZ\",\n    \"balance\": 85,\n    \"loyalty_system\": \"wrapped\",\n    \"customer_giftcard_id\": 567,\n    \"adjusted_at\": \"2026-06-21T03:15:00.000Z\"\n  }\n}"
            },
            {
              "name": "Invalid brand/customer id",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id or customer_id\"\n}"
            },
            {
              "name": "Unparseable JSON body",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid JSON body\"\n}"
            },
            {
              "name": "Validation error on amount",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Amount must be a positive number\"\n}"
            },
            {
              "name": "404 Customer or credit account not found.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error. Details are logged server-side.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/credit",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "credit"
                  ]
                },
                "description": "Add stored value to a customer's linked credit.\n\nSend `amount` and `reason` in the body. Reason is stored for audit and appears in the credit ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate credits are not applied. The customer must already have linked credit.\n\nSee glossary: Credit.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": 10,\n  \"reason\": \"Birthday bonus\",\n  \"idempotency_key\": \"credit-topup-001\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Points",
      "item": [
        {
          "name": "Get customer points balance",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "points"
              ]
            },
            "description": "Return a customer's Brand Points balance and the brand's points label (for example \"Stars\").\n\n`active` is false and balance is 0 when Brand Points is not enabled for this brand.\n\nSee glossary: Points."
          },
          "response": [
            {
              "name": "200 Brand Points balance and label. When points are not enabled, active is false and balance is 0.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Return a customer's Brand Points balance and the brand's points label (for example \"Stars\").\n\n`active` is false and balance is 0 when Brand Points is not enabled for this brand.\n\nSee glossary: Points."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"ok\",\n  \"response\": {\n    \"balance\": 1250,\n    \"points_label\": \"Stars\",\n    \"active\": true\n  }\n}"
            },
            {
              "name": "400 Invalid brand_id or customer_id.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Return a customer's Brand Points balance and the brand's points label (for example \"Stars\").\n\n`active` is false and balance is 0 when Brand Points is not enabled for this brand.\n\nSee glossary: Points."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id or customer_id\"\n}"
            },
            {
              "name": "404 Customer not found for this brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Return a customer's Brand Points balance and the brand's points label (for example \"Stars\").\n\n`active` is false and balance is 0 when Brand Points is not enabled for this brand.\n\nSee glossary: Points."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Return a customer's Brand Points balance and the brand's points label (for example \"Stars\").\n\n`active` is false and balance is 0 when Brand Points is not enabled for this brand.\n\nSee glossary: Points."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        },
        {
          "name": "Add points to a customer",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "points"
              ]
            },
            "description": "Add Brand Points to a customer.\n\nSend `points_amount` and `reason` in the body. Reason is stored for audit and appears in the points ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate top-ups are not applied. Returns 400 when Brand Points is not enabled for this brand.\n\nSee glossary: Points.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"points_amount\": 100,\n  \"reason\": \"Compensation for delayed order\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Points successfully added.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Add Brand Points to a customer.\n\nSend `points_amount` and `reason` in the body. Reason is stored for audit and appears in the points ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate top-ups are not applied. Returns 400 when Brand Points is not enabled for this brand.\n\nSee glossary: Points.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"points_amount\": 100,\n  \"reason\": \"Compensation for delayed order\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"ok\",\n  \"response\": {\n    \"loyalty_system\": \"brand_points\",\n    \"points_amount\": 100,\n    \"balance_after\": 1350,\n    \"adjusted_at\": \"2026-06-21T03:15:00.000Z\"\n  }\n}"
            },
            {
              "name": "400 Invalid body or Brand Points is not enabled for this brand.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Add Brand Points to a customer.\n\nSend `points_amount` and `reason` in the body. Reason is stored for audit and appears in the points ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate top-ups are not applied. Returns 400 when Brand Points is not enabled for this brand.\n\nSee glossary: Points.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"points_amount\": 100,\n  \"reason\": \"Compensation for delayed order\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Brand Points is not enabled for this brand\"\n}"
            },
            {
              "name": "404 Customer not found for this brand.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Add Brand Points to a customer.\n\nSend `points_amount` and `reason` in the body. Reason is stored for audit and appears in the points ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate top-ups are not applied. Returns 400 when Brand Points is not enabled for this brand.\n\nSee glossary: Points.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"points_amount\": 100,\n  \"reason\": \"Compensation for delayed order\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/points",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "points"
                  ]
                },
                "description": "Add Brand Points to a customer.\n\nSend `points_amount` and `reason` in the body. Reason is stored for audit and appears in the points ledger. `note` is accepted as a legacy alias for `reason` for one release.\n\nSupply `idempotency_key` when retrying so duplicate top-ups are not applied. Returns 400 when Brand Points is not enabled for this brand.\n\nSee glossary: Points.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"points_amount\": 100,\n  \"reason\": \"Compensation for delayed order\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Products",
      "item": [
        {
          "name": "Browse products for a brand",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/products",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "products"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "15",
                  "description": "",
                  "disabled": false
                },
                {
                  "key": "search",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "location_id",
                  "value": "{{location_id}}",
                  "description": "Include products scoped to this location (unscoped products still match).",
                  "disabled": true
                },
                {
                  "key": "updated_since",
                  "value": "",
                  "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Page through the brand's sellable catalog.\n\nFilter by `location_id` to include products scoped to one venue (unscoped products still match). Use free-text search to narrow by name or description.\n\nProduct rows include partner-safe fields. Use get-by-id or by-external-id when you need integration `extended[]` payloads—especially surface-specific POS ids before evaluate.\n\nSee glossary: Location, Order line pos_id, Surface."
          },
          "response": [
            {
              "name": "200 Paginated product catalog for the brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/products",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "products"
                  ],
                  "query": [
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "search",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "location_id",
                      "value": "{{location_id}}",
                      "description": "Include products scoped to this location (unscoped products still match).",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Page through the brand's sellable catalog.\n\nFilter by `location_id` to include products scoped to one venue (unscoped products still match). Use free-text search to narrow by name or description.\n\nProduct rows include partner-safe fields. Use get-by-id or by-external-id when you need integration `extended[]` payloads—especially surface-specific POS ids before evaluate.\n\nSee glossary: Location, Order line pos_id, Surface."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Products fetched successfully\",\n  \"response\": {\n    \"products\": [\n      {\n        \"id\": 501,\n        \"name\": \"Flat white\",\n        \"description\": \"Double-shot flat white\",\n        \"price\": 4.5,\n        \"is_option\": false,\n        \"sku\": \"FW-REG\",\n        \"image_url\": null,\n        \"created_at\": \"2025-11-01T00:00:00.000Z\",\n        \"updated_at\": \"2026-06-01T00:00:00.000Z\"\n      }\n    ],\n    \"total\": 1,\n    \"limit\": 20,\n    \"offset\": 0,\n    \"page\": 1\n  }\n}"
            },
            {
              "name": "400 Invalid brand_id. Invalid updated_since.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/products",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "products"
                  ],
                  "query": [
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "search",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "location_id",
                      "value": "{{location_id}}",
                      "description": "Include products scoped to this location (unscoped products still match).",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Page through the brand's sellable catalog.\n\nFilter by `location_id` to include products scoped to one venue (unscoped products still match). Use free-text search to narrow by name or description.\n\nProduct rows include partner-safe fields. Use get-by-id or by-external-id when you need integration `extended[]` payloads—especially surface-specific POS ids before evaluate.\n\nSee glossary: Location, Order line pos_id, Surface."
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid brand_id\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/products",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "products"
                  ],
                  "query": [
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "search",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "location_id",
                      "value": "{{location_id}}",
                      "description": "Include products scoped to this location (unscoped products still match).",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Page through the brand's sellable catalog.\n\nFilter by `location_id` to include products scoped to one venue (unscoped products still match). Use free-text search to narrow by name or description.\n\nProduct rows include partner-safe fields. Use get-by-id or by-external-id when you need integration `extended[]` payloads—especially surface-specific POS ids before evaluate.\n\nSee glossary: Location, Order line pos_id, Surface."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Promotions",
      "item": [
        {
          "name": "Browse promotions for a brand",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/promotions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "promotions"
              ],
              "query": [
                {
                  "key": "location_id",
                  "value": "{{location_id}}",
                  "description": "Restrict to promotions for one location (includes brand-wide promotions).",
                  "disabled": true
                },
                {
                  "key": "page",
                  "value": "1",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "15",
                  "description": "",
                  "disabled": false
                },
                {
                  "key": "search",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "valid_only",
                  "value": "true",
                  "description": "When true, only promotions within their valid date range are returned.",
                  "disabled": true
                },
                {
                  "key": "surface",
                  "value": "",
                  "description": "Restrict to promotions visible on one channel.",
                  "disabled": true
                },
                {
                  "key": "integration_type",
                  "value": "",
                  "description": "List filter only — not a basket field. Use to return which promotions can show from customer Show vs available groups, in a coarse context (ordering, listing, or ecommerce), without knowing which app will evaluate the sale. Do not send on evaluate, apply, or complete. Those open-order calls always n",
                  "disabled": true
                },
                {
                  "key": "updated_since",
                  "value": "",
                  "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                  "disabled": true
                }
              ]
            },
            "description": "List promotions configured for a brand.\n\nFilter by `location_id`, paginate with `page` and `limit`, or narrow with search.\n\nPass `surface` (`connection_pages`, `meandu`, `lso`, or `lsk`) when you already know the app. Optional `integration_type` is only for listing what can show without an open order and without knowing which app will later evaluate the sale: `ordering` → meandu, `listing` / `ecommerce` → connection_pages. Eligibility still follows customer **Show vs available** groups. Do not send `integration_type` on evaluate, apply, or complete — those basket calls always need `surface` (`lsk` or `lso`). `pos` is not a substitute for a register or ordering app.\n\nEach promotion includes `image_url` (the offer image, or null), `availability[]` (the surfaces it may appear on) and enriched requirements/targets with product and category names plus `extended[]`.\n\nSee glossary: Promotion, Surface, Location."
          },
          "response": [
            {
              "name": "200 Paginated promotion catalog for the brand.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/promotions",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "promotions"
                  ],
                  "query": [
                    {
                      "key": "location_id",
                      "value": "{{location_id}}",
                      "description": "Restrict to promotions for one location (includes brand-wide promotions).",
                      "disabled": true
                    },
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "search",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "valid_only",
                      "value": "true",
                      "description": "When true, only promotions within their valid date range are returned.",
                      "disabled": true
                    },
                    {
                      "key": "surface",
                      "value": "",
                      "description": "Restrict to promotions visible on one channel.",
                      "disabled": true
                    },
                    {
                      "key": "integration_type",
                      "value": "",
                      "description": "List filter only — not a basket field. Use to return which promotions can show from customer Show vs available groups, in a coarse context (ordering, listing, or ecommerce), without knowing which app will evaluate the sale. Do not send on evaluate, apply, or complete. Those open-order calls always n",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "List promotions configured for a brand.\n\nFilter by `location_id`, paginate with `page` and `limit`, or narrow with search.\n\nPass `surface` (`connection_pages`, `meandu`, `lso`, or `lsk`) when you already know the app. Optional `integration_type` is only for listing what can show without an open order and without knowing which app will later evaluate the sale: `ordering` → meandu, `listing` / `ecommerce` → connection_pages. Eligibility still follows customer **Show vs available** groups. Do not send `integration_type` on evaluate, apply, or complete — those basket calls always need `surface` (`lsk` or `lso`). `pos` is not a substitute for a register or ordering app.\n\nEach promotion includes `image_url` (the offer image, or null), `availability[]` (the surfaces it may appear on) and enriched requirements/targets with product and category names plus `extended[]`.\n\nSee glossary: Promotion, Surface, Location."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Promotions fetched successfully\",\n  \"response\": {\n    \"promotions\": [\n      {\n        \"id\": 901,\n        \"brand_id\": 42,\n        \"name\": \"Free regular coffee\",\n        \"description\": \"One regular coffee on us\",\n        \"image_url\": \"https://assets.myne.network/images/demo/free-coffee.png\",\n        \"discount_type\": \"free_item\",\n        \"applies_to\": \"in_store\",\n        \"channel\": \"pos\",\n        \"location_id\": null,\n        \"valid_from\": \"2026-01-01T00:00:00.000Z\",\n        \"valid_until\": \"2026-12-31T23:59:59.000Z\",\n        \"created_at\": \"2025-12-01T00:00:00.000Z\",\n        \"updated_at\": \"2026-06-01T00:00:00.000Z\",\n        \"availability\": [\n          \"connection_pages\",\n          \"lsk\",\n          \"lso\",\n          \"meandu\",\n          \"meandu_connect\",\n          \"shopify\"\n        ],\n        \"requirements\": {\n          \"products\": [],\n          \"categories\": [\n            {\n              \"id\": 10,\n              \"name\": \"Coffee\",\n              \"extended\": []\n            }\n          ]\n        },\n        \"targets\": {\n          \"products\": [\n            {\n              \"id\": 501,\n              \"name\": \"Flat white\",\n              \"extended\": [\n                {\n                  \"source\": \"lightspeed-k\",\n                  \"external_id\": \"456\",\n                  \"json_data\": {},\n                  \"updated_at\": null\n                }\n              ]\n            }\n          ],\n          \"categories\": []\n        }\n      }\n    ],\n    \"total\": 1,\n    \"limit\": 20,\n    \"offset\": 0,\n    \"page\": 1\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Transactions",
      "item": [
        {
          "name": "List transactions for a customer",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/transactions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "customers",
                "{{customer_id}}",
                "transactions"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "15",
                  "description": "",
                  "disabled": false
                },
                {
                  "key": "offset",
                  "value": "",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "page",
                  "value": "1",
                  "description": "",
                  "disabled": true
                },
                {
                  "key": "payments",
                  "value": "",
                  "description": "When true, include payment detail on each transaction.",
                  "disabled": true
                },
                {
                  "key": "updated_since",
                  "value": "",
                  "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Page through paid purchase history for one customer. An open sale is an **order**; once paid it becomes a **Transaction**. Returns POS and payment-linked transactions with line items.\n\nUse `limit` and `offset` (or `page`) for pagination. Set `payments=true` to include payment detail on each row.\n\nCustomer events and CRM activities are separate endpoints—see Activities and `POST …/events`. Returns 404 when the customer is not in this brand.\n\nSee glossary: Customer, Transaction, Activity."
          },
          "response": [
            {
              "name": "200 Paginated customer transaction history.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/transactions",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "transactions"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail on each transaction.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Page through paid purchase history for one customer. An open sale is an **order**; once paid it becomes a **Transaction**. Returns POS and payment-linked transactions with line items.\n\nUse `limit` and `offset` (or `page`) for pagination. Set `payments=true` to include payment detail on each row.\n\nCustomer events and CRM activities are separate endpoints—see Activities and `POST …/events`. Returns 404 when the customer is not in this brand.\n\nSee glossary: Customer, Transaction, Activity."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Transactions fetched successfully\",\n  \"response\": {\n    \"transactions\": [\n      {\n        \"id\": 550012,\n        \"transaction_id\": 550012,\n        \"transacted_at\": \"2026-06-21T03:15:00.000Z\",\n        \"location\": \"Sydney CBD\",\n        \"location_id\": 3,\n        \"source\": \"lightspeed\",\n        \"external_transaction_id\": \"POS-88421\",\n        \"notes\": null,\n        \"order_type\": \"dine_in\",\n        \"total_paid\": 24.5,\n        \"line_items\": [\n          {\n            \"id\": 88001,\n            \"product_id\": 1201,\n            \"product_name\": \"Flat White\",\n            \"quantity\": 1,\n            \"price_inc_tax\": 5.5,\n            \"total_price\": 5.5,\n            \"children\": [],\n            \"modifiers\": []\n          }\n        ],\n        \"payments\": [\n          {\n            \"id\": 77001,\n            \"method\": \"Card\",\n            \"paid_amount\": 24.5,\n            \"tip_amount\": 0,\n            \"last_4\": \"4242\"\n          }\n        ]\n      }\n    ],\n    \"total\": 1,\n    \"limit\": 25,\n    \"offset\": 0,\n    \"page\": 1\n  }\n}"
            },
            {
              "name": "404 Customer not found.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/transactions",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "transactions"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail on each transaction.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Page through paid purchase history for one customer. An open sale is an **order**; once paid it becomes a **Transaction**. Returns POS and payment-linked transactions with line items.\n\nUse `limit` and `offset` (or `page`) for pagination. Set `payments=true` to include payment detail on each row.\n\nCustomer events and CRM activities are separate endpoints—see Activities and `POST …/events`. Returns 404 when the customer is not in this brand.\n\nSee glossary: Customer, Transaction, Activity."
              },
              "status": "Error",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Customer not found\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/customers/{{customer_id}}/transactions",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "customers",
                    "{{customer_id}}",
                    "transactions"
                  ],
                  "query": [
                    {
                      "key": "limit",
                      "value": "15",
                      "description": "",
                      "disabled": false
                    },
                    {
                      "key": "offset",
                      "value": "",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "page",
                      "value": "1",
                      "description": "",
                      "disabled": true
                    },
                    {
                      "key": "payments",
                      "value": "",
                      "description": "When true, include payment detail on each transaction.",
                      "disabled": true
                    },
                    {
                      "key": "updated_since",
                      "value": "",
                      "description": "ISO-8601 timestamp. When set, only rows with updated_at on or after this instant are returned (compared in UTC, inclusive). Omit for the full list. Invalid values return 400.",
                      "disabled": true
                    }
                  ]
                },
                "description": "Page through paid purchase history for one customer. An open sale is an **order**; once paid it becomes a **Transaction**. Returns POS and payment-linked transactions with line items.\n\nUse `limit` and `offset` (or `page`) for pagination. Set `payments=true` to include payment detail on each row.\n\nCustomer events and CRM activities are separate endpoints—see Activities and `POST …/events`. Returns 404 when the customer is not in this brand.\n\nSee glossary: Customer, Transaction, Activity."
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Sync",
      "item": [
        {
          "name": "Batch upsert contacts, businesses, and links",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/sync/batch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "brands",
                "{{brand_id}}",
                "sync",
                "batch"
              ]
            },
            "description": "Push up to 50 contacts, businesses, business–contact links, extended fields, or health topics in one request.\n\nThis is the primary write path for CRM, PMS, and POS integrations syncing data into myne (for example guests from MEWS).\n\nSend top-level contact fields plus your `external_id`, and optionally `contact_extended` bodies for extra partner keys/metadata used later for lookup and enrichment.\n\nRecords are always stamped with your Custom API app name—do not send `source` (or `contact_source` / `business_source`) in item bodies.\n\nEach item has a `type` and body; see the request schema for supported types.\n\nSee glossary: Sync batch, External source, external_id and external_data.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"items\": [\n    {\n      \"type\": \"contact\",\n      \"body\": {\n        \"external_id\": \"crm-contact-1001\",\n        \"email\": \"alex@example.com\",\n        \"first_name\": \"Alex\",\n        \"last_name\": \"Nguyen\",\n        \"location_id\": {{location_id}}\n      }\n    },\n    {\n      \"type\": \"business\",\n      \"body\": {\n        \"external_id\": \"crm-company-42\",\n        \"name\": \"Acme Hospitality\",\n        \"email\": \"ops@acme.example\"\n      }\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 Batch upsert completed. Each result entry matches the item type.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/sync/batch",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "sync",
                    "batch"
                  ]
                },
                "description": "Push up to 50 contacts, businesses, business–contact links, extended fields, or health topics in one request.\n\nThis is the primary write path for CRM, PMS, and POS integrations syncing data into myne (for example guests from MEWS).\n\nSend top-level contact fields plus your `external_id`, and optionally `contact_extended` bodies for extra partner keys/metadata used later for lookup and enrichment.\n\nRecords are always stamped with your Custom API app name—do not send `source` (or `contact_source` / `business_source`) in item bodies.\n\nEach item has a `type` and body; see the request schema for supported types.\n\nSee glossary: Sync batch, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"items\": [\n    {\n      \"type\": \"contact\",\n      \"body\": {\n        \"external_id\": \"crm-contact-1001\",\n        \"email\": \"alex@example.com\",\n        \"first_name\": \"Alex\",\n        \"last_name\": \"Nguyen\",\n        \"location_id\": {{location_id}}\n      }\n    },\n    {\n      \"type\": \"business\",\n      \"body\": {\n        \"external_id\": \"crm-company-42\",\n        \"name\": \"Acme Hospitality\",\n        \"email\": \"ops@acme.example\"\n      }\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Batch upsert complete\",\n  \"response\": {\n    \"count\": 2,\n    \"results\": [\n      {\n        \"type\": \"contact\",\n        \"result\": {\n          \"customer_id\": 104823,\n          \"external_id\": \"crm-001\",\n          \"created\": true\n        }\n      },\n      {\n        \"type\": \"business\",\n        \"result\": {\n          \"business_id\": 801,\n          \"external_id\": \"biz-001\",\n          \"is_new\": false\n        }\n      }\n    ]\n  }\n}"
            },
            {
              "name": "400 Invalid JSON, validation error, unsupported item type, or source fields in item bodies.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/sync/batch",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "sync",
                    "batch"
                  ]
                },
                "description": "Push up to 50 contacts, businesses, business–contact links, extended fields, or health topics in one request.\n\nThis is the primary write path for CRM, PMS, and POS integrations syncing data into myne (for example guests from MEWS).\n\nSend top-level contact fields plus your `external_id`, and optionally `contact_extended` bodies for extra partner keys/metadata used later for lookup and enrichment.\n\nRecords are always stamped with your Custom API app name—do not send `source` (or `contact_source` / `business_source`) in item bodies.\n\nEach item has a `type` and body; see the request schema for supported types.\n\nSee glossary: Sync batch, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"items\": [\n    {\n      \"type\": \"contact\",\n      \"body\": {\n        \"external_id\": \"crm-contact-1001\",\n        \"email\": \"alex@example.com\",\n        \"first_name\": \"Alex\",\n        \"last_name\": \"Nguyen\",\n        \"location_id\": {{location_id}}\n      }\n    },\n    {\n      \"type\": \"business\",\n      \"body\": {\n        \"external_id\": \"crm-company-42\",\n        \"name\": \"Acme Hospitality\",\n        \"email\": \"ops@acme.example\"\n      }\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Invalid JSON body\"\n}"
            },
            {
              "name": "500 Unexpected server error.",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/brands/{{brand_id}}/sync/batch",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "brands",
                    "{{brand_id}}",
                    "sync",
                    "batch"
                  ]
                },
                "description": "Push up to 50 contacts, businesses, business–contact links, extended fields, or health topics in one request.\n\nThis is the primary write path for CRM, PMS, and POS integrations syncing data into myne (for example guests from MEWS).\n\nSend top-level contact fields plus your `external_id`, and optionally `contact_extended` bodies for extra partner keys/metadata used later for lookup and enrichment.\n\nRecords are always stamped with your Custom API app name—do not send `source` (or `contact_source` / `business_source`) in item bodies.\n\nEach item has a `type` and body; see the request schema for supported types.\n\nSee glossary: Sync batch, External source, external_id and external_data.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"items\": [\n    {\n      \"type\": \"contact\",\n      \"body\": {\n        \"external_id\": \"crm-contact-1001\",\n        \"email\": \"alex@example.com\",\n        \"first_name\": \"Alex\",\n        \"last_name\": \"Nguyen\",\n        \"location_id\": {{location_id}}\n      }\n    },\n    {\n      \"type\": \"business\",\n      \"body\": {\n        \"external_id\": \"crm-company-42\",\n        \"name\": \"Acme Hospitality\",\n        \"email\": \"ops@acme.example\"\n      }\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"message\": \"Something went wrong. Please try again later.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "OAuth",
      "item": [
        {
          "name": "Get an access token (this brand)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "token"
              ]
            },
            "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code !== 200) { return; }",
                  "const json = pm.response.json();",
                  "if (json.access_token) { pm.environment.set('access_token', json.access_token); }",
                  "if (json.brand_id != null) { pm.environment.set('brand_id', String(json.brand_id)); }",
                  "if (json.refresh_token) { pm.environment.set('refresh_token', json.refresh_token); }"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "Creating brand (no refresh token)",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"access_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\",\n  \"token_type\": \"Bearer\",\n  \"expires_in\": 3600,\n  \"brand_id\": 42\n}"
            },
            {
              "name": "Granted brand (includes refresh token)",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"access_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\",\n  \"token_type\": \"Bearer\",\n  \"expires_in\": 3600,\n  \"brand_id\": 99,\n  \"refresh_token\": \"rt_example\"\n}"
            },
            {
              "name": "Missing grant_type",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": \"invalid_request\",\n  \"error_description\": \"grant_type is required\"\n}"
            },
            {
              "name": "Code or refresh token rejected",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": \"invalid_grant\",\n  \"error_description\": \"Authorization code is invalid\"\n}"
            },
            {
              "name": "Unknown grant_type",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "Error",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": \"unsupported_grant_type\",\n  \"error_description\": \"grant_type must be client_credentials, authorization_code, or refresh_token\"\n}"
            },
            {
              "name": "401 invalid_client",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "Error",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": \"invalid_client\",\n  \"error_description\": \"Client authentication failed\"\n}"
            },
            {
              "name": "500 server_error",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/v1/token",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "token"
                  ]
                },
                "description": "Exchange API Credentials for a Connect access token. This route is on the Connect host only (`POST /v1/token`). Do not send a gateway JWT.\n\nJSON body is preferred. `client_id` and `client_secret` may also be sent as HTTP Basic on this call, or as `application/x-www-form-urlencoded`.\n\n- `grant_type=client_credentials` — creating brand only. No refresh token.\n- `grant_type=authorization_code` — requires `code` and `redirect_uri` (exact match). Returns `refresh_token`. Code cannot be reused. A second Allow for the same brand adds another refresh token; existing ones stay valid.\n- `grant_type=refresh_token` — requires `refresh_token`; issues a new access token and rotates only the refresh token you sent. Other refresh tokens for the same brand stay valid. Earlier access tokens stay valid until they expire.\n\nAccess tokens last 3600 seconds. Issuing another access token does not invalidate earlier ones. Use `Authorization: Bearer {access_token}` on resource routes. `brand_id` in the token body is the creating brand (client credentials) or the granted brand (authorization code / refresh).\n\nAuthorize (browser, staff admin login): `https://app.myne.network/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}`. PKCE S256 is accepted when `code_challenge` was sent on authorize.\n\nSee the **OAuth** section for the this-brand and other-brand walkthroughs.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"grant_type\": \"client_credentials\",\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "auth": {
                  "type": "noauth"
                }
              },
              "status": "Error",
              "code": 500,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"error\": \"server_error\",\n  \"error_description\": \"Token service is unavailable\"\n}"
            }
          ]
        }
      ]
    }
  ]
}
