Tutoriais
Receitas curtas para os casos que aparecem de verdade.
Proteger o meu primeiro plugin
- Registre em /seller/licensing/plugins/new. Copie o Product ID.
- Deixe a política no padrão: vínculo por instalação, 1 instalação, vitalícia.
- Associe o produto do marketplace, se já estiver publicado.
- Adicione o SDK ao build e relocate o pacote.
- Cole o trecho de inicialização da tela do plugin no seu
onEnable(). - Emita uma licença de teste e rode em um servidor local com
test-mode: true.
Os detalhes de cada passo estão em primeiros passos.
Vincular ao IP do servidor
Leia antes de escolher
INSTALLATION.- Na política do plugin, escolha
Vinculada ao IP. - No plugin, declare o endereço:
LodestoneLicensing.builder()
.productId(PRODUCT_ID)
.licenseKey(key)
.declaredAddress(getServer().getIp(), getServer().getPort())
.build();Sem o endereço declarado, a ativação é recusada com bad_request e o motivo endereco_obrigatorio — a política exige, o cliente não mandou.
O IP é gravado na primeira ativação. A partir daí, qualquer validação com endereço diferente recebe binding_mismatch. Para o cliente trocar de máquina, uma instalação precisa ser liberada.
Vincular também à porta
Escolha Vinculada a IP e porta. Mais restritivo: muda a porta, a licença para de valer. Útil quando o cliente roda vários servidores no mesmo host e você quer cobrar por servidor — e inútil quando o painel de hospedagem sorteia porta a cada reinício.
Permitir múltiplas instalações
Ajuste Instalações simultâneas na política. O teto do plano limita quanto você consegue configurar; licenças já emitidas não são afetadas.
Para vender uma licença com mais instalações do que a política padrão — uma licença de rede, por exemplo — emita à mão com maxInstallations maior. A licença guarda esse valor para sempre.
curl -X POST https://lodestone.gg/api/v1/licensing/developer/licenses \
-H "Authorization: Bearer $LODESTONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pluginId": "lsp_...",
"buyerEmail": "[email protected]",
"buyerLabel": "Rede Exemplo — licença de rede",
"maxInstallations": 10
}'Criar uma licença temporária
Duas formas:
- Na política, escolha
Por períodoouAvaliaçãoe informe os dias. Todas as licenças novas daquele plugin passam a ter prazo. - Na emissão manual, informe
termDays. Vale só para aquela licença.
# Avaliação de 7 dias
curl -X POST https://lodestone.gg/api/v1/licensing/developer/licenses \
-H "Authorization: Bearer $LODESTONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"pluginId":"lsp_...","buyerEmail":"[email protected]","termDays":7}'A expiração é comparada a cada requisição — não depende de nenhuma rotina ter rodado antes. A rotina que marca o estado como EXPIRED existe só para as listagens e os contadores mostrarem a verdade.
Avisar o cliente antes de expirar
Não há notificação automática de vencimento. O caminho é o webhook license.expired mais uma consulta periódica das suas licenças com vencimento próximo:
curl "https://lodestone.gg/api/v1/licensing/developer/plugins/lsp_.../licenses?status=ACTIVE&pageSize=100" \
-H "Authorization: Bearer $LODESTONE_API_KEY"Filtre por expiresAt no seu lado e dispare o aviso. O painel do comprador já mostra a data de validade em cada licença.
Revogar uma licença
Pelo painel, no detalhe da licença, ou pela API:
curl -X POST https://lodestone.gg/api/v1/licensing/developer/licenses/<id>/revoke \
-H "Authorization: Bearer $LODESTONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason":"Chargeback confirmado pelo provedor."}'- O motivo é obrigatório. Ele fica na auditoria e o comprador consegue consultá-lo — uma revogação sem motivo vira um mistério três meses depois.
- As sessões ativas caem junto. O servidor perde a autorização na próxima verificação, não no próximo reinício.
- É definitivo. Em caso de dúvida, suspenda: a suspensão volta sem reemitir chave.
O cliente perdeu a chave
Ele mesmo resolve: a chave continua disponível no detalhe da licença em /dashboard/licenses, atrás de uma ação explícita. Cada visualização fica registrada no histórico.
Se a chave vazou, aí sim rotacione — pelo painel, no detalhe da licença. A chave antiga para de valer imediatamente, e as instalações e o prazo são preservados. O cliente só troca a chave no config.yml e reinicia.
Tratar indisponibilidade da API
O SDK já faz o certo por padrão. O que o seu plugin precisa é apenas não atrapalhar:
@Override
public void onGrace(LicenseResult r) {
// A plataforma caiu. Os recursos CONTINUAM ligados.
// Não desligue nada aqui.
premium.set(true);
getLogger().info("Modo offline: " + r.message());
}
@Override
public void onOffline(LicenseResult r) {
// A tolerância acabou. AGORA sim.
premium.set(false);
getLogger().warning("Sem autorização utilizável: " + r.message());
}O erro que mais aparece
onGrace. Isso transforma uma indisponibilidade nossa em uma indisponibilidade do cliente, que não tem nada a ver com o problema — e gera o pior tipo de avaliação negativa no seu produto.Para ver o comportamento: com o plugin já autorizado, derrube a aplicação e reinicie o servidor. Ele deve subir funcionando. O Playground tem o cenário pronto.
Migrar o cliente de servidor
- No servidor antigo, o plugin chama
deactivateao desligar — se você configurou isso — ou o cliente desvincula em/dashboard/licenses. - A vaga é liberada na hora.
- No servidor novo, cole a mesma chave e reinicie.
Se a política tiver allowSelfReset desligado, só o vendedor libera. E o resetCooldownHours impede que a liberação vire rodízio entre servidores.
O que acontece se eu parar de pagar
As licenças que você já emitiu continuam valendo. Seus clientes não perdem acesso. O que a inadimplência bloqueia é a criação de plugins, licenças e webhooks novos.
Isso é regra do serviço, não cortesia: o comprador do seu plugin não tem relação nenhuma com a sua assinatura, e desligar o servidor dele transformaria um problema de cobrança em um incidente de produção de terceiro.