Pular para o conteúdo

Começar

Login de usuário (OAuth2)

Quando o seu app entra com a conta da pessoa: OAuth2 com PKCE, a escolha do workspace e o token de 1 hora.

Há dois jeitos de autenticar na v1, e eles não competem. A chave de API é credencial do workspace: o dono cria, o seu servidor guarda, e ela não carrega pessoa nenhuma. O login de usuário é OAuth2 com redirect: a pessoa entra com o e-mail e a senha dela, na nossa tela, escolhe em qual workspace o seu app vai agir, e o seu app recebe um token que carrega quem ela é.

Use este caminho quando o seu app é de terceiro e cada usuário dele já tem conta no Growth OS — um app desktop, uma extensão, um produto que você vende pra vários clientes nossos.

Chave de API ou login de usuário

Chave de API (gos_…)Login de usuário (OAuth2)
Quem é o portadoro workspacea pessoa que entrou
Onde a credencial morano seu servidorno seu app, uma por usuário
Quem a emiteo dono do workspace, na tela de Acessosa própria pessoa, fazendo login
Escoposmarcados na criação da chavepedidos por você na URL de autorização, confirmados por ela na tela
Workspaceo da chave, fixoescolhido por ela no consentimento
Validade1 ano por padrão1 hora, renovável por 30 dias
Allowlist de IPopcionalnão se aplica
platform.readsó a conta Acceleranunca, para ninguém
Se a pessoa sai do workspacenada mudao token para de funcionar na requisição seguinte

Antes de começar: o registro do app

Não existe autosserviço: quem registra o app somos nós. Peça pelo seu canal de sempre, com o nome do app (é o que a pessoa vê na tela de consentimento) e as URLs de retorno (redirect_uri) que ele usa. Você recebe um client_id.

App que roda na máquina do usuário (desktop, mobile, CLI) é registrado como público: não recebe client_secret, porque não há onde guardar um segredo em código que o usuário tem na mão — a prova de posse é o PKCE. App que tem servidor próprio pode ser registrado como confidencial e aí sim ganha um client_secret. Trocar a URL de retorno depois não troca o seu client_id.

Os escopos que o app pode pedir

São os mesmos da chave de API — contacts.read, contacts.write, pipelines.read, opportunities.read, opportunities.write, calendars.read, calendars.write, users.read, webhooks.manage — menos platform.read, que é exclusivo da conta Accelera e não existe por este caminho: pedido ou não, a rota responde 403 forbidden_platform. Some a eles dois escopos do próprio protocolo:

  • openid — sempre; é o que faz o pedido ser um login.
  • offline_access — só se você quiser o refresh token. Sem ele a resposta não traz refresh_token nenhum, e o seu app terá que mandar a pessoa fazer login de novo a cada hora. É o esquecimento mais caro deste guia.

Peça só o que o app usa: o que não foi consentido responde 403 forbidden_scope nomeando o que falta, igual à chave.

O fluxo, do botão ao token

  1. O seu app gera um code_verifier aleatório, calcula o code_challenge (SHA-256, base64url) e abre o navegador na URL de autorização abaixo. S256 é obrigatório — plain é recusado.
  2. A pessoa entra com e-mail e senha na nossa tela (e o 2FA dela, se estiver ativo). Se já houver sessão aberta no navegador, este passo não aparece.
  3. Ela vê a tela de consentimento: o nome do seu app, a lista do que ele está pedindo, e em qual workspace. O seletor só aparece quando ela é membro de mais de um; quem não é membro de nenhum não consegue autorizar.
  4. Ela clica em "Permitir" e o navegador volta pro seu redirect_uri com code e o seu state de volta — confira o state, é ele que amarra a resposta ao pedido que você fez.
  5. O seu app troca esse code pelo token, no passo seguinte.
URL de autorização
https://api.staging.growthaisystem.com/api/auth/oauth2/authorize
  ?response_type=code
  &client_id=SEU_CLIENT_ID
  &redirect_uri=meuapp%3A%2F%2Foauth%2Fcallback
  &scope=openid%20offline_access%20contacts.read%20opportunities.read
  &state=UM_VALOR_ALEATORIO_SEU
  &code_challenge=BASE64URL_DO_SHA256_DO_VERIFIER
  &code_challenge_method=S256

