> ## Documentation Index
> Fetch the complete documentation index at: https://docs.weve.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# Pontos de quem estuda

> Nível, conquistas, como ganhar e o extrato recente.



## OpenAPI

````yaml GET /v1/clubs/{clubId}/classroom/gamification
openapi: 3.0.3
info:
  title: weve API
  description: >
    Contrato entre a API Go e o dashboard. **Este arquivo é a fonte de
    verdade**:

    os tipos e a interface de servidor em Go, e o client TypeScript, são todos

    gerados daqui (`make openapi`). Handler que divergir da interface não
    compila.


    A superfície interna (`/internal/*`) fica de fora de propósito: é acesso de

    máquina, protegido por segredo dedicado, e não é contrato de cliente.
  version: 0.2.0
servers:
  - url: https://api.useweve.com
    description: produção
  - url: http://localhost:8080
    description: desenvolvimento
security: []
tags:
  - name: health
  - name: session
  - name: account
  - name: clubs
  - name: members
  - name: webhooks
  - name: outgoing-webhooks
  - name: sales-platforms
  - name: catalog
  - name: content
  - name: classroom
  - name: community
  - name: mentorships
  - name: agents
  - name: lives
  - name: students
  - name: auth
  - name: campaigns
  - name: workflows
  - name: email
  - name: exports
  - name: certificates
  - name: terms
  - name: mcp
  - name: gamification
  - name: support
  - name: help
