---
id: ts12-emandate-authorization
title: "TS12: E-Mandate Authorization"
hide_title: false
sidebar_label: E-Mandate Authorization
description: TS12 SCA workflow for e-mandate authorization using a Payment Account credential, including transaction data for recurring payment mandates.
keywords: [TS12, SCA, e-mandate, payment account, recurring payment, mandate authorization, OpenID4VP, EUDI Wallet, verifiable credentials]
slug: /ts12-emandate-authorization/
---

> **Build this with an AI coding agent.** Install the iGrant.io Agent Skills, then ask your agent to build the integration:
>
> ```bash
> npx skills add L3-iGrant/skills
> ```


import { ApiKeyManager } from "@site/src/components/ApiKeyManager";
import DcqlStepTemplate from "@site/src/components/DCQL/DcqlStepTemplate";

TS12 SCA e-mandate authorization enables a relying party to authorise a recurring payment mandate by requesting a Payment Account credential with transaction data that captures the mandate details, including payment schedule, amount, and creditor information.

**Scenario:** A bank requests e-mandate authorization from the user's Payment Account credential with transaction data describing a 60-month personal loan repayment mandate with monthly payments to Piggy Bank.

For the underlying TS12 specification and transaction data requirements, see the **"E-Mandate authorization"** use case in our [TS12 concepts article](/concepts/eudi-wallet-dcql-openid4vp-business-wallet-payments/#ts12-emandate-authorization).

## Step 1: Get the API Key (Issuer Admin)

To obtain your API key, please contact [support@igrant.io](mailto:support@igrant.io?subject=Request%20API%20Key). Once you have received your API key, enter it in the field below and click the **Set API Key** button to save it for future use.

<ApiKeyManager />

## Step 2: Create Credential Definition (Issuer Admin)

To create a credential definition, run the interactive block below using the **Run** button. Alternatively, you can manually copy the JSON and use it in the body of the API available [here](/docs/openid4vc-api/config-create-digital-wallet-open-id-credential-definition).

From the API response, copy the `credentialDefinitionId` and `id` value from the `credentialDefinitions` array for use in Step 3.

<DcqlStepTemplate
  initialJsonData={{
    label: "Payment Account",
    trustAnchor: "did:key",
    version: "version_01",
    kid: "",
    enforceWUA: false,
    supportInteractiveAuthorisationEndpoint: true,
    credentialDefinitions: [
      {
        label: "Payment Account Credential - TS12",
        expirationInDays: 60,
        supportRevocation: true,
        validationPath: "$",
        revocationMethod: "status_list",
        enforceCredentialUniqueness: false,
        supportCredentialReissuance: false,
        credentialBindingMethods: ["did:key", "jwk", "kid", "x5c"],
        authorizationRequestType: "authorization_details",
        scope: "",
        display: {
          name: "Payment Account",
          description: "Payment Account credential for SCA",
        },
        credentialResponseInterval: 20,
        credentialFormat: "dc+sd-jwt",
        vct: "https://staging-oid4vc.igrant.io/service/vct-metadata/payment_account",
        claims: {
          claims: [
            { limitDisclosure: true, mandatory: true, path: ["iban"] },
            { limitDisclosure: true, mandatory: true, path: ["bic"] },
            { limitDisclosure: true, mandatory: true, path: ["currency"] },
          ],
        },
      },
    ],
  }}
  endpointPath="/v2/config/digital-wallet/openid/sdjwt/credential-definition"
  method="POST"
  extractJsonResponse={(result) => result}
/>

## Step 3: Issue and Receive Credential (Issuer/Holder)

The holder of the wallet submits a request for the issuance of a credential by executing the JSON code block below using the **Run** button in `InTime` issuance mode. Replace `<credentialDefinitionId>` and `<id>` with the actual values obtained from the previous step. Alternatively, you may use the API available [here](/docs/openid4vc-api/config-digital-wallet-open-id-issue-credential).

After receiving the response, you can toggle the switch to dynamically generate a QR code. The EUDI Wallet/Holder can then accept the credential offer using the [Data Wallet](https://www.igrant.io/datawallet.html) (or any other EU Digital Identity Wallet) by either scanning the QR code or by directly accessing the credential offer on their mobile device (e.g. via a browser).

<DcqlStepTemplate
  initialJsonData={{
    issuanceMode: "InTime",
    credentialDefinitionId: "<credentialDefinitionId>",
    urlScheme: "openid-credential-offer://",
    credentials: [
      {
        id: "<id>",
        claims: {
          iban: "SE4109645307235006470086",
          bic: "ALPKOMO3XXX",
          currency: "SEK",
        },
      },
    ],
    userPin: "",
  }}
  endpointPath="/v2/config/digital-wallet/openid/sdjwt/credential/issue"
  method="POST"
  extractJsonResponse={(result) => result}
  extractQrValue={(result) => result?.credentialHistory?.credentialOffer}
/>

To receive and accept the credential via API. First, use the `credentialOffer` to call the [Receive Credential API](https://docs.igrant.io/docs/openid4vc-api/config-receive-digital-wallet-open-id-credential/). Once you have the response, copy the `credentialId` and provide it at [Accept Credential API](https://docs.igrant.io/docs/openid4vc-api/config-accept-digital-wallet-open-id-credential/) to accept the credential.

## Step 4: Create Presentation Definition (Verifier Admin)

To create a presentation definition for requesting proof, you can run the code block below using the **Run** button. Alternatively, you can manually copy the code block and use it in the body of the API request provided [here](/docs/openid4vc-api/config-digital-wallet-open-id-presentation-definition).

Once a presentation definition has been created, the `presentationDefinitionId` can be reused to verify multiple credentials (Step 5).

<DcqlStepTemplate
  initialJsonData={{
    label: "E-Mandate Authorization",
    kid: "",
    trustAnchor: "did:key",
    version: "version_01",
    scope: "",
    responseType: "vp_token",
    enforceWUA: false,
    transactionDataDefinitionType: "emandate",
    transactionDataDefinition: {
      $schema: "https://json-schema.org/draft/2020-12/schema",
      type: "object",
      properties: {
        transaction_id: {
          type: "string",
          maxLength: 36,
          minLength: 1,
          examples: ["8D8AC610-566D-4EF0-9C22-186B2A5ED793"],
        },
        date_time: {
          type: "string",
          format: "date-time",
          examples: ["2025-11-13T20:20:39+00:00"],
        },
        start_date: {
          type: "string",
          format: "date-time",
          examples: ["2025-11-13T20:20:39+00:00"],
        },
        end_date: {
          type: "string",
          format: "date-time",
          examples: ["2025-12-13T20:20:39+00:00"],
        },
        reference_number: {
          type: "string",
          maxLength: 50,
          minLength: 1,
          examples: ["A-98765"],
        },
        creditor_id: {
          type: "string",
          maxLength: 50,
          minLength: 1,
          examples: ["FR14ZZZ001122334455"],
        },
        purpose: {
          type: "string",
          maxLength: 1000,
          examples: ["Pay monthly bill"],
        },
        payment_payload: {
          $schema: "https://json-schema.org/draft/2020-12/schema",
          type: "object",
          properties: {
            transaction_id: {
              type: "string",
              maxLength: 36,
              minLength: 1,
              examples: ["8D8AC610-566D-4EF0-9C22-186B2A5ED793"],
            },
            date_time: {
              type: "string",
              format: "date-time",
              examples: ["2025-11-13T20:20:39+00:00"],
            },
            payee: {
              type: "object",
              properties: {
                name: { type: "string" },
                id: { type: "string" },
                logo: { type: "string", format: "uri" },
                website: { type: "string", format: "uri" },
              },
              required: ["name", "id"],
            },
            pisp: {
              type: "object",
              properties: {
                legal_name: { type: "string" },
                brand_name: { type: "string" },
                domain_name: { type: "string" },
              },
              required: ["legal_name", "brand_name", "domain_name"],
            },
            execution_date: { type: "string", format: "date-time" },
            currency: { type: "string", pattern: "^[A-Z]{3}$" },
            amount: { type: "number" },
            amount_estimated: { type: "boolean" },
            amount_earmarked: { type: "boolean" },
            sct_inst: { type: "boolean" },
            recurrence: {
              type: "object",
              properties: {
                start_date: { type: "string", format: "date-time" },
                end_date: { type: "string", format: "date-time" },
                number: { type: "integer" },
                frequency: {
                  type: "string",
                  enum: [
                    "INDA", "DAIL", "WEEK", "TOWK", "TWMN",
                    "MNTH", "TOMN", "QUTR", "FOMN", "SEMI",
                    "YEAR", "TYEA",
                  ],
                },
                mit_options: {
                  type: "object",
                  properties: {
                    amount_variable: { type: "boolean" },
                    min_amount: { type: "number" },
                    max_amount: { type: "number" },
                    total_amount: { type: "number" },
                    initial_amount: { type: "number" },
                    initial_amount_number: { type: "integer" },
                    apr: { type: "number" },
                  },
                },
              },
              required: ["frequency"],
            },
          },
          required: ["transaction_id", "payee", "currency", "amount"],
          additionalProperties: false,
        },
      },
      additionalProperties: false,
      required: ["transaction_id"],
    },
    clientIdScheme: "redirect_uri",
    responseMode: "direct_post",
    dcqlQuery: {
      credentials: [
        {
          id: "Payment Account Credential - TS12",
          format: "dc+sd-jwt",
          meta: {
            vct_values: [
              "https://staging-oid4vc.igrant.io/service/vct-metadata/payment_account",
            ],
          },
          claims: [
            { path: ["iban"] },
            { path: ["bic"] },
            { path: ["currency"] },
          ],
          require_cryptographic_holder_binding: true,
          multiple: false,
        },
      ],
    },
  }}
  endpointPath="/v2/config/digital-wallet/openid/sdjwt/presentation-definition"
  method="POST"
  extractJsonResponse={(result) => result}
/>

## Step 5: Create Verification Request (Verifier/Relying Party)

To create the verification request, execute the code block below using the **Run** button. Alternatively, you can manually copy the JSON and use it in the body of the API available [here](/docs/openid4vc-api/config-create-digital-wallet-open-id-verification-request-v-3). This step includes `transactionData` in the verification request payload, which is specific to TS12 SCA workflows. The `transactionData.payload` contains the transaction details that are dynamically linked to the user's authentication.

After receiving the response, toggle the button provided to dynamically generate a QR code. The EUDI Wallet/Holder can then accept the verification request using the Data Wallet (or any other EU Digital Identity Wallet) by either scanning the QR code or directly accessing the verification request on their mobile device, such as via a browser.

<DcqlStepTemplate
  initialJsonData={{
    requestByReference: true,
    transactionData: {
      payload: {
        transaction_id: "LOAN-EMANDATE-1747137600000",
        date_time: "2026-05-05T12:00:00.000Z",
        start_date: "2026-06-01",
        end_date: "2031-05-31",
        reference_number: "LOAN-REF-1747137600000",
        creditor_id: "PIGBANK-SE-001",
        purpose: "Authorize recurring monthly repayment for personal loan (60 months, 3.5% APR)",
        payment_payload: {
          transaction_id: "LOAN-PAY-1747137600000",
          date_time: "2026-05-05T12:00:00.000Z",
          payee: {
            name: "Piggy Bank",
            id: "PIGBANK-SE-001",
            logo: "https://www.piggybank.com/assets/logo.png",
            website: "https://www.piggybank.com",
          },
          execution_date: "2026-06-01",
          currency: "EUR",
          amount: 8.33,
          amount_estimated: false,
          amount_earmarked: false,
          sct_inst: true,
          recurrence: {
            start_date: "2026-06-01",
            end_date: "2031-05-01",
            number: 60,
            frequency: "MNTH",
          },
        },
      },
    },
    presentationDefinitionId: "<presentationDefinitionId>",
  }}
  endpointPath="/v3/config/digital-wallet/openid/sdjwt/verification/send"
  method="POST"
  extractJsonResponse={(result) => result}
  extractQrValue={(result) => result?.verificationHistory?.vpTokenQrCode}
/>

Users can copy the `presentationExchangeId` from the JSON response to track verification history.