Trocar o code pelo access token

No formato de formulário (application/x-www-form-urlencoded), que é o que a RFC pede — não JSON:

curl
curl -X POST "https://api.staging.growthaisystem.com/api/auth/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=O_CODE_QUE_VEIO_NO_REDIRECT" \
  -d "redirect_uri=meuapp://oauth/callback" \
  -d "client_id=SEU_CLIENT_ID" \
  -d "code_verifier=O_VERIFIER_QUE_GEROU_O_CHALLENGE"
200 OK
{
  "access_token": "eyJhbGciOi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tok_...",
  "scope": "openid offline_access contacts.read opportunities.read",
  "id_token": "eyJhbGciOi..."
}

refresh_token só vem se você pediu offline_access; id_token, se você pediu openid. Guarde os dois tokens como credencial da pessoa, no cofre do sistema operacional — não em arquivo de configuração em texto puro.

Chamar a v1 com o token da pessoa

Mesmo header de sempre, e é só isto que muda em relação à chave: o token não começa com gos_. As rotas são as mesmas, o envelope é o mesmo, os erros são os mesmos.

curl
curl "https://api.staging.growthaisystem.com/api/v1/contacts?limit=1" \
  -H "Authorization: Bearer O_ACCESS_TOKEN"

Os limites são os mesmos da chave (100 requisições por 10 segundos, 50 por rota, 10.000 por dia), só que contados por app + usuário — dois vendedores do mesmo cliente têm baldes separados, e renovar o token não zera balde nenhum. A idempotência funciona igual, e sobrevive à renovação: a mesma Idempotency-Key continua deduplicando depois de um refresh.

Duas coisas não se aplicam aqui: a allowlist de IP (um app instalado na máquina de alguém não tem IP fixo) e platform.read.

Renovar sem pedir login de novo

O access token vale 1 hora; o refresh token, 30 dias. Renove antes de expirar, ou quando levar 401:

curl
curl -X POST "https://api.staging.growthaisystem.com/api/auth/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=O_REFRESH_TOKEN" \
  -d "client_id=SEU_CLIENT_ID"

A renovação não passa por tela nenhuma e mantém o workspace que a pessoa escolheu. Se o refresh token também tiver expirado (30 dias sem uso), aí sim é login de novo — recomece pelo passo 1.

Em qual workspace o token entra

Um token vale para um workspace: o que a pessoa escolheu na tela. Na segunda vez que ela autoriza o mesmo app com os mesmos escopos, a tela de consentimento não aparece (é o padrão do OAuth2: não repergunta o que já foi respondido), e nós reaproveitamos a escolha anterior dela.

Se não houver escolha válida — a pessoa foi removida do workspace que tinha escolhido, por exemplo —, o token nasce sem workspace e a v1 responde 401 pedindo login de novo. Nunca chutamos um workspace no lugar dela.

Os erros que só existem aqui

Tudo o que a página de erros descreve continua valendo. O que muda são estes 401, todos com o mesmo remédio do lado do seu app — renovar ou refazer o login:

RespostaO que aconteceuO que o app faz
401 "Este token OAuth expirou"passou de 1 horarenova pelo refresh token
401 "Token OAuth desconhecido, revogado ou o app está desativado"token inválido, ou o app perdeu o registrorefaz o login; se persistir, fale conosco
401 "…não tem workspace associado"nenhuma escolha de workspace válida sobrourefaz o login (com prompt=consent)
401 "…não é mais membro do workspace"a pessoa saiu ou foi removida — checado a cada requisiçãorefaz o login e escolhe outro workspace
403 forbidden_scopea rota pede um escopo que não foi consentidoautoriza de novo pedindo o escopo que falta
403 forbidden_platform/platform/* por este caminhonada a fazer: é exclusivo da conta Accelera
403 workspace_suspendedo workspace está pausadonada a fazer: é a conta do cliente