{
  "openapi": "3.1.0",
  "info": {
    "title": "PeruOTP API",
    "version": "1.0.0",
    "description": "OTP SMS Perú. Token de servidor. Solo plantillas aprobadas."
  },
  "servers": [
    {
      "url": "https://api.peruotp.com",
      "description": "API de producción PeruOTP"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "schemas": {
      "Receipt": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "state": {
            "type": "string"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/otp": {
      "post": {
        "summary": "Generar OTP o enviar código propio",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "phone",
                  "template_id"
                ],
                "properties": {
                  "phone": {
                    "type": "string",
                    "pattern": "^\\+519[0-9]{8}$"
                  },
                  "template_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "code": {
                    "type": "string",
                    "pattern": "^[0-9]{4,8}$",
                    "description": "Opcional. Si se aporta, lo verifica el integrador."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Datos, saldo, plantilla o límites inválidos"
          },
          "401": {
            "description": "Token inválido"
          },
          "403": {
            "description": "Cuenta no habilitada"
          },
          "429": {
            "description": "Límite de solicitudes excedido"
          },
          "202": {
            "description": "En cola o solicitud idempotente existente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "409": {
            "description": "Clave usada con otro cuerpo"
          }
        }
      }
    },
    "/v1/otp/{id}/verify": {
      "post": {
        "summary": "Verificar OTP generado por PeruOTP; hasta cinco intentos",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "pattern": "^[0-9]{4,8}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Datos, saldo, plantilla o límites inválidos"
          },
          "401": {
            "description": "Token inválido"
          },
          "403": {
            "description": "Cuenta no habilitada"
          },
          "429": {
            "description": "Límite de solicitudes excedido"
          },
          "200": {
            "description": "Resultado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/messages/{id}": {
      "get": {
        "summary": "Estado de un envío propio",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Datos, saldo, plantilla o límites inválidos"
          },
          "401": {
            "description": "Token inválido"
          },
          "403": {
            "description": "Cuenta no habilitada"
          },
          "429": {
            "description": "Límite de solicitudes excedido"
          },
          "200": {
            "description": "Arreglo de cero o un mensaje; sent no garantiza entrega"
          }
        }
      }
    },
    "/v1/templates": {
      "get": {
        "summary": "Plantillas de la cuenta y globales aprobadas",
        "responses": {
          "400": {
            "description": "Datos, saldo, plantilla o límites inválidos"
          },
          "401": {
            "description": "Token inválido"
          },
          "403": {
            "description": "Cuenta no habilitada"
          },
          "429": {
            "description": "Límite de solicitudes excedido"
          },
          "200": {
            "description": "Arreglo de plantillas: id, name, body, status"
          }
        }
      }
    }
  }
}
