Corporate Mandate Verification quickstart

Verifies a wallet-held EWC (European Wallet Consortium) RB-004 “Signatory Rights” attestation instead of a PID: confirms whether a named natural person currently has authority to legally bind a specific company, alone or jointly. Same Nexiel Verify service, same POST /v1/verify/sessions route as every other check type. Only checkType: "corporate-mandate-verification" differs.

New to EUDI wallets? Read what an EU Digital Identity Wallet is, and how a session works before this page assumes you already know what OpenID4VP, DCQL, and SD-JWT VC mean.

What this is, and what this isn't

This is not a new verification engine. It is the same OpenID4VP session flow every other Nexiel Verify check type uses, requesting a different credential: dc+sd-jwt with vct_values: ["urn:eudi:signatory-rights:1"], the EWC RB-004 “Signatory Rights” attestation, instead of the PID's own vct. The wire format matches the PID's SD-JWT VC mechanics exactly. What it asks is different: not who someone is, but whether a named natural person currently has authority to bind a specific company, alone or jointly.

Trust for a Signatory Rights credential is resolved on a genuinely separate chain from a PID, an mDL, or an EU Age Verification attestation. EWC's rulebook names the issuer as “company registration offices” acting as “authentic sources,” governed by trust mechanisms defined at national level, not the eIDAS PID-Provider Trusted List, a road-transport authority's IACA program, or Nexiel's own vetted academic-issuer registry. See production status below for what that means for a live deployment.

This check requests only the “held by person” shape of RB-004: one named individual holding the mandate. RB-004 also defines a shape where one company holds signatory rights over another, a corporate mandate chain, which is out of scope here.

This check requests a signatory's full name, date of birth, and job title, alongside a company's own legal name and registration identifier: real, name-level detail about both a natural person and a legal entity. It deliberately does not request nationality or the job title's optional code sub-field, both real fields in the source schema this check does not need to answer the mandate question. It does not request a portrait. No check type in Nexiel Verify requests a photo claim.

Before you start: requesting access

Production access is gated. corporate-mandate-verification is the second Nexiel Verify check type gated this way, the same system mobile-driving-licence uses. A production request against it needs both an active Nexiel Verify account and a specifically APPROVED entitlement grant for this check type. Having Verify enabled is not enough by itself.

A signed-in member of your organization requests access from the dashboard's CheckType access page: pick corporate-mandate-verification and enter a declared use case (for example, "verifying a counter-signatory's authority before releasing funds held in escrow"). That creates a request in a PENDING state, visible on the same page alongside every other request your organization has made. A Nexiel reviewer approves or denies it from a separate reviewer queue. There is no automatic approval path for a gated check type. A denied or still-pending request is not silently retried. You can see its current status on the same dashboard page at any time.

A production request for corporate-mandate-verification made before approval, or after a denial, fails closed with a 403:

403 (no APPROVED entitlement for this organization)
{
  "error": "checktype_entitlement_denied",
  "message": "organization \"9d2b4f61-7a83-4c15-b6e2-8f04d3a91c67\" has never requested checkType \"corporate-mandate-verification\", which requires an approved entitlement grant before it can be used"
}

The same three-state message distinguishes a request that was never made from one still PENDING review, or one that was reviewed and DENIED. This gate runs after authentication and after the normal account-active check, and before rate limiting and anomaly tracking for the request.

Sandbox mode has no entitlement gate. An unauthenticated sandbox request (no Authorization header, a self-run instance with no VERIFY_API_MODEset) never reaches this check at all: it is a production, organization-scoped concept, the same "no-op outside production" scoping the account-active gate already uses. Every example below runs against sandbox mode.

The DCQL template

Real field names, taken directly from EWC's own published JSON Schema for the RB-004 Signatory Rights attestation:

corporate-mandate-verification.v1.json
{
  "id": "corporate-mandate-verification",
  "version": 1,
  "dcqlQuery": {
    "credentials": [
      {
        "id": "corporate_mandate_check",
        "format": "dc+sd-jwt",
        "meta": {
          "vct_values": [
            "urn:eudi:signatory-rights:1"
          ]
        },
        "claims": [
          {
            "path": [
              "legal_person_name"
            ]
          },
          {
            "path": [
              "legal_person_id"
            ]
          },
          {
            "path": [
              "signatory_rights",
              null,
              "full_name"
            ]
          },
          {
            "path": [
              "signatory_rights",
              null,
              "date_of_birth"
            ]
          },
          {
            "path": [
              "signatory_rights",
              null,
              "signatory_rule"
            ]
          },
          {
            "path": [
              "signatory_rights",
              null,
              "post",
              null,
              "name"
            ]
          }
        ]
      }
    ]
  }
}

