A verification provider tells you a session is Approved. Your onboarding service has to decide whether that word may change anything in your application. A bare status cannot answer that. It does not say which tenant and user the session belongs to, whether the session is still inside its deadline, or whether your own policy currently allows the action. This article proposes a hypothetical handoff contract that carries those facts. It then checks each field against the synthetic delivery fixture so you can decide whether a sandbox integration fits your identity onboarding task. Everything below runs locally with synthetic identifiers. No live adapter is described or implied.

The problem: a status without context

Suppose your handler receives a callback with status Approved and a session ID. If you act on that alone, three failures become possible. A callback bound to another tenant or user could unlock the wrong account. A late callback could revive a session your product already abandoned. An approval could grant an action that your policy has since disabled. The decision in front of you is what your handoff record must contain, and who owns each check. The fixture answers part of this question. Your application answers the rest.

Proposed handoff contract (application design, not implemented by GridZen)

We propose that every handoff record carry the following:

  1. Binding: session, tenant and subject, fixed when the session is created.
  2. Deadline: an absolute expiry, after which no status may grant anything.
  3. Caller policy: a policy_version and an allow_action flag, both owned by your application.
  4. Evidence state: the normalized status, plus whether a permission was granted and how many grants occurred.
  5. Next action: an explicit instruction, never an implied permission.

This is a design recommendation. GridZen's Bring Your Own Provider guide states that the current alpha does not accept arbitrary provider keys in a browser or request body. It also states that each provider product needs its own approved adapter and scope check, and that live route availability requires separate confirmation.

What the fixture actually implements

The Identity class stores each session in SQLite with these columns: id, tenant, subject, status, deadline, granted, grants, policy_version and allow_action.

The create method rejects any identifier that does not start with fixture-. It also rejects a timeout outside the range 1 to 3600 seconds.

The event method behaves as follows:

  • It accepts only mode synthetic_fixture with source fixture_callback. Anything else raises PRODUCTION_SIGNATURE_VERIFIER_NOT_IMPLEMENTED, because there is no real signature verification.
  • It raises BINDING_MISMATCH when the tenant or subject differs from the stored values.
  • It ignores duplicate event IDs.
  • It marks the session expired once now is at or past the deadline.
  • It maps an unrecognized status to unknown.
  • It grants permission only when the status is Approved, policy is True, and allow_action is set.

The handoff method returns the current record with verified set to false and next_action set to read_current_evidence_and_policy_before_explicit_decision. The decide method requires a matching policy_version, an explicit approval, an approved status inside the deadline, and allow_action. If the policy_version does not match, it raises STALE_POLICY_VERSION.

Worked hypothetical scenario and expected outputs

A hypothetical marketplace onboards a seller. The steps below use the fixture defaults.

  1. Create a session. The expected output includes session fixture-session, a hosted_link under example.invalid, link_executable false, and next send_real_provider_link_only_after_authorization.

  2. Send the event fixture-approved with policy True. The expected output is status approved, deadline 60, permission_granted true, grant_count 1, live_permission_changed false, policy_version 1 and allow_action true.

  3. Replay the same event. The output is identical, and grant_count stays at 1.

  4. Send a later event with status Declined. The output shows status declined and permission_granted false. grant_count remains 1, because it records history.

  5. In a fresh session where no callback arrives, call recover at now 61. The output shows status expired, permission_granted false, grant_count 0, next review_or_authorized_provider_refresh and provider_polled false.

  6. Errors behave as follows. An event for an unknown session returns BINDING_MISMATCH. A read for an unknown session returns SESSION_NOT_FOUND.

Failure handling your caller owns

The fixture names failures. Your application must decide what each one means.

  • BINDING_MISMATCH: treat it as a security event. Do not retry it.
  • STALE_POLICY_VERSION: re-read the policy and retry the decision.
  • Expired: route the session to review, or create a new authorized session.
  • Unknown status: hold the session for review.

The recover method expires sessions locally and never polls a provider. Refreshing evidence from a real provider is a separate, authorized integration.

A fixture grant is a local record. It is not live business permission, and live_permission_changed is always false. In the real hosted identity trial, GridZen verifies signed notifications and re-fetches authoritative decisions. However, a newly Approved user followed by a customer business action remains unverified end to end.

Acceptance checklist

Before you move from the fixture to a sandbox request, confirm each item:

  • Every handoff record stores session, tenant, subject and deadline at creation.
  • A mismatched tenant or subject is rejected and logged, not retried.
  • A duplicate event does not increase grant_count.
  • A callback that arrives after the deadline cannot grant anything.
  • A Declined event after an approval revokes permission_granted.
  • A policy change resets the grant, and a stale policy_version is refused.
  • No code path treats verified false as permission.
  • Retention, deletion, access logging and policy ownership are approved before any live use.

If your task needs a provider or country outside the confirmed routes, do not assume support exists. Ask for a scoping review first.

Run the checked synthetic example

Download and extract https://gridzen.ai/downloads/verification-delivery.zip, enter verification_delivery, then run with Python 3.10+. This local example makes no network calls. Use a fresh database for an independent identity run.

python3 delivery.py identity --db /tmp/gridzen-article-fixture.sqlite 

Sources and scope

https://gridzen.ai/guides/bring-your-own-provider/
https://gridzen.ai/guides/current-capabilities/
Based on the checked source snapshot and local fixture; proposed application rules are design advice, not proven production behavior. Written with AI assistance and reviewed independently.

curl https://gridzen.ai/console/api/quickstart/trial \ -H 'Content-Type: application/json' \ -d '{"task": "identity_onboarding", "scenario": "success"}' 

This is synthetic integration testing, not identity verification or production authorization. Real payments are disabled.

Create a free sandbox account · Integration guide

Written and tested by the GridZen team with AI assistance.