Skip to main content
Um entitlement é o que o plano permite, e é uma pergunta diferente de o que uma pessoa pode. getEntitlements() responde a primeira, para o time dentro do qual a sessão atual está agindo.
As features são o seu catálogo — os planos que você vende, não os nossos. kind é uma string simples e não uma união justamente por isso: um kind que você criar não pode depender de uma nova versão do SDK para ser lido por um cliente. limit é um teto para comparar com o uso; included é uma concessão por período para somar a um saldo, e só existe para o kind credit. São dois campos porque são duas perguntas. “Sem teto” viaja como unlimited: true, nunca como um limit ausente. Uma feature com limit: null e unlimited: false não tem teto registrado, o que é um teto de zero e não permissão para um teto infinito — um número mágico no fio é um número que todo cliente precisa aprender, e um null solto é um que todo cliente interpreta do seu jeito. Toda feature do seu catálogo aparece aqui, inclusive as que o plano atual não carrega: elas chegam com enabled: false, que é a resposta e não uma lacuna.

No React

Num app Next, importe o hook do @userkit/nextjs — é o mesmo hook, e em modo proxy a leitura é encaminhada pelos handlers, com a sessão num cookie httpOnly da sua própria origem. O time continua sendo resolvido e nunca nomeado: o X-Customer-Id atravessa os handlers e identifica sem nunca autorizar. Ele segue a sessão: sair da conta limpa o valor, e trocar de time refaz a leitura para o time dentro do qual a próxima requisição vai agir.

O time é resolvido, nunca nomeado

A concessão pertence ao cliente que a sessão resolveu — o que setActiveCustomer() nomeou, ou a associação mais antiga do contato quando nenhum foi nomeado. Não existe parâmetro que nomeie um cliente, e é isso que faz um id colado responder 404 em vez do plano de outra pessoa.

Três respostas que valem um branch

  • 404 — a sessão não pertence a time nenhum. Um visitante anônimo recebe isso, e é a resposta verdadeira em vez de uma recusa: é o que diz à interface para oferecer a criação de um time.
  • 403 unverified_session — uma sessão identificada mas não verificada. O que uma conta paga inclui não se entrega a uma afirmação que qualquer um que saiba um external_id poderia fazer de um navegador.
  • 503 entitlements_unavailable — nada está sendo recusado. A concessão não pôde ser resolvida agora, então pergunte de novo. A API não responde corpo nenhum, em vez de responder um cheio de false, porque uma tela cheia de false tomaria a decisão por você, em silêncio, na direção que fecha o seu produto durante uma queda nossa.
useEntitlements() renderiza as três como null, que é a mesma renderização de “ainda carregando”, de propósito: as duas significam ainda não há nada para barrar. Nunca trate null como uma concessão de nada — barre em grant?.features[key].enabled e deixe null significar “ainda não”.

Isto é o portão da interface, não a aplicação da regra

Um navegador pode ouvir qualquer coisa. Leia a mesma concessão no seu backend — com uma chave de servidor, GET /v1/customers/{id}/entitlements, ao lado do token de sessão que prova quem está perguntando — e aplique a regra lá. O que getEntitlements() compra é uma tela que não oferece um botão que o plano vai recusar.