Who Signs Your Credentials?
Every credential is signed by a key. Decide whether you hold it or LearnCard holds one for you.
Every credential is signed by a private key. You have two choices: you sign with your own seed, or LearnCard signs for you with a key it hosts on your behalf — a signing authority. Pick one; you can change later.
The one-line version
npx @learncard/cli setup-signingCreates a hosted signing authority, registers it, and makes it your primary — the "LearnCard signs for you" path below, done. Idempotent: run it again and it tells you it's already set. Then npx @learncard/cli send --template sends from a template with no signing details in the call.
Pick a path
You sign
LearnCard signs for you
Your own signing service
Choose when
You run a server and are happy to keep a seed in an environment variable
You don't want to hold keys, or you use API tokens, templates, or the Developer Portal
You already run a VC-API issuer and it must be the signer of record
What you set up
Nothing — initLearnCard({ seed })
A hosted signing authority, once (below)
Register your endpoint (below)
What send() takes
signedCredential
templateUri or template
templateUri or template
Where the key lives
Your server
LearnCard, tied to your profile
Your service
Also unlocks
—
Claim links, Developer Portal templates, Partner Connect apps
Same as hosted
You sign
Nothing to set up. The Quickstart does this: initLearnCard({ seed, network: true }) → issueCredential(...) → send({ signedCredential }). Keep the seed in an environment variable and back it up.
LearnCard signs for you
Do this once per profile per network (staging and production are separate). Afterwards send({ templateUri }) and send({ template }) work with no signing details.
Sign in at learncard.app/app-store/developer.
Open Guides → Issue Credentials → Signing Authority and click Create.
The first authority you create becomes your primary. Done.
Creating a hosted authority needs the LearnCard App API plugin in addition to the network plugin:
send() always uses your primary authority. To switch, call setPrimaryRegisteredSigningAuthority with another registered one.
Your own signing service
If you run a VC-API compliant issuer and it must be the signer, register it instead of a hosted authority. It needs a public HTTPS /issue endpoint and a DID.
Or in code:
send() will now call your endpoint to sign. If you register several authorities and need to choose per issuance, use the lower-level Universal Inbox API and pass configuration.signingAuthority: { name, endpoint }.
What you should see
After setup, send() with a template returns normally — no signing details in the call:
In the Developer Portal, Signing Authority shows the authority name with a Primary badge.
Troubleshooting
You must register a signing authority before using send without a pre-signed credential
You're sending a template without a primary authority. Finish LearnCard signs for you, or pass signedCredential.
learnCard.invoke.createSigningAuthority is not a function
You used initLearnCard. Hosted authorities need initLCALearnCard from @learncard/lca-api-plugin.
Profile not found
Create a profile first (createServiceProfile) — the Quickstart's setup.mjs does this.
It works on staging but not production
Authorities are per network. Register again on production — see Go to Production.
Next steps
The CLI's send --template saves the reusable script below after setting up your signer and template:
Send from a template → Issue at scale with templates
Know when it's claimed → Know When a Credential Is Claimed
Understand what a signing authority is under the hood → Signing Authorities
Last updated
Was this helpful?