{
  "info": {
    "name": "WingsFlow API v1",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://YOUR_WINGSFLOW_HOST/v1"
    },
    {
      "key": "api_key",
      "value": ""
    },
    {
      "key": "idempotency_key",
      "value": ""
    },
    {
      "key": "resource_version",
      "value": ""
    },
    {
      "key": "external_id",
      "value": ""
    },
    {
      "key": "contact_id",
      "value": ""
    },
    {
      "key": "template_id",
      "value": ""
    },
    {
      "key": "message_id",
      "value": ""
    },
    {
      "key": "event_id",
      "value": ""
    },
    {
      "key": "subscription_id",
      "value": ""
    },
    {
      "key": "delivery_id",
      "value": ""
    },
    {
      "key": "channel_id",
      "value": ""
    },
    {
      "key": "version",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "getIdentity",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/me",
        "description": "P0. Any valid API key. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "listChannels",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/channels",
        "description": "P0. Requires channels:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "upsertExternalContact",
      "request": {
        "method": "PUT",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/contact-identities/{{external_id}}",
        "description": "P0. Requires contacts:write. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"phone\": \"+919876543210\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "getContact",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/contacts/{{contact_id}}",
        "description": "P0. Requires contacts:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "recordConsent",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/contacts/{{contact_id}}/consents",
        "description": "P0. Requires consents:write. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"purpose\": \"service\",\n  \"action\": \"opt_in\",\n  \"source\": \"example\",\n  \"evidence_reference\": \"example\",\n  \"occurred_at\": \"2026-09-14T06:30:00Z\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "listTemplates",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/templates?channel_id={{channel_id}}",
        "description": "P0. Requires templates:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "getTemplate",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/templates/{{template_id}}?channel_id={{channel_id}}&version={{version}}",
        "description": "P0. Requires templates:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "queueMessage",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/messages",
        "description": "P0. Requires messages:write. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"channel_id\": \"11111111-1111-4111-8111-111111111111\",\n  \"contact_id\": \"11111111-1111-4111-8111-111111111111\",\n  \"client_reference\": \"example\",\n  \"message\": {\n    \"type\": \"text\",\n    \"conversation_id\": \"11111111-1111-4111-8111-111111111111\",\n    \"text\": \"example\"\n  }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "getMessage",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/messages/{{message_id}}",
        "description": "P0. Requires messages:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "ingestEvent",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/events",
        "description": "P0. Requires events:write. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Inline customer additionally requires contacts:write. Event receipt does not imply a matching action or WhatsApp delivery. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"source_event_id\": \"storefront:order:ORD-123:created:v1\",\n  \"event\": \"order.created\",\n  \"schema_version\": \"1\",\n  \"occurred_at\": \"2026-09-14T06:30:00Z\",\n  \"contact_id\": \"11111111-1111-4111-8111-111111111111\",\n  \"data\": {\n    \"order_id\": \"ORD-123\",\n    \"aggregate_version\": 1,\n    \"amount_minor\": 2500000,\n    \"currency\": \"INR\"\n  },\n  \"correlation_id\": \"order:ORD-123\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "getEvent",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/events/{{event_id}}",
        "description": "P0. Requires events:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "listSubscriptions",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/webhook-subscriptions",
        "description": "P0. Requires webhooks:read. Read is tenant and grant scoped. Subscription event scopes and grants are rechecked. Signing secrets use protected one-hour encrypted response recovery; later replay returns secret_response_expired. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "createSubscription",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/webhook-subscriptions",
        "description": "P0. Requires webhooks:manage. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Subscription event scopes and grants are rechecked. Signing secrets use protected one-hour encrypted response recovery; later replay returns secret_response_expired. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"url\": \"https://merchant.example/hooks/wingsflow\",\n  \"events\": [\n    \"message.received\"\n  ],\n  \"schema_version\": \"1\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "updateSubscription",
      "request": {
        "method": "PATCH",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "If-Match",
            "value": "\"{{resource_version}}\""
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/webhook-subscriptions/{{subscription_id}}",
        "description": "P0. Requires webhooks:manage. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Subscription event scopes and grants are rechecked. Signing secrets use protected one-hour encrypted response recovery; later replay returns secret_response_expired. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"enabled\": true\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "rotateSubscriptionSecret",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/webhook-subscriptions/{{subscription_id}}/rotate-secret",
        "description": "P0. Requires webhooks:manage. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Subscription event scopes and grants are rechecked. Signing secrets use protected one-hour encrypted response recovery; later replay returns secret_response_expired. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"overlap_seconds\": 0\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "listDeliveries",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/webhook-deliveries",
        "description": "P0. Requires webhooks:read. Read is tenant and grant scoped. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery."
      }
    },
    {
      "name": "replayDelivery",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Accept",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{idempotency_key}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/webhook-deliveries/{{delivery_id}}/replay",
        "description": "P0. Requires webhooks:manage. Every mutation requires Idempotency-Key; seven-day response retention, current authorization rechecked. Set path variables and keep the same idempotency key and exact body for retries. A 202 response is admission, not delivery.",
        "body": {
          "mode": "raw",
          "raw": "{}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "if (pm.request.method !== 'GET' && !pm.variables.get('idempotency_key')) { throw new Error('Set and persist idempotency_key for this logical operation before sending. Reuse it only for identical retries.'); }"
        ]
      }
    }
  ]
}
