{
  "openapi": "3.0.2",
  "info": {
    "title": "API pública de parceiros TiqueTaque",
    "version": "1",
    "description": "<h2>Autenticação</h2>\n  Para todas as requisições, exceto a geração de token, é necessária a autenticação com um token JWT\n  de parceiro, enviado no header <code>Authorization: Bearer &ltseu_token&gt</code>.<br>\n  O token é obtido através do endpoint <code>POST /tokens</code> desta API, utilizando as credenciais\n  de um usuário do portal de parceiros. A resposta contém o campo <code>token</code> a ser usado\n  nas requisições.\n<h2>Rate limiting</h2>\n  Requisições são limitadas a 60 requisições por janela deslizante de 1 minuto.\n  Se o limite for excedido, será retornada uma resposta HTTP <code>429 Too Many Requests</code>.<br>\n"
  },
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "servers": [
    {
      "url": "https://api.tiquetaque.com/partners/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Autenticação",
      "description": "Geração de token de acesso à API de parceiros."
    },
    {
      "name": "Contas",
      "description": "Operações sobre as contas criadas pelo parceiro."
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "IsoDateTimeTzModel": {
        "type": "string",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+-][0-2]\\d:[0-5]\\d$",
        "example": "2026-01-01T00:00:00+00:00"
      },
      "PartnerAccountModel": {
        "type": "object",
        "properties": {
          "_id": {
            "description": "Identificador único da conta, gerado internamente.",
            "type": "string",
            "example": "5f5bc225b511a6edec2891f7"
          },
          "_created": {
            "$ref": "#/components/schemas/IsoDateTimeTzModel"
          },
          "name": {
            "description": "Nome do empregador vinculado à conta.",
            "type": "string",
            "nullable": true,
            "example": "TIQUETAQUE SERVICOS DE TECNOLOGIA S.A."
          },
          "financial_email": {
            "description": "E-mail do setor financeiro do empregador vinculado à conta.",
            "type": "string",
            "nullable": true,
            "example": "financeiro@empresa.com"
          },
          "cnpj": {
            "description": "CNPJ do empregador vinculado à conta. Apenas números.",
            "type": "string",
            "nullable": true,
            "example": "23467093000164"
          },
          "active_employees": {
            "description": "Número de funcionários ativos da conta.",
            "type": "integer",
            "example": 12
          },
          "subscription_employees": {
            "description": "Número de funcionários contratados nas assinaturas da conta.",
            "type": "integer",
            "example": 15
          },
          "subscription_face_ids": {
            "description": "Número de reconhecimentos faciais contratados na assinatura ativa da conta.",
            "type": "integer",
            "example": 5
          }
        }
      },
      "PartnerAccountDetailModel": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PartnerAccountModel"
          },
          {
            "type": "object",
            "properties": {
              "api_token": {
                "description": "Token de acesso da conta à API pública TiqueTaque (usado com autenticação BasicAuth sendo user=public, senha=&ltapi_token&gt). Presente somente quando o header <code>X-Secret</code> da requisição corresponde à chave secreta da conta (campo <code>secret</code> retornado na criação da conta); caso o header esteja ausente ou não corresponda, o campo não é retornado. Retorna null caso o token tenha sido revogado.\n",
                "type": "string",
                "nullable": true,
                "example": "8f14e45fceea167a5a36dedd4bea2543"
              }
            }
          }
        ]
      },
      "PartnerTokenRequestModel": {
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "properties": {
          "email": {
            "description": "E-mail do usuário do portal de parceiros.",
            "type": "string",
            "example": "parceiro@empresa.com"
          },
          "password": {
            "description": "Senha do usuário do portal de parceiros.",
            "type": "string"
          }
        }
      },
      "PartnerTokenModel": {
        "type": "object",
        "properties": {
          "token": {
            "description": "Token JWT de parceiro a ser usado no header Authorization das demais requisições.",
            "type": "string"
          },
          "_id": {
            "description": "Identificador único do usuário do portal de parceiros autenticado.",
            "type": "string",
            "example": "5f5bc225b511a6edec2891f7"
          }
        }
      },
      "PartnerAccountPostModel": {
        "type": "object",
        "required": [
          "full_name",
          "email",
          "mobile_phone",
          "company_doc",
          "employees_quantity"
        ],
        "properties": {
          "full_name": {
            "description": "Nome completo do usuário administrador da nova conta.",
            "type": "string",
            "maxLength": 200,
            "example": "Exemplo da Silva"
          },
          "employees_quantity": {
            "description": "Quantidade de funcionários da assinatura da nova conta. Deve ser entre 1 e 5000.",
            "type": "integer",
            "minimum": 1,
            "maximum": 5000,
            "example": 10
          },
          "email": {
            "description": "E-mail do usuário administrador da nova conta. Recebe os e-mails de ativação e boas-vindas.",
            "type": "string",
            "example": "exemplo@empresa.com"
          },
          "mobile_phone": {
            "description": "Número de telefone celular com código de área, somente números.",
            "type": "string",
            "example": "11991234567"
          },
          "company_doc": {
            "type": "object",
            "required": [
              "name",
              "trade_name",
              "address"
            ],
            "properties": {
              "name": {
                "description": "Razão social do empregador.",
                "type": "string",
                "example": "TIQUETAQUE SERVICOS DE TECNOLOGIA S.A."
              },
              "trade_name": {
                "description": "Nome fantasia do empregador.",
                "type": "string",
                "example": "TiqueTaque"
              },
              "cpf": {
                "description": "CPF do empregador. Apenas números. Necessário que exista ou este campo ou o campo CNPJ, mutuamente exclusivos.\n",
                "type": "string",
                "pattern": "^\\d{11}$",
                "example": "01234567890"
              },
              "cnpj": {
                "description": "CNPJ do empregador. Apenas números. Necessário que exista ou este campo ou o campo CPF, mutuamente exclusivos.\n",
                "type": "string",
                "pattern": "^[0-9A-Z]{12}\\d{2}$",
                "example": "23467093000164"
              },
              "financial_email": {
                "description": "E-mail do setor financeiro do empregador.",
                "type": "string",
                "example": "financeiro@empresa.com"
              },
              "address": {
                "type": "object",
                "required": [
                  "cep",
                  "street_name",
                  "street_number",
                  "neighborhood",
                  "state",
                  "city"
                ],
                "properties": {
                  "cep": {
                    "description": "CEP do endereço do empregador. Apenas números.",
                    "type": "string",
                    "example": "90240111"
                  },
                  "street_name": {
                    "description": "Logradouro do endereço.",
                    "type": "string",
                    "example": "RUA FREDERICO MENTZ"
                  },
                  "street_number": {
                    "description": "Número do endereço.",
                    "type": "string",
                    "maxLength": 6,
                    "example": "1606"
                  },
                  "neighborhood": {
                    "description": "Bairro do endereço.",
                    "type": "string",
                    "example": "Navegantes"
                  },
                  "complement": {
                    "description": "Complemento do endereço, caso exista.",
                    "type": "string",
                    "example": "LOJA 134"
                  },
                  "state": {
                    "description": "UF do endereço.",
                    "type": "string",
                    "example": "RS"
                  },
                  "city": {
                    "description": "Cidade do endereço do empregador.",
                    "type": "string",
                    "example": "Porto Alegre"
                  }
                }
              }
            }
          }
        }
      },
      "LinksModel": {
        "type": "object",
        "properties": {
          "parent": {
            "type": "object",
            "properties": {
              "href": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            }
          },
          "self": {
            "description": "Página atual. Presente apenas quando existem resultados.",
            "type": "object",
            "properties": {
              "href": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            }
          },
          "next": {
            "description": "Próxima página. Presente apenas quando existe uma página seguinte.",
            "type": "object",
            "properties": {
              "href": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            }
          },
          "last": {
            "description": "Última página. Presente apenas quando existe mais de uma página.",
            "type": "object",
            "properties": {
              "href": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            }
          }
        }
      },
      "MetaModel": {
        "type": "object",
        "properties": {
          "max_results": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "MaxResultsParamModel": {
        "type": "integer",
        "description": "Tamanho da página dos resultados, valor padrão 25.",
        "default": 25
      },
      "PageParamModel": {
        "type": "integer",
        "description": "Número da página de resultados solicitada.",
        "default": 1
      },
      "ErroRespostaModel": {
        "description": "Resposta de erro",
        "type": "object",
        "properties": {
          "_code": {
            "description": "Código de erro interno. Ausente nos erros de validação de campos, nos quais <code>_error.message</code> contém um objeto com os erros por campo.\n",
            "type": "integer"
          },
          "_status": {
            "type": "string",
            "example": "ERR"
          },
          "_error": {
            "type": "object",
            "properties": {
              "code": {
                "description": "Codigo de erro HTTP.",
                "type": "integer"
              },
              "message": {
                "description": "Mensagem de erro interna. Nos erros de validação de campos (veja <code>_code</code>), é um objeto que mapeia cada campo inválido à lista de mensagens de erro daquele campo.\n",
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "object",
                    "additionalProperties": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                ]
              },
              "ui_message": {
                "description": "Mensagem de erro para o usuário.",
                "type": "string"
              }
            }
          }
        }
      }
    },
    "examples": {
      "401_example": {
        "value": {
          "_code": 9,
          "_error": {
            "code": 401,
            "message": "Invalid account credentials.",
            "ui_message": "Credenciais inválidas"
          },
          "_status": "ERR"
        }
      },
      "403_example": {
        "value": {
          "_code": 666,
          "_error": {
            "code": 403,
            "message": "Forbidden resource for this token.",
            "ui_message": "Acesso não autorizado."
          },
          "_status": "ERR"
        }
      },
      "404_account_example": {
        "value": {
          "_code": 56,
          "_error": {
            "code": 404,
            "message": "account not found.",
            "ui_message": "account não encontrado."
          },
          "_status": "ERR"
        }
      },
      "422_validation_example": {
        "summary": "Erro de validação de campos",
        "value": {
          "_error": {
            "code": 422,
            "message": {
              "company_doc": [
                "required field"
              ]
            }
          },
          "_status": "ERR"
        }
      },
      "422_invalid_account_id_example": {
        "summary": "Identificador da conta com formato inválido",
        "value": {
          "_code": 113,
          "_error": {
            "code": 422,
            "message": "Invalid 'account_id' query parameter for request.",
            "ui_message": "Parâmetro account_id inválido para essa requisição."
          },
          "_status": "ERR"
        }
      },
      "422_invalid_body_example": {
        "summary": "Corpo da requisição não é um JSON válido",
        "value": {
          "_code": 1405,
          "_error": {
            "code": 422,
            "message": "Invalid body format.",
            "ui_message": "Formato do corpo da requisição inválido."
          },
          "_status": "ERR"
        }
      },
      "422_duplicated_email_example": {
        "summary": "E-mail já cadastrado",
        "value": {
          "_code": 88,
          "_error": {
            "code": 422,
            "message": "Value is not unique",
            "ui_message": "Valor já cadastrado no sistema."
          },
          "_status": "ERR"
        }
      }
    }
  },
  "paths": {
    "/tokens": {
      "post": {
        "operationId": "postPartnerToken",
        "tags": [
          "Autenticação"
        ],
        "summary": "Gera um token de parceiro",
        "description": "Gera um token JWT de parceiro a partir das credenciais de um usuário do portal de parceiros. O token retornado deve ser enviado no header <code>Authorization: Bearer &lttoken&gt</code> das demais requisições desta API.\n",
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerTokenRequestModel"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token gerado com sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerTokenModel"
                }
              }
            }
          },
          "401": {
            "description": "Erro por credenciais ausentes ou inválidas, ou por usuário ainda não ativado. Usuários do portal de parceiros precisam ativar a conta pelo link recebido por e-mail antes do primeiro login.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "credenciais_invalidas": {
                    "summary": "Credenciais ausentes ou inválidas",
                    "value": {
                      "_code": 1418,
                      "_error": {
                        "code": 401,
                        "message": "Invalid credentials.",
                        "ui_message": "Credenciais inválidas."
                      },
                      "_status": "ERR"
                    }
                  },
                  "usuario_nao_ativado": {
                    "summary": "Usuário ainda não ativado",
                    "value": {
                      "_code": 24,
                      "_error": {
                        "code": 401,
                        "message": "Account not activated. Verify email.",
                        "ui_message": "Conta ainda não ativada, verifique o e-mail de ativação."
                      },
                      "_status": "ERR"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Erro por corpo da requisição inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "corpo_invalido": {
                    "$ref": "#/components/examples/422_invalid_body_example"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/partner-accounts": {
      "get": {
        "operationId": "getPartnerAccounts",
        "tags": [
          "Contas"
        ],
        "summary": "Lista as contas criadas pelo parceiro",
        "description": "Retorna a listagem paginada das contas vinculadas ao parceiro identificado pelo token da requisição, ordenadas da mais recente para a mais antiga. Cada conta é retornada com o nome, e-mail financeiro e CNPJ do empregador, o número de funcionários ativos, o número de funcionários contratados na assinatura e o número de reconhecimentos faciais contratados na assinatura ativa.<br><br> A listagem nunca retorna o token de acesso das contas à API pública TiqueTaque; ele pode ser obtido através do endpoint <code>GET /partner-accounts/{account_id}</code>, mediante a chave secreta da conta.\n",
        "parameters": [
          {
            "name": "max_results",
            "description": "Tamanho da página de resultados paginados.",
            "required": false,
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/MaxResultsParamModel"
            }
          },
          {
            "name": "page",
            "description": "Número da página de resultados a retornar",
            "required": false,
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PageParamModel"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de contas do parceiro.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "_items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PartnerAccountModel"
                      }
                    },
                    "_links": {
                      "$ref": "#/components/schemas/LinksModel"
                    },
                    "_meta": {
                      "$ref": "#/components/schemas/MetaModel"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Erro por credenciais ausentes ou inválidas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "401": {
                    "$ref": "#/components/examples/401_example"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Erro por token sem permissão de acesso ao recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "403": {
                    "$ref": "#/components/examples/403_example"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "postPartnerAccount",
        "tags": [
          "Contas"
        ],
        "summary": "Cria uma nova conta vinculada ao parceiro",
        "description": "Cria uma nova conta vinculada ao parceiro identificado pelo token da requisição, aplicando o cupom do parceiro quando este possui um, junto com uma assinatura com a quantidade de funcionários informada em <code>employees_quantity</code> (entre 1 e 5000). São criados os cadastros iniciais da conta: o usuário administrador, o empregador, a unidade e uma escala de trabalho de exemplo. Os e-mails de ativação e boas-vindas são enviados ao usuário administrador quando a assinatura da conta é ativada.<br><br> A conta é criada com seu token de acesso à API pública TiqueTaque e a chave secreta já gerados, retornados nos campos <code>api_token</code> e <code>secret</code> da resposta. A chave secreta é retornada somente nesta resposta e não pode ser consultada posteriormente.\n",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerAccountPostModel"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Conta criada com sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "_id": {
                      "description": "Identificador único da nova conta.",
                      "type": "string",
                      "example": "5f5bc225b511a6edec2891f7"
                    },
                    "api_token": {
                      "description": "Token de acesso da nova conta à API pública TiqueTaque (usado com autenticação BasicAuth sendo user=public, senha=&ltapi_token&gt), gerado automaticamente na criação da conta.\n",
                      "type": "string",
                      "nullable": true,
                      "example": "e7a56a3e-8a5b-4a75-b7a4-4bfbe6f36a10"
                    },
                    "secret": {
                      "description": "Chave secreta da nova conta, gerada automaticamente na criação. Retornada somente nesta resposta, não sendo possível consultá-la posteriormente.\n",
                      "type": "string",
                      "nullable": true,
                      "example": "kHc9tGm3xQ7LpZ2vNwRbQg"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Erro por credenciais ausentes ou inválidas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "401": {
                    "$ref": "#/components/examples/401_example"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Erro por token sem permissão de acesso ao recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "403": {
                    "$ref": "#/components/examples/403_example"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Parâmetro obrigatório ausente ou com formato inválido, corpo da requisição inválido, ou e-mail do usuário administrador já cadastrado.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "erro_validacao": {
                    "$ref": "#/components/examples/422_validation_example"
                  },
                  "corpo_invalido": {
                    "$ref": "#/components/examples/422_invalid_body_example"
                  },
                  "email_duplicado": {
                    "$ref": "#/components/examples/422_duplicated_email_example"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/partner-accounts/{account_id}": {
      "get": {
        "operationId": "getPartnerAccount",
        "tags": [
          "Contas"
        ],
        "summary": "Retorna uma conta criada pelo parceiro",
        "description": "Retorna uma conta vinculada ao parceiro identificado pelo token da requisição, com os mesmos campos da listagem de contas e o campo <code>api_token</code>. A conta pode ser identificada pelo seu identificador único (campo <code>_id</code>) ou pelo documento do empregador: CNPJ (incluindo o novo formato alfanumérico) ou CPF, sem pontuação.<br><br> O token de acesso da conta à API pública TiqueTaque (<code>api_token</code>) é retornado somente quando o header <code>X-Secret</code> da requisição corresponde à chave secreta da conta; caso contrário o campo não é retornado. A chave secreta é exibida somente no momento da criação  de cada conta.\n",
        "parameters": [
          {
            "name": "account_id",
            "description": "Identificador único da conta (campo <code>_id</code>, 24 caracteres hexadecimais), CNPJ do empregador da conta (14 caracteres sem pontuação: 12 letras ou dígitos mais 2 dígitos verificadores, aceitando o novo formato alfanumérico, com letras maiúsculas ou minúsculas) ou CPF do empregador da conta (11 dígitos, sem pontuação).<br><br> Os documentos são procurados somente entre os empregadores das contas do parceiro e seus dígitos verificadores não são validados: um CNPJ ou CPF com formato válido que não corresponda a nenhuma conta do parceiro retorna <code>404</code>. Documentos com pontuação ou qualquer outro formato retornam <code>422</code>.\n",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string",
              "pattern": "^([0-9a-fA-F]{24}|[0-9A-Za-z]{12}[0-9]{2}|[0-9]{11})$"
            },
            "examples": {
              "id": {
                "summary": "Identificador único da conta",
                "value": "5f5bc225b511a6edec2891f7"
              },
              "cnpj": {
                "summary": "CNPJ do empregador",
                "value": "23467093000164"
              },
              "cnpj_alfanumerico": {
                "summary": "CNPJ alfanumérico do empregador",
                "value": "12ABC34501DE35"
              },
              "cpf": {
                "summary": "CPF do empregador",
                "value": "01234567890"
              }
            }
          },
          {
            "name": "X-Secret",
            "description": "Chave secreta da conta (campo <code>secret</code> retornado na criação da conta). Quando presente e correspondente à chave secreta da conta, o campo <code>api_token</code> é retornado com o token de acesso à API pública.\n",
            "required": false,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Conta do parceiro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerAccountDetailModel"
                }
              }
            }
          },
          "401": {
            "description": "Erro por credenciais ausentes ou inválidas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "401": {
                    "$ref": "#/components/examples/401_example"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Erro por token sem permissão de acesso ao recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "403": {
                    "$ref": "#/components/examples/403_example"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Erro por conta inexistente, não vinculada ao parceiro ou sem empregador com o CNPJ ou CPF informado.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "404": {
                    "$ref": "#/components/examples/404_account_example"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Erro por identificador com formato inválido: <code>account_id</code> deve ser o identificador único da conta (24 caracteres hexadecimais), o CNPJ do empregador (14 caracteres, sem pontuação) ou o CPF do empregador (11 dígitos, sem pontuação). Documentos enviados com pontuação também retornam este erro.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroRespostaModel"
                },
                "examples": {
                  "identificador_invalido": {
                    "$ref": "#/components/examples/422_invalid_account_id_example"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}