The null entries inside signatory_rights and post are DCQL 1.0's array-wildcard convention: a null path segment matches every element of an array, since a session does not know in advance how many signatories, or how many job title entries under one signatory, a real wallet presentation will disclose.

This is the least certain claim structure in Nexiel Verify. EWC's schema for RB-004 confirms these field names exist, legal_person_name, legal_person_id, and, inside each signatory_rights entry, full_name, date_of_birth, signatory_rule, and a required postarray, but publishes no worked example JSON payload. Whether a real disclosed SD-JWT VC exposes those claims flat at the token's own top level, the same assumption every Nexiel Verify template makes, rather than nested under a credential_subjectwrapper, has not been checked against a real EWC or WE BUILD reference implementation, or a real issued credential. Unlike mobile driving licence's ISO 18013-5 namespace, which is unambiguous, treat this claim structure as a best-effort reading of the schema, not a confirmed one.

The vct value above, urn:eudi:signatory-rights:1, is a placeholder for the same reason. EWC has not published a real vctstring for this attestation anywhere in its rulebook or schema. This value follows Nexiel's own urn:eudi:<name>:<version>convention, the same pattern the PID's own confirmed urn:eudi:pid:1uses, but has not been checked against any real issuer's actual served value.

Create a session

The session-initiate step is a plain HTTP request you can call directly. Completing a session requires a wallet-signed SD-JWT VC presentation, which a bare HTTP client cannot produce on its own. The request and response below match this service's real sandbox-mode schema, the same shape documented on the Verify API reference.

curl -s -X POST https://compliance.nexiel.io/v1/verify/sessions \
  -H "Content-Type: application/json" \
  -d '{"clientId": "docs-example-client", "checkType": "corporate-mandate-verification"}'
200
{
  "sessionId": "b3f7a2e9-6c14-4de6-9c2a-8f0daf319b6c",
  "templateVersion": "corporate-mandate-verification@1",
  "authorizationRequest": {
    "client_id": "https://verify.nexiel.eu",
    "response_type": "vp_token",
    "response_mode": "direct_post",
    "response_uri": "https://compliance.nexiel.io/v1/verify/sessions/b3f7a2e9-6c14-4de6-9c2a-8f0daf319b6c/responses",
    "dcql_query": {
      "credentials": [
        {
          "id": "corporate_mandate_check",
          "format": "dc+sd-jwt",
          "meta": {
            "vct_values": [
              "urn:eudi:signatory-rights:1"
            ]
          },
          "claims": [
            {
              "path": [
                "legal_person_name"
              ]
            },
            {
              "path": [
                "legal_person_id"
              ]
            },
            {
              "path": [
                "signatory_rights",
                null,
                "full_name"
              ]
            },
            {
              "path": [
                "signatory_rights",
                null,
                "date_of_birth"
              ]
            },
            {
              "path": [
                "signatory_rights",
                null,
                "signatory_rule"
              ]
            },
            {
              "path": [
                "signatory_rights",
                null,
                "post",
                null,
                "name"
              ]
            }
          ]
        }
      ]
    },
    "nonce": "Wq2K9pL3vXcR6bYtM5nJ8aQ1sD4jE7gU0iO2zM9pB",
    "state": "H6mF1v8x3T0qN9rP2wZ5cA7nS4jG1kD3oB6iR0yQ4z"
  },
  "authorizationRequestUri": "openid4vp://authorize?client_id=https%3A%2F%2Fverify.nexiel.eu&response_type=vp_token&...(truncated)",
  "expiresAt": "2026-08-27T14:18:52.401Z"
}

The wallet discloses the mandate, and you get back a boolean

The wallet resolves authorizationRequestUri and answers with the SD-JWT VC presentation, POSTed back to response_uri. This check runs no AML or PEP screening at all: it is a mandate and authority check, nothing more. A wallet whose Signatory Rights credential verifies against a trusted issuer produces:

