{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-docs/guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Verification Cases"},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"verification-cases","__idx":0},"children":["Verification Cases"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A verification case is a rule: which credentials are accepted, which attributes are asked for, and the constraints their values must meet. Launching a case starts a verification session that asks for exactly that; the holder's data comes back only when every constraint is met. Cases are made in the portal by people, or by your integration over this API, typically one per object you guard: a door, a zone, a ticket category."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You need a case when a check accepts more than one credential type, or when a presented value must meet a constraint; a check with one credential type and no constraints is a plain ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/guides/verification/flow#which-one-a-credential-definition-or-a-case"},"children":["credential definition session"]},". Any organization's case is launched by its id: if the case is not yours, ask its owner for the id."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Reading and launching cases requires the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deepcredentials.verify"]}," scope; creating, changing and archiving them requires ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deepcredentials.verification-cases"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/guides/authentication"},"children":["Authentication"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-a-case-is","__idx":1},"children":["What a case is"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A case accepts one or more ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["credential definitions"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["credential_definition_ids"]},"): your organization's own, official ones such as the Beta-ID, or any other organization's, by id. With several, the holder presents any one of them."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Its ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["requested attributes"]}," are what a session answers with. Each attribute has its own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]}," and is bound to a claim in every accepted credential (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bindings"]},", keyed by credential definition id), so a session answers with the same keys whichever credential the holder presented. A session's own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["requested_attributes"]}," carry the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bindings"]},", keyed by credential definition id. Where the credentials name the same fact differently, the bindings say so: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{\"<badge id>\": \"zone\", \"<pass id>\": \"area\"}"]},". What a presented value must satisfy sits under the attribute's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["constraints"]},": ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["values"]}," (allowed values, for text, choice and yes/no attributes) or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["min"]},"/",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["max"]}," (bounds, for numbers and dates, where a date may be relative such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["today-18y"]},"). An attribute without ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["constraints"]}," is only asked for; one with them is checked by the verifier. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["values"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["min"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["max"]}," at the attribute's top level are refused with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400 invalid_argument"]},", so a check is never silently dropped."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"constraints-by-claim-type","__idx":2},"children":["Constraints by claim type"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An attribute takes the type of the claims it is bound to, and the type decides which fields its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["constraints"]}," can carry:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"value_type of the bound claims"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["value_type"]}," of the bound claims"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Constraints"},"children":["Constraints"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["string"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["values"]},": the allowed strings"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["enum"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["values"]},": keys from the claim's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["options"]}," (a key that is not an option is refused)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["boolean"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["values"]},": ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["[true]"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["[false]"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["integer"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["number"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["min"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["max"]},": numbers, inclusive"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["date"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["min"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["max"]},": an ISO date (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2000-01-01"]},") or a date relative to the day of verification (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["today"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["today-18y"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["today+30d"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["today-6m"]},"), inclusive. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"constraints\": {\"max\": \"today-18y\"}"]}," on a birth date means at least 18 years old"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["image/jpeg"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["none: it can be asked for, not constrained"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An attribute without constraints just asks for the value. A claim's own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["rules"]}," in the credential definition (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["pattern"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["min_length"]}," and the like) are checked when a credential is issued and are not constraints of a case."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"building-a-case-from-a-definition","__idx":3},"children":["Building a case from a definition"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Read the definition with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /b2b/v1/credential-definitions/{credentialDefinitionId}"]}," (your own, an official one, or any other organization's: a definition id is not a secret, it is the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["vct"]}," of every credential of its type). Its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["claims"]}," map claim keys to their ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["value_type"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["display"]}," names and, for an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["enum"]},", its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["options"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For each fact the case asks for, add an attribute with your own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},", bind it to the claim key in every accepted definition, and add the constraints its type allows."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check the definitions' ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environments"]},": the case runs only where all of them are enabled."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"whose-case","__idx":4},"children":["Whose case"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A case is run by its id. It is one of your organization's own, or any other organization's whose id you were given: there is nothing to switch on, and either way it stays its owner's to change; you read and launch it. A case id is not a secret: it is in every QR code the case produces, and everything the case asks for (its accepted credential definitions, the claim paths it requests, the issuers it trusts) is in the OpenID4VP request object every launch produces, which any wallet fetches unauthenticated. Holding the id and the contract is what a verifier has anyway, so the platform does not pretend otherwise."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Another organization's case reads in the same shape as your own — its contract (accepted credentials, requested attributes with their ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bindings"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["constraints"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["version"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["launchable_versions"]}," to pin against, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environments"]},") and what the holder reads (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["name"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["presentation"]},") — without the owner's own bookkeeping: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reference_id"]}," is left out, and it reads only while it is not archived. A session you launch from it reads exactly like one of your own case, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bindings"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["accepted_issuer_dids"]}," included. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /b2b/v1/verification-cases"]}," lists only your organization's own cases; there is no catalogue of other organizations' cases."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["What stays the owner's: changing the case (its contract, texts and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reference_id"]},"), archiving it, granting it to its members, and seeing which organizations ran it. What the owner cannot do is keep anyone who holds the id from running it, short of archiving it."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"where-it-runs","__idx":5},"children":["Where it runs"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A case has no environment of its own: it runs wherever every credential it accepts is enabled, listed in its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environments"]},". ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /b2b/v1/verification-cases"]}," lists the cases that run in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Environment"]},"; add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["availability=all"]}," to see every case with its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environments"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"versions","__idx":6},"children":["Versions"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A case's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["version"]}," moves whenever what it asks for changes (credentials, attributes, constraints), never on a rename or a new purpose. Every session records the case and the version it ran, under ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["version"]},")."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Pin the version your integration was built against with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_version"]}," on a launch. A pin runs:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["current"]}," version, always;"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["an ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["older"]}," version while it is listed in the case's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["launchable_versions"]},". The owner can keep the version it replaces open when saving a new one (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["keep_previous_launchable"]},"), and close it later: a migration window, so integrations move to the new rule at their own pace. The launch then runs that older version's contract (its credentials, attributes and constraints) with the case's current texts."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Any other pin, an older version the owner has not kept open or a version that does not exist, is refused with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 aborted"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_version_mismatch"]},": re-read the case and upgrade deliberately. Without ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_version"]},", a launch always runs the current version."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"archived-cases","__idx":7},"children":["Archived cases"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A case its owner archived answers ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["404 not_found"]}," on launch, the same as an id that never existed. On read, another organization's archived case is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["404"]}," too; your own archived case still reads, with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["archived_at"]},", so you can restore it."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"what-the-verifier-learns","__idx":8},"children":["What the verifier learns"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A session's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["attributes"]}," come back only when every constraint of the case is met. A disclosed value that fails one closes the session as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["failed"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error_code: attribute_value_rejected"]}," and a fixed ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error_description"]}," that names neither the attribute nor the value, and nothing the holder disclosed is stored: which rule failed is what the case gates on."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"launching-a-case","__idx":9},"children":["Launching a case"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /b2b/v1/verification-cases/{caseId}/sessions"]}," starts a session in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Environment"]},", optionally pinned to a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_version"]},". A case that does not run in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Environment"]}," is refused with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400 failed_precondition"]},", a message starting ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_not_available:"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["details"]}," naming the environment and the credentials not enabled there (see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/guides/error-handling"},"children":["Error Handling"]},"), by id and name, whoever's case it is. A case whose date bounds have crossed since it was saved (a relative ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["min"]}," such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["today-10y"]}," that has overtaken an absolute ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["max"]},") cannot be passed by anyone: its launch is refused with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400 failed_precondition"]}," naming the attribute, until the case's author changes the bounds. The session is polled and reported like any other; see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/guides/verification/flow#launch-a-verification-case"},"children":["Verification Flow"]},". A launch takes ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_uri"]}," like any session: see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/guides/verification/same-device"},"children":["Same-Device Return"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/openapi/verification-cases-v1"},"children":["Open in API reference →"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"authoring-cases","__idx":10},"children":["Authoring cases"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["With the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deepcredentials.verification-cases"]}," scope your integration can author its own cases instead of having them made in the portal: typically one per access object, a door or a zone, with the rule that opens it. Key each case with your own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reference_id"]}," and find it again with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /b2b/v1/verification-cases?reference_id=door-7B"]}," (the list's defaults still apply: add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["availability=all"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["archived=include"]}," to find the case wherever it runs and whatever its state)."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"http","header":{"controls":{"copy":{}}},"source":"POST /b2b/v1/verification-cases\n{\n  \"reference_id\": \"door-7B\",\n  \"name\": \"Door 7B\",\n  \"presentation\": {\n    \"title\": [{ \"locale\": \"de\", \"name\": \"Zutritt Serverraum\" }, { \"locale\": \"en\", \"name\": \"Server room access\" }],\n    \"purpose\": [{ \"locale\": \"de\", \"name\": \"Zutritt zum Serverraum\" }, { \"locale\": \"en\", \"name\": \"Access to the server room\" }]\n  },\n  \"credential_definition_ids\": [\"5b0c…\"],\n  \"requested_attributes\": [\n    { \"id\": \"zone\", \"constraints\": { \"values\": [\"server-room\"] },\n      \"bindings\": { \"5b0c…\": \"zone\" } }\n  ]\n}\n","lang":"http"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every attribute needs a binding for every accepted credential, to a claim of the same type in each. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["value_type"]}," may be omitted: it is taken from the bound claims. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["label"]}," is an optional display name for your staff (the kiosk result and the session detail in the portal); the holder never sees it, their wallet shows its own claim labels. Without one, the bound claim's label is shown. What the holder reads is under ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["presentation"]},": ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["title"]},", the headline of the verification screen, and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["purpose"]},", why the verification asks, each one entry per language (at most 1000 characters per language for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["purpose"]},"). A launch may give a different ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["purpose"]}," for one run, as one string. Neither is part of the contract, so changing them never moves the version."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In the swiyu Sandbox, a case's request is published in the swiyu trust registry when it is first launched (a Verification Query Public Statement): its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["title"]}," as the name, its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["purpose"]}," as the description, the credentials and attributes it asks for, and the allowed values of their ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["constraints"]},". Anyone can read what is published; a launch's own one-run ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["purpose"]}," is not published. A case reads back in the same shape, so you can change what you read and send it back."]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Create"]}," answers with the case at ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["version"]}," 1 and the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environments"]}," it runs in; credentials that share no environment are refused with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400 invalid_argument"]},". A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reference_id"]}," already held by another of your cases is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 already_exists"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reference_id_conflict"]},"), with that case's id in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["details.case_id"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Update"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PUT /b2b/v1/verification-cases/{caseId}"]},") replaces the contract and texts. Send ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["expected_version"]}," with the version you read: if someone changed the case since (a person in the portal, another instance of your integration), the update is refused with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 aborted"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_version_mismatch"]},") instead of overwriting their change; a save that lands between your read and your write is refused the same way. Omitting ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reference_id"]}," keeps the current key. The version moves when what the case asks for changes; launches that pin the old version (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["case_version"]},") are then refused until they upgrade."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Archive"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PATCH …/archived {\"archived\": true}"]},") when the object goes away: launches answer ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["404"]},", updates ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400"]}," until you restore it with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{\"archived\": false}"]},". Sessions already run stay as they were."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A case has no environment to set: it runs wherever its credentials are enabled. On an update that moves the version, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["keep_previous_launchable"]}," keeps the replaced version in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["launchable_versions"]}," for integrations that pin it."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Cases you create are ordinary cases: they appear in the portal, where a manager can read and edit them, and the audit log names your service user as the author."]}]}]},"headings":[{"value":"Verification Cases","id":"verification-cases","depth":1},{"value":"What a case is","id":"what-a-case-is","depth":2},{"value":"Constraints by claim type","id":"constraints-by-claim-type","depth":3},{"value":"Building a case from a definition","id":"building-a-case-from-a-definition","depth":3},{"value":"Whose case","id":"whose-case","depth":3},{"value":"Where it runs","id":"where-it-runs","depth":3},{"value":"Versions","id":"versions","depth":3},{"value":"Archived cases","id":"archived-cases","depth":3},{"value":"What the verifier learns","id":"what-the-verifier-learns","depth":3},{"value":"Launching a case","id":"launching-a-case","depth":2},{"value":"Authoring cases","id":"authoring-cases","depth":2}],"frontmatter":{"seo":{"title":"Verification Cases"}},"lastModified":"2026-10-21T09:09:47.194Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/guides/verification/cases","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}