Every endpoint, what authenticates it, and what a paid plan is needed for. Base URL is
https://api.shinid.com.
Auth column: apikey = integration Secret Key in the apikey header · session =
Authorization: Bearer from a dashboard sign-in · none = open, scoped by an unguessable
ID · admin = internal, not available to customers.
Endpoints marked Paid plan or Premium+ check the tier of the acting
organization — named by a current-identity header, defaulting to the organization you
have belonged to longest. See Authentication.
Verifications
| Method | Path | Auth | Notes |
|---|
GET | /verifications | session | Paginated list |
POST | /verifications | session | Paid plan, unless "sandbox": true. Create a verification request |
GET | /verifications/{id} | session | One verification request |
PUT | /verifications/{id} | session | Update. Owner only |
DELETE | /verifications/{id} | session | Owner only |
GET | /verifications/{id}/individuals | session | Paginated runs of one verification |
GET | /verifications/{id}/individuals/{customer} | apikey or session | Result for one customer_id. The call to decide on |
GET | /verifications/individuals/{id} | session | One run by its own ID |
POST | /verifications/individuals | none | Open a run. Idempotent per (customer_id, verification_id) |
GET | /verifications/{individual_id}/connect | none | Connection URL for the QR code. Reused for 2 minutes |
GET | /verifications/{individual_id}/callback | none | Called by the wallet. Not for you |
GET | /verifications/{individual_id}/verify | none | Current status; settles the presentation |
POST | /verifications/{individual_id}/simulate | apikey or session | Sandbox only. Settle a test individual through the real validator. 403 NOT_SANDBOX on a live verification |
Credentials
| Method | Path | Auth | Notes |
|---|
GET | /credentials | session | Paginated list |
GET | /credentials/{id} | session | |
POST | /credentials | session | Paid plan. Emails a claim link if the recipient has an address |
POST | /credentials/with-recipient | session | Paid plan. Creates the recipient too |
POST | /credentials/import | session | Paid plan. Multipart: file (CSV) + schema_id |
GET | /credentials/import/{id} | session | Import progress |
GET | /credentials/import/download-sample/{schema_id} | none | Schema-shaped CSV template |
POST | /credentials/notify | session | Claim email for a list of credentials |
POST | /credentials/notify/via-schema | session | Claim email for every credential on a schema |
PUT | /credentials/{id} | session | |
PATCH | /credentials/{id}/revoke | session | Owner only |
PATCH | /credentials/revoke | session | Bulk, asynchronous |
DELETE | /credentials/{id} | session | |
POST | /credentials/delete | session | Bulk delete |
GET | /credentials/{id}/connect | none | Claim connection URL. Reused for 2 minutes |
GET | /credentials/{id}/callback | none | Called by the wallet |
Schemas and recipients
| Method | Path | Auth | Notes |
|---|
GET | /schemas | session | Paginated |
GET | /schemas/{id} | session | |
POST | /schemas | session | Publish a schema |
DELETE | /schemas/{id} | session | |
GET | /recipients | apikey or session | ?q= searches |
GET | /recipients/{id} | apikey or session | |
POST | /recipients | apikey or session | |
PUT | /recipients/{id} | apikey or session | |
DELETE | /recipients/{id} | apikey or session | |
Organizations, plan and billing
| Method | Path | Auth | Notes |
|---|
GET | /organizations | session | Organizations you belong to |
GET | /organizations/{id} | session | |
POST | /organizations | session | |
PUT | /organizations/{id} | session | Members only |
GET | /organizations/{id}/usage | session | Plan, quota, usage, 12-month history |
GET | /organizations/{id}/billing/subscription | session | null where the tier was granted by hand |
POST | /organizations/{id}/billing/checkout | session | Buy Standard. Returns a Stripe Checkout URL; the webhook applies the tier |
POST | /organizations/{id}/billing/portal | session | Stripe portal. 409 if there is no billing account |
Organization codes and vouchers
| Method | Path | Auth | Notes |
|---|
POST | /organizations/{id}/codes | session | Paid plan. Mint a code. Types narrowed to the plan — identity always covered, phone/address Premium+ |
GET | /organizations/{id}/codes | session | List with redemption counts |
DELETE | /organizations/{id}/codes/{codeId} | session | Revoke |
POST | /vouchers | session | Premium+. Mint a grant directly |
POST | /vouchers/exchange | none | Wallet exchanges a typed code. 200/hour/IP |
POST | /vouchers/redeem | none | Service-to-service. The signature is the authorization |
Policies
A multi-requirement policy engine — several credentials, per-requirement reasons — is in
the API but not yet wired end to end: the evaluation step is restricted to internal calls,
so a policy request cannot currently be driven to a verdict by a customer integration.
Documented here so you know it exists. Use verification requests for anything you are
shipping now.
| Method | Path | Auth | Notes |
|---|
POST | /policies | session | Premium+ |
GET | /policies/{id} | session | Members of the owning organization only |
POST | /policy-requests | apikey or session | Returns a deep-link token |
GET | /policy-requests/{token}/definition | none | Token-scoped, no personal data |
GET | /policy-requests/{id}/status | apikey or session | Verdict with per-requirement reasons |
POST | /policy-requests/{id}/evaluate | admin | Internal |
Other
| Method | Path | Auth | Notes |
|---|
GET | /ping | none | Health check. Returns {"message":"pong"} |
GET | /integrations/keys | session | Your API keys |
POST | /integrations/keys | session | Paid plan. Mint a key |
PUT | /integrations/keys/{id} | session | Rename |
DELETE | /integrations/keys/{id} | session | Revoke |
POST | /kyb/{org_id} | session | Submit KYB documents |
GET | /kyb, /kyb/{id} | session | KYB status |
POST | /media/upload | session | Multipart upload |
GET | /users | session | Your profile |
PUT | /users/profile | session | |
List endpoints take page (default 1) and limit (default 10, maximum 100 — values above
100 fall back to 10, they do not error). Filter with filter.<field>=<value>. Responses
are { "results": [...], "total": n }.
A note on /docs
api.shinid.com/docs and api.shinid.com/swagger.yaml now redirect here. They used to
serve an OpenAPI page describing eleven of these routes, last updated in August 2025, and
several of the shapes it documented had since changed — so anyone who found it by guessing
got worse information than this page. These pages are the reference.