POST /v1/verify/sessions/{sessionId}/responses
{
  "sessionId": "b3f7a2e9-6c14-4de6-9c2a-8f0daf319b6c",
  "method": "eudi_wallet",
  "booleanProofs": {
    "claimsVerified": true
  },
  "amlResult": null,
  "pepFlag": null,
  "sanctionedFlag": null,
  "listsChecked": [],
  "humanReviewRequired": false,
  "templateVersion": "corporate-mandate-verification@1",
  "frozenDecisionArtifact": null
}

amlResult, pepFlag, sanctionedFlag, listsChecked, and frozenDecisionArtifact are all null or empty for the same reason they are on an age-verification or login-authentication check: no matching engine ever runs here, so there is no screening decision to human-review or freeze. This callback reply never includes the disclosed claims or an evidence pack. See below for how those are delivered instead.

A Signatory Rights credential signed by an issuer this deployment does not trust fails closed. The session is marked failed and the disclosed claims are discarded. No partial result is ever returned.

The evidence pack

The disclosed claims are never stored by Nexiel as plaintext. They are encrypted into an “evidence pack,” JWE compact serialized (ECDH-ES, A256GCM, P-256), to a public key your organization registers and controls, the same mechanism every other identity-adjacent check type in Nexiel Verify uses. See setting up evidence pack encryption for how to generate and register that key from the dashboard.

This check runs no AML or sanctions screening, so its payload is narrower than an aml-identityevidence pack: no screening decision, no frozen decision artifact, only the disclosed claims and the wallet's issuer signature validation result. Decrypted, it holds:

Decrypted evidence pack payload
{
  "method": "corporate-mandate-verification",
  "timestamp": "2026-08-27T14:19:07.918Z",
  "disclosedClaims": {
    "legalPersonName": "Kilkenny Precision Engineering Ltd",
    "legalPersonId": "IE-CRO-611234",
    "signatoryRights": [
      {
        "full_name": "Aoife Ní Bhriain",
        "date_of_birth": "1980-03-22",
        "signatory_rule": "alone",
        "post": [
          {
            "name": "Managing Director"
          }
        ]
      }
    ]
  },
  "issuerSignatureValidation": {
    "valid": true,
    "credentialProofRef": "7c1a9e4f2b6d8305a1c7e9b2d4f6a8305c1e7b9d2f4a6c8305f1a9c7e2b4d6f8"
  }
}

credentialProofRef is a SHA-256 hash of the presented wallet token, never the raw token itself, the same convention every other evidence pack in Nexiel Verify uses. signatoryRights is relayed exactly as the wallet disclosed it, in its own field names and nesting, and is included only when disclosed.

Nexiel's own retention for this check stops at a minimal audit row: the session id, client id, timestamp, template version, and a SHA-256 hash of the delivered ciphertext, proof a pack was generated and handed off, never its contents. Whatever record-keeping obligation a relying party has for a mandate or signatory-authority record is that organization's own responsibility on its own systems, the same way it is for every check type Nexiel Verify offers.

Collect it the same way as an aml-identity evidence pack: a follow-up GET /v1/verify/sessions/{sessionId} call.

What gets persisted

Production status

Sandbox mode is fully real and usable today,exactly as shown above, no entitlement request or bearer token required. Production is gated behind a real, external infrastructure gap, not a code gap: verifying a Signatory Rights credential against a real issuer requires this deployment to be configured with that issuer's trust anchors, and no EU-wide, publicly fetchable trusted list of company-registration-office Signatory Rights issuers has been confirmed to exist for this integration, the same real gap mobile driving licence's own issuer trust anchors have. A production deployment populates trust anchors per issuing jurisdiction as it obtains and verifies them out of band. Without one configured, production verification of a real Signatory Rights credential fails closed, the same discipline every credential type in Nexiel Verify uses when it cannot resolve trust.

This is independent of the entitlement gate above. An organization can be fully approved for corporate-mandate-verificationand still have every production request fail closed at the trust-resolution step until this deployment has a real jurisdiction's Signatory Rights issuer trust anchors configured.

Reference

There is no separate corporate mandate verification API reference. Every route, parameter, and response schema this page uses is documented on the Verify API reference. The routes this page walks through are POST /v1/verify/sessions and POST /v1/verify/sessions/{sessionId}/responses, with checkType: "corporate-mandate-verification".