Socious
Verifying people

Sandbox mode

A sandbox verification lets you drive the whole flow from your own code — no person, no wallet, no credential, no charge. It is the only way to exercise the paths that matter most and are hardest to rehearse: what your integration does when a condition fails, or when a credential arrives from an issuer you do not trust.

Sandbox verifications do not need a paid plan. You can integrate before you buy.

What is and is not simulated

Only the wallet is stood in for. A simulated presentation runs through the same validation code a real one does — the same issuer check, the same attribute conditions, in the same order — so a FAILED you see here is a FAILED you would have seen in production, with the same reason string.

What is skipped is the part that needs a human holding a phone: no DIDComm connection is opened, and no cloud agent is involved.

1. Create a sandbox verification

In the dashboard, or through the API with a session token:

curl -X POST https://api.shinid.com/verifications \
  -H "Authorization: Bearer SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Voting eligibility (test)",
    "description": "Integration testing",
    "schema_id": "SCHEMA_ID",
    "type": "MULTI",
    "sandbox": true,
    "trusted_issuers": ["did:prism:your-issuer"],
    "attributes": [
      { "attribute_id": "ATTRIBUTE_ID", "operator": "EQUAL", "value": "true" }
    ]
  }'

sandbox is returned on every verification and on the verification embedded in each result, so a relying party can never mistake a test verification for a real one.

The flag cannot be changed after creation. A live verification that could be flipped to sandbox would let anyone who can edit it forge VERIFIED results, so PUT ignores the field.

2. Open an individual and connect

Exactly as in the real flow:

curl -X POST https://api.shinid.com/verifications/individuals \
  -H "Content-Type: application/json" \
  -d '{ "verification_id": "VERIFICATION_ID", "customer_id": "test-user-1" }'

curl https://api.shinid.com/verifications/INDIVIDUAL_ID/connect

connect returns status: "REQUESTED" and a connection_url under /sandbox/connect/…. It is deliberately not a wallet invitation — nothing can scan it. The status advances the way a real connection would, so the lifecycle you poll is the one production will show you.

3. Simulate the presentation

curl -X POST https://api.shinid.com/verifications/INDIVIDUAL_ID/simulate \
  -H "apikey: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "issuer_did": "did:prism:your-issuer",
    "claims": { "liveness_verified": "true" }
  }'

claims are the credential’s claims as a wallet would have shared them. issuer_did is who would have signed it — supply an untrusted one to test your pinning.

The response is the settled individual. Three outcomes worth writing tests around:

You sendYou get
claims that satisfy every condition, from a trusted issuerVERIFIED
a claim that fails a conditionFAILED, validation_error naming the attribute
a trusted set that does not include your issuer_didFAILED, validation_error naming the refused issuer

The issuer is checked before the conditions, so a credential from an untrusted issuer is never rescued by carrying the right values.

simulate needs your API key or a session token, and refuses a verification your organization does not own.

Simulation cannot touch a live verification

Calling simulate on a non-sandbox verification returns 403:

{
  "error": "only a sandbox verification can be settled by simulation",
  "code": "NOT_SANDBOX"
}

This is the point of the sandbox flag rather than a convenience of it. An endpoint that accepted a caller’s account of what was presented and wrote VERIFIED onto a real person’s record would defeat the entire product, so a live individual can only ever be settled by a real presentation.

Billing and usage

Sandbox runs are excluded from verifications_completed, from the all-time totals, from the monthly history and from your quota. Test as much as you like; see Plans, tiers and usage.

Scope

Sandbox covers the verification flow, which is what an integration key reaches. There is no sandbox issuance — a sandbox verification cannot mint a credential, and issuing one for real still requires KYB and a paid plan.

There is one API host. A sandbox verification is a flag on a verification, not a separate environment, so you use the same base URL and the same key.