Issuing credentials
Your organization can be an issuer as well as a verifier: you define a schema, name a recipient, and send them a credential they claim into their Socious Wallet. From then on they can present it to anyone — including you — without you being asked again.
Before you can issue anything, your organization must pass KYB. Upload a registration document in the dashboard; review takes 1–3 business days. Issuing also requires a paid plan — see Plans, tiers and usage.
All issuance endpoints require a dashboard session token, so bulk issuance today runs through the dashboard’s CSV import rather than through an API key. See Authentication for the split.
Lifecycle
| Status | Meaning |
|---|---|
CREATED | The credential exists in your dashboard; nothing sent yet |
ISSUED | Offered to the recipient — the claim link is live |
CLAIMED | The recipient accepted it into their wallet. It can now be presented |
CANCELED | Withdrawn before it was claimed |
REVOKED | Withdrawn after issuance; the credential’s status entry is revoked on-chain |
Creating one
curl -X POST https://api.shinid.com/credentials \
-H "Authorization: Bearer SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Senior Engineer, 2024-2026",
"description": "Work certificate",
"schema_id": "SCHEMA_ID",
"recipient_id": "RECIPIENT_ID",
"claims": [
{ "name": "job_title", "value": "Senior Engineer" },
{ "name": "start_date", "value": "2024-04-01" }
]
}'
Three claims are added for you and do not need to be sent: type (the schema name),
issued_date, and company_name (your organization). If the recipient has an email
address on file, they are emailed a claim link automatically.
POST /credentials/with-recipient does the same thing and creates the recipient in the
same call — useful when you are issuing to someone who is not in your system yet.
Recipients
Recipients are the one part of issuance an API key can reach:
curl -X POST https://api.shinid.com/recipients \
-H "apikey: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "first_name": "Ada", "last_name": "Lovelace", "email": "[email protected]" }'
GET /recipients?q=ada searches them. Recipients created through the verification flow
carry your customer_id instead of a name, which is how the two halves stay linked.
Bulk import
POST /credentials/import takes a multipart upload with file (CSV) and schema_id.
Download a schema-shaped sample first from
GET /credentials/import/download-sample/{schema_id}, fill it in, upload it, then track
progress at GET /credentials/import/{id} — the import moves from INITIATED to
COMPLETED.
Only one import can be in flight per user at a time; starting a second returns
400 You have an existing incomplete import.
Sending and claiming
Credentials are not pushed to a wallet — the recipient claims them.
POST /credentials/notifysends the claim email to a chosen list of credentials, with a message you write.POST /credentials/notify/via-schemadoes the same for every credential on one schema.- The claim link is
https://app.shinid.com/connect/credential/{credential_id}. It shows a QR code; the recipient scans it with the Socious Wallet and accepts. GET /credentials/{id}/connectreturns the underlying connection URL if you want to render that QR code yourself. Like the verification flow, a link is reused for 2 minutes.
Revoking
# One credential
curl -X PATCH https://api.shinid.com/credentials/CREDENTIAL_ID/revoke \
-H "Authorization: Bearer SESSION_TOKEN"
# Several at once — processed asynchronously
curl -X PATCH https://api.shinid.com/credentials/revoke \
-H "Authorization: Bearer SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "credentials": ["ID_1", "ID_2"] }'
Revocation sets the credential to REVOKED and revokes its on-chain status entry. Bulk
revocation returns immediately and completes in the background, so read the credentials
back rather than trusting the 200.
One honest limit: a verification does not currently check a presented credential against its revocation status. Revocation is real and recorded, but the verification path does not consult it, so a revoked credential presented today can still satisfy a verification. If revocation checking at verification time matters to your use case, tell us — do not assume it.
Schemas
POST /schemas publishes one (session token required):
{
"name": "Membership",
"description": "Organization membership record",
"public": false,
"attributes": [
{ "name": "member_since", "type": "DATETIME" },
{ "name": "tier", "type": "TEXT" }
]
}
Types are TEXT, NUMBER, BOOLEAN, URL, DATETIME, EMAIL. Some schemas are marked
issue-disabled — the identity ones, which are issued through the KYC flow rather than by
you — and creating a credential against one returns
400 schema for issuing credentials is disabled.