Secret and publishable
A secret key islath_live_ or lath_test_ and 43 more characters. It carries the permissions you name and belongs on a server.
A publishable key is lath_live_pk or lath_test_pk and 40 more, so anyone reading a bundle can tell the two apart at a glance. It holds exactly one permission, auth:public, which reaches only the end-user sign-in operations — auth.signin.start, auth.signin.verify, auth.session.refresh, auth.session.exchange, auth.session.signout. That is why it is safe in a browser, an app or a CLI.
The kind is fixed when the key is made. There is no call that turns one into the other.
What there is to grant
A permission is a product and a verb:email:write, auth:read, billing:read. The products are account, auth, email, sms, audience, developers and billing, and both verbs exist for each, so the full list is derived rather than written down anywhere.
auth:public is not in that list. It is the publishable key’s built-in permission and is never granted to a secret key by name.
You cannot grant what you do not hold. A key without billing:write cannot create one that has it, and the refusal says so: permission_exceeds_caller.
The plaintext is shown once
developers.key.create returns the key itself in that one response. No operation returns it again — developers.key.list reports the prefix, the permissions and when it was last used, and never a plaintext or a hash.
Store it before you make the next call. If it is lost, the way back is developers.key.rotate, not a lookup.
Changing a key without replacing it
developers.key.update changes a key’s name and its permissions. The key itself does not change, so nothing holding it has to be redeployed and no request fails while it happens.
That is the one to reach for when a service needs one more scope. Rotation is for a key you no longer trust.
Rotate, and revoke
developers.key.rotate issues a new key with the same name and the same permissions and revokes the old one in the same transaction. The new plaintext is returned once, exactly as create returns it. The old key stops working immediately — there is no overlap window, so deploy the new one promptly.
developers.key.revoke ends a key on its own. It is refused when it is the last key in the environment holding developers:write, because an environment that can no longer manage its own keys cannot be recovered through the API.

