{
  "openapi": "3.0.3",
  "info": {
    "title": "Partner Integration API",
    "description": "API de integração para assessorias esportivas e academias. Permite sincronização de alunos e registro de check-ins.",
    "version": "v1",
    "contact": {
      "name": "Suporte Partner Integration",
      "email": "suporte@seudominio.com"
    }
  },
  "servers": [
    {
      "url": "https://api-homolog.seudominio.com",
      "description": "Homologação"
    },
    {
      "url": "https://api.seudominio.com",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/auth/token": {
      "post": {
        "tags": ["Auth"],
        "summary": "Obter token JWT",
        "description": "Autentica o tenant com ClientId e ClientSecret e retorna um JWT Bearer Token. Utilize o accessToken retornado no header Authorization de todas as demais requisições.",
        "operationId": "PostAuthToken",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthTokenRequest"
              },
              "example": {
                "clientId": "sua-assessoria",
                "clientSecret": "sua-senha-secreta"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token obtido com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthTokenResponse"
                },
                "example": {
                  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "tokenType": "Bearer",
                  "expiresIn": 3600
                }
              }
            }
          },
          "401": {
            "description": "ClientId ou ClientSecret inválidos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Campos obrigatórios ausentes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/students/sync": {
      "post": {
        "tags": ["Students"],
        "summary": "Sincronização incremental de alunos",
        "description": "Sincroniza apenas os alunos informados no payload. Use para enviar novos alunos ou atualizar/desativar alunos existentes. Idempotente: re-enviar os mesmos alunos é seguro.",
        "operationId": "PostStudentsSync",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncStudentsRequest"
              },
              "example": {
                "students": [
                  {
                    "canonicalStudentId": "ALUNO-001",
                    "wellhubMemberId": null,
                    "totalPassMemberId": null,
                    "status": "ACTIVE"
                  },
                  {
                    "canonicalStudentId": "ALUNO-002",
                    "wellhubMemberId": "WH-MEMBER-98765",
                    "totalPassMemberId": null,
                    "status": "ACTIVE"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sincronização realizada com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncStudentsResponse"
                },
                "example": {
                  "total": 2,
                  "created": 1,
                  "updated": 1,
                  "deactivated": 0,
                  "results": [
                    {
                      "studentIdentityId": "550e8400-e29b-41d4-a716-446655440001",
                      "canonicalStudentId": "ALUNO-001",
                      "action": "CREATED"
                    },
                    {
                      "studentIdentityId": "550e8400-e29b-41d4-a716-446655440002",
                      "canonicalStudentId": "ALUNO-002",
                      "action": "UPDATED"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Token ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Payload inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/students/sync/full": {
      "post": {
        "tags": ["Students"],
        "summary": "Full Sync de alunos",
        "description": "Sincroniza todos os alunos informados no payload. Use na primeira implantação ou para garantir consistência total. Comportamento idêntico ao Sync Incremental por aluno.",
        "operationId": "PostStudentsSyncFull",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncStudentsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sincronização realizada com sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncStudentsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Token ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Payload inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/checkins": {
      "post": {
        "tags": ["Checkins"],
        "summary": "Registrar check-in",
        "description": "Registra um check-in na plataforma. Retorna 201 para novos registros e 200 para requisições duplicadas (idempotência via partnerTransactionId). O campo isDuplicate=true indica que o partnerTransactionId já foi processado — o check-in não é reprocessado.",
        "operationId": "PostCheckin",
        "parameters": [
          {
            "name": "X-Correlation-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "ID de rastreabilidade customizado. Se não informado, a plataforma gera um automaticamente."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReceiveCheckinRequest"
              },
              "example": {
                "source": "INTERNAL",
                "partnerTransactionId": "TXN-2026-07-03-001",
                "externalStudentId": "ALUNO-001",
                "occurredAt": "2026-07-03T08:30:00Z"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Check-in registrado com sucesso (novo)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckinCreatedResponse"
                },
                "example": {
                  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                  "isDuplicate": false
                }
              }
            }
          },
          "200": {
            "description": "Check-in duplicado detectado — não reprocessado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckinCreatedResponse"
                },
                "example": {
                  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                  "isDuplicate": true
                }
              }
            }
          },
          "401": {
            "description": "Token ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Tenant não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 404,
                  "title": "TENANT_NOT_FOUND",
                  "detail": "Tenant não encontrado."
                }
              }
            }
          },
          "422": {
            "description": "Payload inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/checkins/{id}": {
      "get": {
        "tags": ["Checkins"],
        "summary": "Consultar check-in",
        "description": "Consulta os detalhes e o status de um check-in pelo seu identificador único. O campo status indica o resultado do processamento: PUBLISHED (aprovado), REJECTED (negado). Em caso de rejeição, o campo rejectionReason indica o motivo.",
        "operationId": "GetCheckinById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "ID do check-in retornado pelo POST /api/v1/checkins"
          }
        ],
        "responses": {
          "200": {
            "description": "Check-in encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckinDetailResponse"
                },
                "examples": {
                  "published": {
                    "summary": "Check-in aprovado",
                    "value": {
                      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                      "tenantId": "1a2b3c4d-0000-0000-0000-000000000001",
                      "source": "Internal",
                      "status": "PUBLISHED",
                      "partnerTransactionId": "TXN-2026-07-03-001",
                      "correlationId": "2b3c4d5e-aaaa-bbbb-cccc-000000000002",
                      "occurredAt": "2026-07-03T08:30:00Z",
                      "receivedAt": "2026-07-03T08:30:01.234Z",
                      "rejectionReason": null
                    }
                  },
                  "rejected": {
                    "summary": "Check-in rejeitado",
                    "value": {
                      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                      "tenantId": "1a2b3c4d-0000-0000-0000-000000000001",
                      "source": "Internal",
                      "status": "REJECTED",
                      "partnerTransactionId": "TXN-2026-07-03-999",
                      "correlationId": "2b3c4d5e-aaaa-bbbb-cccc-000000000003",
                      "occurredAt": "2026-07-03T09:00:00Z",
                      "receivedAt": "2026-07-03T09:00:01.100Z",
                      "rejectionReason": "STUDENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Token ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Check-in não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 404,
                  "title": "CHECKIN_NOT_FOUND",
                  "detail": "Check-in não encontrado."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token JWT obtido via POST /api/v1/auth/token"
      }
    },
    "schemas": {
      "AuthTokenRequest": {
        "type": "object",
        "required": ["clientId", "clientSecret"],
        "properties": {
          "clientId": {
            "type": "string",
            "description": "Identificador do tenant, fornecido no onboarding"
          },
          "clientSecret": {
            "type": "string",
            "description": "Senha de autenticação, fornecida no onboarding"
          }
        }
      },
      "AuthTokenResponse": {
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string",
            "description": "Token JWT para usar no header Authorization"
          },
          "tokenType": {
            "type": "string",
            "example": "Bearer",
            "description": "Sempre 'Bearer'"
          },
          "expiresIn": {
            "type": "integer",
            "example": 3600,
            "description": "Validade em segundos"
          }
        }
      },
      "SyncStudentItem": {
        "type": "object",
        "required": ["canonicalStudentId", "status"],
        "properties": {
          "canonicalStudentId": {
            "type": "string",
            "maxLength": 200,
            "description": "Identificador único do aluno no sistema do cliente. Mesmo valor usado em externalStudentId nos check-ins INTERNAL."
          },
          "wellhubMemberId": {
            "type": "string",
            "nullable": true,
            "description": "ID do aluno no Wellhub. Omitir ou null se não aplicável."
          },
          "totalPassMemberId": {
            "type": "string",
            "nullable": true,
            "description": "ID do aluno no TotalPass. Omitir ou null se não aplicável."
          },
          "status": {
            "type": "string",
            "enum": ["ACTIVE", "INACTIVE"],
            "description": "ACTIVE ativa o aluno; INACTIVE o desativa (histórico preservado)."
          }
        }
      },
      "SyncStudentsRequest": {
        "type": "object",
        "required": ["students"],
        "properties": {
          "students": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SyncStudentItem"
            },
            "description": "Lista de alunos a sincronizar"
          }
        }
      },
      "SyncStudentResult": {
        "type": "object",
        "properties": {
          "studentIdentityId": {
            "type": "string",
            "format": "uuid",
            "description": "ID interno do aluno na plataforma"
          },
          "canonicalStudentId": {
            "type": "string",
            "description": "ID do aluno no sistema do cliente (espelho do enviado)"
          },
          "action": {
            "type": "string",
            "enum": ["CREATED", "UPDATED", "DEACTIVATED"],
            "description": "Ação realizada pela plataforma"
          }
        }
      },
      "SyncStudentsResponse": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total de alunos processados"
          },
          "created": {
            "type": "integer",
            "description": "Novos alunos cadastrados"
          },
          "updated": {
            "type": "integer",
            "description": "Alunos existentes atualizados"
          },
          "deactivated": {
            "type": "integer",
            "description": "Alunos desativados"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SyncStudentResult"
            }
          }
        }
      },
      "ReceiveCheckinRequest": {
        "type": "object",
        "required": ["source", "partnerTransactionId", "externalStudentId", "occurredAt"],
        "properties": {
          "source": {
            "type": "string",
            "enum": ["INTERNAL"],
            "description": "Origem do check-in. Nesta etapa, sempre INTERNAL."
          },
          "partnerTransactionId": {
            "type": "string",
            "description": "Identificador único da transação no sistema do cliente. Chave de idempotência."
          },
          "externalStudentId": {
            "type": "string",
            "description": "ID do aluno conforme enviado em canonicalStudentId na sincronização."
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "description": "Data e hora do check-in em UTC (ISO 8601)."
          }
        }
      },
      "CheckinCreatedResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identificador do check-in na plataforma"
          },
          "isDuplicate": {
            "type": "boolean",
            "description": "true se este partnerTransactionId já foi processado anteriormente"
          }
        }
      },
      "CheckinDetailResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tenantId": {
            "type": "string",
            "format": "uuid"
          },
          "source": {
            "type": "string",
            "example": "Internal"
          },
          "status": {
            "type": "string",
            "enum": ["RECEIVED", "PUBLISHED", "REJECTED"]
          },
          "partnerTransactionId": {
            "type": "string"
          },
          "correlationId": {
            "type": "string"
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rejectionReason": {
            "type": "string",
            "nullable": true,
            "enum": ["STUDENT_NOT_FOUND", "STUDENT_INACTIVE", "STUDENT_SUSPENDED", "AUTHORIZATION_EXPIRED", null]
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          },
          "correlationId": {
            "type": "string"
          }
        }
      },
      "ValidationProblemDetails": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "example": 422
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": {
              "source": ["O campo 'source' é obrigatório."]
            }
          }
        }
      }
    }
  }
}
