Skip to main content
Migrate Already selling? Move your customers to Keylight without re-issuing a single key.
Keylight
Blog
licensing automation cli

Four Licensing Jobs You Can Stop Doing By Hand

5 min read Nicolas Demanez — Founder

Every licensing setup accumulates the same handful of chores: someone needs a beta key, a refund slipped past your webhook, you’d like your own copy of your license data, and a support ticket needs an answer. None of it is hard. All of it is the kind of thing that eats twenty minutes out of a Tuesday because it lives in a dashboard you have to open, click through, and copy out of by hand.

The Keylight CLI — Automate Your Licensing Operations turns each of those into a command with flags instead of clicks, which means it also turns them into something you can schedule or hand to a coding agent. Below are four real workflows, with the commands as they actually run — checked against the CLI’s own --help output, flag by flag.

One thing before the workflows: seven operations are confirm-gated. Revoking a license, exporting licenses, deleting a key type, rotating an integration secret, reading your SDK key, rotating your SDK key, and setting your webhook all block on the command line and wait for a person to approve them in a browser. A token alone — stolen, leaked, or otherwise — cannot complete any of those seven. That matters here because it shapes what “automated” honestly means for two of the four jobs below.

Issue a batch of beta keys

You’re opening a beta and you have a list of email addresses. licenses create takes a customer email and a product, and returns a plaintext key — printed once, so capture it or use --send-email and let Keylight deliver it directly:

while read -r email; do
  keylight licenses create \
    --product beta-app \
    --key-type beta \
    --customer-email "$email" \
    --send-email
done < testers.txt

Pass --idempotency-key if the same list might run twice — a retried call with the same key won’t mint a second license for someone who already has one. This is fully ungated: nothing here waits on a person, so it’s genuinely safe to trigger from a form submission or a scheduled job, not just to run by hand.

Catch refunded licenses before they cost you

A webhook is best-effort. Most refunds reach it fine, but a dropped delivery, a provider outage, or a tenant that switched payment processors mid-flight can all leave a license active behind a refund your system never heard about.

The detection half is ungated and safe to run nightly:

keylight licenses list --status active --json

Cross-reference the result against your payment provider’s refund and dispute records, and you’re left with a short list: licenses that are still active but shouldn’t be. That’s as far as the scheduled job goes. Revoking is one of the seven gated operations, so the job doesn’t call licenses revoke — it can’t, unattended, and it shouldn’t. Instead it hands the list to a person, who runs:

keylight licenses revoke MYAP-K3M2-8XQD-7FTW-B12Z

That command blocks, prints an approval link, and waits. Someone opens it, confirms, and the license is gone. The job did the tedious part — scanning every active license every night, which nobody was going to do by hand — and left the one step that should require a human exactly where it is.

Snapshot your license set every night

Holding your own copy of your license data, separate from Keylight’s dashboard, is a reasonable thing to want. The command for it is licenses list --json, not licenses export — export is one of the seven gated operations, and it’s also restricted to the Enterprise plan, so a nightly job calling it fails twice over: once waiting on a browser nobody’s watching, once on a 402 if you’re not on that plan.

licenses list is cursor-paginated, up to 100 per page, so a full snapshot pages through until there’s no nextCursor left:

#!/usr/bin/env bash
out="licenses-$(date +%F).json"
cursor=""
: > "$out"
while :; do
  page=$(keylight licenses list --json --limit 100 ${cursor:+--cursor "$cursor"})
  echo "$page" | jq -c '.items[]' >> "$out"
  cursor=$(echo "$page" | jq -r '.nextCursor // empty')
  [ -z "$cursor" ] && break
done

Point a cron line at this on any machine you already own and you have a nightly backup in storage you control, with nothing waiting on approval.

Answer a support email in one lookup

A ticket comes in: “I paid for this and it says my key is invalid.” You need every license tied to that email, fast.

A Keylight customer ID is a sha256 hash of the email, not the address itself, so the lookup is two ungated commands rather than one — this is also exactly what a coding agent does for you when you paste the email in and ask it to look someone up:

keylight customers list --json | jq '.items[] | select(.email == "person@example.com")'

That gives you the customer’s id. Feed it to customers get and you get everything behind it — every license, masked keys, activation state, revenue, activity — in one response:

keylight customers get <id> --json

No dashboard tab, no clicking into a customer record. Both commands are ungated, so an agent with your token can run the whole lookup and hand you back an answer while you’re still reading the ticket.

The pattern underneath all four

Three of these run start to finish without anyone watching. The fourth — refunds — splits cleanly into an unattended detection step and a one-approval revoke, which is the shape every gated workflow on the CLI takes: automate the finding, keep a human on the doing. That’s not a limitation bolted on around the edges. It’s the same reason a stolen token can’t revoke your customers’ licenses either — the seven gated operations are gated for the same reason, on purpose, everywhere they show up.

For the reasoning behind that split — why the CLI never prompts, why the token lives in an environment variable instead of a flag, and why those seven operations block on approval instead of failing fast — see Why I Made Keylight Drivable By A Coding Agent.

Frequently asked

Do I need a server to run these?+

No. They are shell commands. A scheduled job on any machine you already own is enough, and several of them are just as useful run by hand when you need them.

Can a coding agent run these for me?+

Yes. No command opens a prompt, every input is a flag, and your token comes from an environment variable — so anything with shell access can run them. Seven operations still need you to approve them in your browser.

What happens if the token leaks?+

Revoking, exporting, deleting a key type, rotating a payment secret, reading or rotating your SDK key, and setting your webhook all need a person to approve them in a browser. A token alone cannot do any of those seven things.

Ready to ship?

Create your account and start licensing your apps in under a minute. Free forever tier included.

Start Free