Skip to main content
At the end of this page, you will have run code that validates a against the and prints a decoded payload to stdout — including the sub, wallet, kyc_status, and scopes claims — proving your verifier is accepting live Sumvin credentials.

Prerequisites

  • A PINT JWT. Either grab one from a test partner, a sample incoming request, or the verification tiers reference for a sample token.
  • Your registered audience identifier (the value SIS puts in the JWT’s aud claim — provided during partner onboarding).
  • A JWT library. This page uses jose for TypeScript and PyJWT for Python.
No SIS API key is required for JWT verification — the JWKS endpoint is public.
1

Install a JWT library

bun add jose
2

Fetch the SIS JWKS

The JWKS endpoint is public and holds the ES256 keys SIS uses to sign PINT JWTs. Keys rotate, so use a remote JWK set helper that caches and auto-refreshes rather than hardcoding the payload.
curl https://sis.sumvin.com/v0/sis/.well-known/jwks.json
Response: 200 OK
{
  "keys": [
    {
      "kty": "EC",
      "crv": "P-256",
      "kid": "sis-001",
      "use": "sig",
      "alg": "ES256",
      "x": "...",
      "y": "..."
    }
  ]
}
Both jose.createRemoteJWKSet and PyJWKClient fetch and cache this response for you. You do not need to call this endpoint directly in production code.
3

Verify the JWT

Validate the signature, issuer, audience, expiry, and algorithm. Anything that fails throws — treat exceptions as verification failures and reject the request.
import * as jose from "jose";

const JWKS_URL = "https://sis.sumvin.com/v0/sis/.well-known/jwks.json";
const MY_AUDIENCE = "partner-x.example.com";
const JWKS = jose.createRemoteJWKSet(new URL(JWKS_URL));

async function verifyPint(token: string) {
  const { payload } = await jose.jwtVerify(token, JWKS, {
    issuer: "https://sis.sumvin.com",
    audience: MY_AUDIENCE,
    algorithms: ["ES256"],
  });
  return payload;
}

const payload = await verifyPint(process.env.PINT_JWT!);
console.log(JSON.stringify(payload, null, 2));
Pin algorithms: ["ES256"]. Accepting anything else — especially none or HS256 — opens you to key-confusion attacks.
4

Inspect the decoded payload

This is the working artefact. If the JWT is valid, you print a decoded payload that looks like this:
{
  "iss": "https://sis.sumvin.com",
  "sub": "sr:us:user:9f8d7e",
  "aud": "partner-x.example.com",
  "jti": "tkn_abc123",
  "iat": 1740000000,
  "exp": 1740003600,
  "wallet": "0xE23c9A70BC749EBddd8c78A864Fd911D04E9e992",
  "kyc_status": "verified",
  "scopes": [
    "sr:us:pint:identity:proof_of_personhood",
    "sr:us:pint:identity:kyc_status"
  ],
  "pint_uri": "sr:us:pint:def456",
  "signer_type": "user",
  "verification_tier": "standard"
}
Claims you act on:
ClaimMeaningReference
subThe user’s Sumvin Resource Identifier (SRI). Treat as the stable user ID.SRI format
walletThe user’s primary EOA address.Wallets guide
kyc_statusverified, pending, or none. Gate KYC-sensitive features on this.KYC guide
scopesThe SRI capability strings this PINT grants. Enforce what you permit against this list.Scopes reference
pint_uriStable identifier for the PINT — use this to check revocation.Revocation checks
verification_tierstandard here, enhanced when signatures are attached.Verification tiers
You have a verified PINT. The user is who SIS says they are, the scopes in front of you are authorised, and you have their SRI and wallet ready to act on.
5

Next: check revocation (optional)

A signed JWT proves identity at issuance, but users can revoke a PINT before the exp time. For high-stakes actions, hit the SIS revocation endpoint with the pint_uri from the payload before you act. See revocation checks for the full flow.

What’s next

NextWhereWhen
JWT deep diveVerify a JWTFull reference for signature, audience, and expiry validation
Tier pickerVerification tiersWhen you need to decide Standard vs Enhanced
RevocationRevocation checksBefore acting on high-stakes requests
JWKS detailJWKS referenceKey rotation and caching guidance