{
  "openapi": "3.0.3",
  "info": {
    "title": "Iaqui Gateway API",
    "description": "# Reference Manual & Integration Guide\n\nIaqui Gateway is an enterprise-grade, decoupled Messaging Infrastructure as a Service (IaaS) for Meta official APIs (WhatsApp Business Cloud API, Instagram Graph API, Facebook Messenger API).\n\n## 🏛️ Multi-Tenant SaaS Architecture\nTo support multi-company CRM systems (e.g., Whatsaky), Iaqui Gateway enforces strict client isolation:\n1. **Create Customer**: Register a client tenant via `POST /v1/customers`. Keep track of the returned `customerId`.\n2. **Generate Setup Link**: Request an onboarding link via `POST /v1/setup-links` for that customer.\n3. **User Onboarding**: Redirect the client to the generated URL. This opens the Meta Embedded Signup popup, allowing them to select their WABA and numbers.\n4. **Discovery & Connection**: The Gateway automatically exchanges the authorization code for a long-lived System User Access Token, discovers active phone IDs, registers webhook event listeners, and configures the channel automatically.\n\n## 🔑 Meta Tech Provider & Coexistence\n- **Embedded Signup**: Customers authenticate directly with Facebook Login. The Gateway handles all secure token exchanges.\n- **Coexistence**: Phone numbers previously on other BSPs or mobile business apps migrate in-fight using Meta's OTP verification during signup without downtime.\n- **WABA Management**: The customer retains ownership of their WhatsApp Business Account, while the Gateway acts as the official Tech Provider to query and send messages.\n\n## 📥 Real-time Webhook Events\nWhen registering a webhook using `POST /v1/webhooks`, you will receive JSON payloads for the following events:\n- `message.received`: Emitted when an end-user sends text, quick replies, lists, flows, or multimedia.\n- `message.status`: Emitted as messages transition through `sent`, `delivered`, `read`, or `failed` statuses.\n- `template.status_changed`: Emitted when Meta reviews and updates a template status (`APPROVED`, `REJECTED`, `SUSPENDED`).\n\n## ⚡ Rate Limits, Queues & Retries\n- **Throttling**: The gateway queues requests using Redis & BullMQ to avoid hitting Meta rate limits (standard limit is 100 req/sec per channel).\n- **Auto-Retries**: Retries are handled with exponential backoff on transient Meta errors (e.g., rate limit code 131301).\n\n## 🔄 Versioning Policy\n- **Gateway Version**: Locked to `/v1` namespace. Breaking changes will trigger `/v2` release.\n- **Meta Cloud API Version**: Decoupled. Currently translating schemas to Meta Graph v24.0 internally.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "/v1",
      "description": "Iaqui Gateway Production Server"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key",
        "description": "Enter your Master API Key starting with 'iq_live_' inside the Bearer authorization field."
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/auth/register": {
      "post": {
        "summary": "Register Tenant Account / Registrar Cuenta",
        "description": "Registers a new master developer/tenant account on the gateway.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string", "example": "Whatsaky SaaS" },
                  "email": { "type": "string", "example": "dev@whatsaky.com" },
                  "password": { "type": "string", "example": "secure_password_123" }
                },
                "required": ["name", "email", "password"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "message": { "type": "string" },
                    "accountId": { "type": "string" },
                    "name": { "type": "string" },
                    "email": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/keys": {
      "post": {
        "summary": "Generate API Key / Generar API Key",
        "description": "Generates a new secure random API Key prefixed with `iq_live_` for the authenticated developer account.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keyName": { "type": "string", "example": "Production Key" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created Key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "apiKey": { "type": "string", "example": "iq_live_5afb32..." },
                    "name": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List API Keys / Listar API Keys",
        "description": "Retrieves metadata of all API keys associated with the account.",
        "responses": {
          "200": { "description": "OK" }
        }
      }
    },
    "/auth/onboard/channel": {
      "post": {
        "summary": "Manual Channel Onboarding / Configurar Canal Manual",
        "description": "Directly registers a Meta channel (WhatsApp, Instagram, Facebook) providing raw Meta access tokens (mostly used for debugging/sandbox).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": { "type": "string", "example": "iq_chan_client_new" },
                  "type": { "type": "string", "enum": ["WHATSAPP", "INSTAGRAM", "FACEBOOK"], "example": "WHATSAPP" },
                  "name": { "type": "string", "example": "Main Support Line" },
                  "systemUserAccessToken": { "type": "string", "example": "EAAQ3d8..." },
                  "wabaId": { "type": "string", "example": "89234802934" },
                  "phoneId": { "type": "string", "example": "82394829384" }
                },
                "required": ["id", "type", "name", "systemUserAccessToken"]
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Channel manually onboarded successfully" }
        }
      }
    },
    "/auth/channels": {
      "get": {
        "summary": "List Channels / Listar Canales",
        "description": "Lists all onboarded channels (WhatsApp, Instagram, Messenger) under the developer's account.",
        "responses": {
          "200": { "description": "OK" }
        }
      }
    },
    "/messages": {
      "post": {
        "summary": "Send Message / Enviar Mensaje",
        "description": "Enqueues and sends text, interactive buttons, lists, templates, or media files to WhatsApp, Messenger, or Instagram.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "channelId": { "type": "string", "example": "iq_chan_wa_soporte" },
                  "channelType": { "type": "string", "enum": ["WHATSAPP", "INSTAGRAM", "FACEBOOK"], "example": "WHATSAPP" },
                  "to": { "type": "string", "example": "5215512345678" },
                  "type": { "type": "string", "enum": ["text", "template", "interactive"], "example": "text" },
                  "text": { "type": "string", "example": "¡Hola! Bienvenido al Gateway. 🚀" },
                  "template": {
                    "type": "object",
                    "properties": {
                      "name": { "type": "string", "example": "factura_disponible_cta" },
                      "language": {
                        "type": "object",
                        "properties": {
                          "code": { "type": "string", "example": "es" }
                        }
                      },
                      "components": {
                        "type": "array",
                        "items": { "type": "object" }
                      }
                    }
                  },
                  "interactive": {
                    "type": "object",
                    "properties": {
                      "type": { "type": "string", "enum": ["button", "list", "flow"] }
                    }
                  }
                },
                "required": ["channelId", "channelType", "to", "type"]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted in delivery queue",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "message": { "type": "string", "example": "Message accepted and enqueued for delivery." },
                    "messageId": { "type": "string", "example": "msg_iq_chan_wa_soporte_178239" }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List Messages / Historial",
        "description": "Queries historical messages, filtering by channel, customer, direction, or status.",
        "parameters": [
          { "name": "channelId", "in": "query", "schema": { "type": "string" } },
          { "name": "customerId", "in": "query", "schema": { "type": "string" } },
          { "name": "direction", "in": "query", "schema": { "type": "string", "enum": ["INBOUND", "OUTBOUND"] } },
          { "name": "status", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } }
        ],
        "responses": {
          "200": {
            "description": "List of messages",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "messages": {
                      "type": "array",
                      "items": { "type": "object" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/customers": {
      "post": {
        "summary": "Create Customer / Crear Cliente",
        "description": "Registers a new tenant/client under your SaaS account.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string", "example": "Clínica DentalCare" },
                  "email": { "type": "string", "example": "contacto@dentalcare.com" },
                  "externalId": { "type": "string", "example": "client_crm_98234" }
                },
                "required": ["name"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created Customer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "customer": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "example": "cust-uuid-12345" },
                        "name": { "type": "string" },
                        "email": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List Customers / Listar Clientes",
        "description": "Retrieves the collection of all customers registered under your developer account.",
        "responses": {
          "200": { "description": "OK" }
        }
      }
    },
    "/setup-links": {
      "post": {
        "summary": "Generate Setup Link / Enlace de Registro",
        "description": "Generates a temporary secure link for Meta's Embedded Signup OAuth pop-up redirection.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customerId": { "type": "string", "example": "cust-uuid-12345" },
                  "redirectUrl": { "type": "string", "example": "https://whatsaky.com/onboard/callback" },
                  "expiresInHours": { "type": "integer", "default": 24 }
                },
                "required": ["customerId"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created Setup Link",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "setupLink": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "token": { "type": "string" },
                        "url": { "type": "string", "example": "https://gateway.iaqui.com/setup/abc123token" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/templates": {
      "post": {
        "summary": "Create Template / Crear Plantilla",
        "description": "Registers a template structure in Meta and waits for approval.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "channelId": { "type": "string", "example": "iq_chan_wa_soporte" },
                  "name": { "type": "string", "example": "factura_disponible_cta" },
                  "language": { "type": "string", "example": "es" },
                  "category": { "type": "string", "enum": ["UTILITY", "AUTHENTICATION", "MARKETING"], "example": "UTILITY" },
                  "components": {
                    "type": "array",
                    "items": { "type": "object" },
                    "example": [
                      {
                        "type": "BODY",
                        "text": "Hola {{1}}, tu factura de {{2}} ya está lista."
                      }
                    ]
                  }
                },
                "required": ["channelId", "name", "language", "category", "components"]
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Template submitted for Meta review" }
        }
      },
      "get": {
        "summary": "List Templates / Listar Plantillas",
        "description": "Returns templates stored in the database. Use query param `sync=true` to fetch and sync from Meta's API first.",
        "parameters": [
          { "name": "channelId", "in": "query", "schema": { "type": "string" } },
          { "name": "sync", "in": "query", "schema": { "type": "string", "enum": ["true", "false"] } }
        ],
        "responses": {
          "200": { "description": "OK" }
        }
      }
    },
    "/templates/{name}": {
      "delete": {
        "summary": "Delete Template / Eliminar Plantilla",
        "description": "Removes a template from the database and Meta.",
        "parameters": [
          { "name": "name", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channelId", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Deleted successfully" }
        }
      }
    },
    "/webhooks": {
      "post": {
        "summary": "Register Webhook / Registrar Webhook",
        "description": "Registers a URL where you will receive normalized events in real-time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": { "type": "string", "example": "https://api.my-crm.com/v1/events" },
                  "events": {
                    "type": "array",
                    "items": { "type": "string" },
                    "example": ["message.received", "message.status", "template.status_changed"]
                  },
                  "secret": { "type": "string", "example": "my_secure_secret_key" }
                },
                "required": ["url", "events"]
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Registered Webhook" }
        },
        "callbacks": {
          "webhookCallback": {
            "{$request.body#/url}": {
              "post": {
                "summary": "Incoming Webhook Deliveries / Entrega de Webhook",
                "description": "The Gateway posts events to your registered URL when events occur.",
                "requestBody": {
                  "required": true,
                  "content": {
                    "application/json": {
                      "schema": {
                        "oneOf": [
                          {
                            "type": "object",
                            "title": "Message Received Event",
                            "properties": {
                              "event": { "type": "string", "example": "message.received" },
                              "channel": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "iq_chan_wa_soporte" },
                                  "type": { "type": "string", "example": "WHATSAPP" }
                                }
                              },
                              "contact": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "5215512345678" },
                                  "name": { "type": "string", "example": "Luis Gomez" }
                                }
                              },
                              "message": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "wamid.HBgNNTIxNTUxMjM0NTY3OBUAgbf..." },
                                  "type": { "type": "string", "example": "text" },
                                  "text": { "type": "string", "example": "Hola, necesito ayuda 🚀" },
                                  "timestamp": { "type": "integer", "example": 1782398402 }
                                }
                              }
                            }
                          },
                          {
                            "type": "object",
                            "title": "Message Status Changed Event",
                            "properties": {
                              "event": { "type": "string", "example": "message.status" },
                              "channel": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "iq_chan_wa_soporte" }
                                }
                              },
                              "message": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "msg_iq_chan_wa_soporte_1782" },
                                  "status": { "type": "string", "enum": ["sent", "delivered", "read", "failed"], "example": "read" },
                                  "recipient": { "type": "string", "example": "5215512345678" },
                                  "timestamp": { "type": "integer", "example": 1782398412 },
                                  "error": { "type": "string", "nullable": true, "example": null }
                                }
                              }
                            }
                          },
                          {
                            "type": "object",
                            "title": "Template Status Updated Event",
                            "properties": {
                              "event": { "type": "string", "example": "template.status_changed" },
                              "channel": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "iq_chan_wa_soporte" }
                                }
                              },
                              "template": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "example": "893472093847029" },
                                  "name": { "type": "string", "example": "factura_disponible_cta" },
                                  "oldStatus": { "type": "string", "example": "PENDING" },
                                  "newStatus": { "type": "string", "example": "APPROVED" }
                                }
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Your server acknowledged receipt successfully."
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List Webhooks / Listar Webhooks",
        "responses": {
          "200": { "description": "OK" }
        }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "summary": "Test Webhook / Diagnóstico",
        "description": "Dispatches a mock event payload immediately to test latency and server code response.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "OK" }
        }
      }
    },
    "/webhook-deliveries": {
      "get": {
        "summary": "List Webhook Deliveries / Bitácora de Envíos",
        "description": "Queries historical webhooks dispatched by the Gateway, reporting latencies, payloads, and response HTTP status codes.",
        "parameters": [
          { "name": "webhookId", "in": "query", "schema": { "type": "string" } },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["SUCCESS", "FAILED"] } }
        ],
        "responses": {
          "200": { "description": "OK" }
        }
      }
    }
  }
}