paths:
  /v1/clubs/{clubId}/classroom/gamification:
    parameters:
      - $ref: '#/components/parameters/OrgId'
    get:
      tags:
        - gamification
      summary: Os pontos, o nível e as conquistas de quem estuda
      description: |
        Tudo o que a tela de pontos desenha, menos o ranking (que tem período e
        rota própria). Com a gamificação do club desligada responde
        `enabled: false` e nada mais — a tela e o item de menu não aparecem.

        As conquistas são um catálogo fixo, calculado do extrato: a décima aula
        é a décima linha de aula concluída. Só aparecem as das ações que valem
        ponto no club, mais as já conquistadas.
      operationId: getClassroomGamification
      responses:
        '200':
          description: Os pontos do aluno
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClassroomGamificationResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - studentSession: []
components:
  parameters:
    OrgId:
      name: clubId
      in: path
      required: true
      description: >
        Id público da organização — o mesmo que `GET /v1/me` devolve em

        `organization_id`.


        Na URL o recurso se chama **club**; no contrato e no domínio,
        organization.

        A divergência é deliberada: `clubs` é a palavra do produto, e a URL é o
        que

        as pessoas leem.


        É o identificador do provedor de autenticação, e é assim de propósito:

        o cliente precisa nomear a organização ao pedir o token, e o token é o

        que prova o escopo. Um id só nosso obrigaria a traduzir um no outro

        antes de ter um token — e a tradução exigiria uma chamada escopada, que

        é justamente a que ainda não dá para fazer.


        O uuid interno da organização não aparece no contrato: ele é o que as

        chaves estrangeiras do domínio referenciam, e continua sendo nosso.
      schema:
        type: string
        format: uuid
  schemas:
    ClassroomGamificationResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: '#/components/schemas/ClassroomGamification'
    ClassroomGamification:
      type: object
      required:
        - enabled
      properties:
        enabled:
          type: boolean
        ranking_visible:
          description: Se o club mostra o ranking aos alunos.
          type: boolean
        ranking_hidden:
          description: Se este aluno pediu para não aparecer no ranking dos colegas.
          type: boolean
        total:
          type: integer
        week:
          type: integer
        level:
          $ref: '#/components/schemas/LevelProgress'
        levels:
          type: array
          items:
            $ref: '#/components/schemas/GamificationLevel'
        rules:
          description: Como ganhar pontos — só as ações que valem ponto.
          type: array
          items:
            $ref: '#/components/schemas/GamificationRule'
        achievements:
          type: array
          items:
            $ref: '#/components/schemas/Achievement'
        recent:
          description: As últimas vinte linhas do extrato.
          type: array
          items:
            $ref: '#/components/schemas/PointEntry'
    ErrorEnvelope:
      type: object
      description: >-
        Envelope único de erro da API. O `code` é o contrato com o cliente — a
        `message` é diagnóstico, e pode mudar.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
          properties:
            code:
              type: string
            message:
              type: string
    LevelProgress:
      description: Onde o aluno está na escada.
      type: object
      required:
        - level
        - level_number
        - levels_count
        - next
        - points_to_next
        - progress
      properties:
        level:
          $ref: '#/components/schemas/GamificationLevel'
        level_number:
          description: A posição do nível na escada, a partir de 1.
          type: integer
        levels_count:
          type: integer
        next:
          allOf:
            - $ref: '#/components/schemas/GamificationLevel'
          nullable: true
          description: O próximo degrau; nulo no último.
        points_to_next:
          description: Quantos pontos faltam para o próximo; zero no último.
          type: integer
        progress:
          description: >-
            A fração do caminho entre o nível atual e o próximo, de 0 a 1; 1 no
            último.
          type: number
    GamificationLevel:
      type: object
      required:
        - name
        - min_points
      properties:
        id:
          description: |
            Estável enquanto o nível existir — as automações filtram por ele. Na
            troca da escada, o nível que vem com `id` é atualizado e o que vem
            sem é criado; o que não vier é apagado.
          type: string
          format: uuid
        name:
          type: string
          minLength: 1
          maxLength: 40
        min_points:
          description: A partir de quantos pontos o aluno está neste nível.
          type: integer
          minimum: 0
    GamificationRule:
      type: object
      required:
        - action
        - points
        - daily_cap
      properties:
        action:
          $ref: '#/components/schemas/PointAction'
        points:
          description: Quanto a ação vale. Zero é desligada.
          type: integer
          minimum: 0
          maximum: 1000
        daily_cap:
          description: >-
            Quantas vezes por dia a ação paga, quando há teto — o que evita que
            conversa vire fábrica de ponto. Fixo pela plataforma.
          type: integer
          nullable: true
    Achievement:
      description: Uma conquista do catálogo fixo.
      type: object
      required:
        - key
        - title
        - description
        - action
        - target
        - current
      properties:
        key:
          type: string
        title:
          type: string
        description:
          type: string
        action:
          $ref: '#/components/schemas/PointAction'
        target:
          description: Quantas vezes a ação leva à conquista.
          type: integer
        current:
          description: Quantas vezes o aluno já fez, até o alvo.
          type: integer
        earned_at:
          description: Quando conquistou. Ausente se ainda não.
          type: string
          format: date-time
    PointEntry:
      description: Uma linha do extrato.
      type: object
      required:
        - id
        - action
        - points
        - created_at
      properties:
        id:
          type: string
          format: uuid
        action:
          $ref: '#/components/schemas/PointAction'
        points:
          description: Negativo só em ajuste.
          type: integer
        title:
          description: >-
            O nome do que gerou o ponto (a aula, o curso, a live, o post).
            Ausente no ajuste, no post sem título e quando a origem foi apagada.
          type: string
        note:
          description: O motivo do ajuste.
          type: string
        created_at:
          type: string
          format: date-time
    PointAction:
      description: |
        O que gera ponto. Todas são disparadas pela plataforma, uma vez por
        origem: `lesson_completed` (a primeira conclusão da aula),
        `course_completed` (a última aula publicada do curso),
        `quiz_passed` (a primeira aprovação no quiz do bloco),
        `assignment_approved` (a entrega aprovada pela equipe),
        `comment_posted` (comentário publicado numa aula, até cinco por dia),
        `post_published` (post na comunidade, até cinco por dia) e
        `live_attended` (entrar numa live). `adjustment` é o ajuste à mão
        da equipe e só aparece no extrato.
      type: string
      enum:
        - lesson_completed
        - course_completed
        - quiz_passed
        - assignment_approved
        - comment_posted
        - post_published
        - live_attended
        - adjustment
  responses:
    Unauthorized:
      description: Sessão ausente, expirada ou revogada
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Forbidden:
      description: >
        A sessão é válida, mas não age nesta organização. É a mesma resposta
        para

        uma organização que não existe — distinguir as duas deixaria enumerar

        organizações alheias.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    InternalError:
      description: >-
        Falha inesperada. O corpo nunca traz o erro real — ele fica no log e no
        rastreamento.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  securitySchemes:
    studentSession:
      type: http
      scheme: bearer
      description: |
        Token OPACO de sessão de aluno, emitido por `/v1/auth/sign-in` e
        verificado contra a nossa tabela — não é JWT e não se lê nada dele.

        A ida ao banco não é custo novo: toda requisição autenticada já resolve
        o dono da sessão. Em troca, encerrar uma sessão vale no mesmo instante,
        sem lista de bloqueio nem janela de tolerância.

        O classroom o guarda em cookie **host-only**: um cookie de domínio o
        mandaria para os subdomínios dos outros clubs.

````