> ## Documentation Index
> Fetch the complete documentation index at: https://docs.finhub.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Consent Verification API

> Verify consents via email, magic links, and tokens

# Consent Verification API

APIs for verifying customer consents through various methods including email resend, magic links, and token verification.

<Info>
  **Base URL:** `https://sandbox.finhub.cloud/api/v2.1/consent/verification`
</Info>

## Available Operations

<CardGroup cols={2}>
  <Card title="Resend Verification" icon="paper-plane">
    `POST /resend`
  </Card>

  <Card title="Send Magic Link" icon="wand-magic-sparkles">
    `POST /send-magic-link`
  </Card>

  <Card title="Verify Token" icon="check-circle">
    `GET /verify/{token}`
  </Card>

  <Card title="Accept Consent" icon="file-contract">
    `POST /consents/{type}`
  </Card>
</CardGroup>

***

## Accept Consent

<Note>Directly accept a consent on behalf of a customer (used in onboarding flows).</Note>

### Endpoints

* `POST /api/v2.1/customer/individual/{customerId}/consents/terms`
* `POST /api/v2.1/customer/individual/{customerId}/consents/privacy`
* `POST /api/v2.1/customer/individual/{customerId}/consents/data-processing`
* `POST /api/v2.1/customer/organization/{organizationId}/consents/terms`
* `POST /api/v2.1/customer/organization/{organizationId}/consents/privacy`
* `POST /api/v2.1/customer/organization/{organizationId}/consents/data-processing`

### Request Body

<ParamField body="accepted" type="boolean" required>
  Whether the consent is accepted

  Example: `true`
</ParamField>

<ParamField body="version" type="string" required>
  Consent version

  Example: `"1.0"`
</ParamField>

### Headers

<ParamField header="X-Tenant-ID" type="string" required>
  Tenant identifier
</ParamField>

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`
</ParamField>

<ParamField header="X-Forwarded-From" type="string" required>
  Source identifier for request origin tracking
</ParamField>

<ParamField header="User-Agent" type="string" required>
  Client application identifier — required by the global request filter
</ParamField>

<ParamField header="platform" type="string" required>
  Client platform identifier. Also accepted as `sec-ch-ua-platform`
</ParamField>

<ParamField header="deviceId" type="string" required>
  Unique device identifier for session tracking. Also accepted as `X-Device-Id` or `device-id`
</ParamField>

### Code Example

```bash cURL - Terms Consent theme={null}
curl -X POST "https://sandbox.finhub.cloud/api/v2.1/customer/individual/de645b7b-219a-4fdf-bd59-a7bf454a0586/consents/terms" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
  -H "X-Forwarded-From: e2e-test" \
  -H "User-Agent: YourApp/1.0" \
  -H "platform: web" \
  -H "deviceId: e2e-test-device" \
  -d '{
    "accepted": true,
    "version": "1.0"
  }'
```

### Response

<ResponseExample>
  ```json 200 - Success theme={null}
  {
    "code": 200,
    "data": {
      "verificationId": "f778e9d2-9097-4328-9b76-8f225d48c9aa",
      "status": "PENDING",
      "verificationType": "CONSENT",
      "updatedAt": "2026-03-10T07:10:04.068Z",
      "updatedBy": "7e14ae4c-1e6c-4792-83f0-2263f2d13bce"
    },
    "message": "Success"
  }
  ```
</ResponseExample>

***

***

## Resend Verification

<Note>Resends the consent verification email to the customer.</Note>

### Request

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication
</ParamField>

<ParamField header="X-Tenant-ID" type="string" required>
  Tenant identifier
</ParamField>

<ParamField body="customerId" type="string" required>
  Customer identifier
</ParamField>

<ParamField body="consentId" type="string" required>
  Consent identifier to verify
</ParamField>

<ParamField body="channel" type="string">
  Delivery channel: `EMAIL`, `SMS` (default: `EMAIL`)
</ParamField>

### Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://sandbox.finhub.cloud/api/v2.1/consent/verification/resend" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
    -H "X-Forwarded-From: e2e-test" \
    -H "User-Agent: YourApp/1.0" \
    -H "platform: web" \
    -H "deviceId: 356938035643809" \
    -d '{
      "customerId": "cust_12345",
      "consentId": "cons_67890",
      "channel": "EMAIL"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://sandbox.finhub.cloud/api/v2.1/consent/verification/resend',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`,
        'X-Tenant-ID': '97e7ff29-15f3-49ef-9681-3bbfcce4f6cd',
        'X-Forwarded-From': 'e2e-test',
        'User-Agent': 'YourApp/1.0',
        'platform': 'web',
        'deviceId': '356938035643809'
      },
      body: JSON.stringify({
        customerId: 'cust_12345',
        consentId: 'cons_67890',
        channel: 'EMAIL'
      })
    }
  );

  const { data } = await response.json();
  console.log('Verification sent:', data.sentAt);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://sandbox.finhub.cloud/api/v2.1/consent/verification/resend',
      headers={
          'Content-Type': 'application/json',
          'Authorization': f'Bearer {access_token}',
          'X-Tenant-ID': '97e7ff29-15f3-49ef-9681-3bbfcce4f6cd',
          'X-Forwarded-From': 'e2e-test',
          'User-Agent': 'YourApp/1.0',
          'platform': 'web',
          'deviceId': '356938035643809'
      },
      json={
          'customerId': 'cust_12345',
          'consentId': 'cons_67890',
          'channel': 'EMAIL'
      }
  )

  data = response.json()['data']
  print(f"Verification sent at: {data['sentAt']}")
  ```
</CodeGroup>

<ResponseExample>
  ```json 200 - Success theme={null}
  {
    "success": true,
    "data": {
      "customerId": "cust_12345",
      "consentId": "cons_67890",
      "channel": "EMAIL",
      "sentAt": "2024-01-15T10:30:00Z",
      "expiresAt": "2024-01-15T11:30:00Z"
    }
  }
  ```

  ```json 429 - Too Many Requests theme={null}
  {
    "success": false,
    "error": {
      "code": "RATE_LIMIT_EXCEEDED",
      "message": "Too many verification requests. Please wait before trying again.",
      "retryAfter": 300
    }
  }
  ```
</ResponseExample>

***

## Send Magic Link

<Note>Sends a magic link for one-click consent verification.</Note>

### Request

<ParamField body="customerId" type="string" required>
  Customer identifier
</ParamField>

<ParamField body="consentId" type="string" required>
  Consent identifier to verify
</ParamField>

<ParamField body="redirectUrl" type="string">
  URL to redirect after verification (must be whitelisted)
</ParamField>

<ParamField body="expiresInMinutes" type="integer">
  Link expiration time in minutes (default: 60, max: 1440)
</ParamField>

### Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://sandbox.finhub.cloud/api/v2.1/consent/verification/send-magic-link" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
    -H "X-Forwarded-From: e2e-test" \
    -H "User-Agent: YourApp/1.0" \
    -H "platform: web" \
    -H "deviceId: 356938035643809" \
    -d '{
      "customerId": "cust_12345",
      "consentId": "cons_67890",
      "redirectUrl": "https://your-app.com/consent-confirmed",
      "expiresInMinutes": 60
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://sandbox.finhub.cloud/api/v2.1/consent/verification/send-magic-link',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`,
        'X-Tenant-ID': '97e7ff29-15f3-49ef-9681-3bbfcce4f6cd',
        'X-Forwarded-From': 'e2e-test',
        'User-Agent': 'YourApp/1.0',
        'platform': 'web',
        'deviceId': '356938035643809'
      },
      body: JSON.stringify({
        customerId: 'cust_12345',
        consentId: 'cons_67890',
        redirectUrl: 'https://your-app.com/consent-confirmed',
        expiresInMinutes: 60
      })
    }
  );

  const { data } = await response.json();
  console.log('Magic link sent, expires:', data.expiresAt);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://sandbox.finhub.cloud/api/v2.1/consent/verification/send-magic-link',
      headers={
          'Content-Type': 'application/json',
          'Authorization': f'Bearer {access_token}',
          'X-Tenant-ID': '97e7ff29-15f3-49ef-9681-3bbfcce4f6cd',
          'X-Forwarded-From': 'e2e-test',
          'User-Agent': 'YourApp/1.0',
          'platform': 'web',
          'deviceId': '356938035643809'
      },
      json={
          'customerId': 'cust_12345',
          'consentId': 'cons_67890',
          'redirectUrl': 'https://your-app.com/consent-confirmed',
          'expiresInMinutes': 60
      }
  )

  data = response.json()['data']
  print(f"Magic link expires: {data['expiresAt']}")
  ```
</CodeGroup>

<ResponseExample>
  ```json 200 - Success theme={null}
  {
    "success": true,
    "data": {
      "customerId": "cust_12345",
      "consentId": "cons_67890",
      "sentTo": "j***@example.com",
      "sentAt": "2024-01-15T10:30:00Z",
      "expiresAt": "2024-01-15T11:30:00Z"
    }
  }
  ```

  ```json 400 - Invalid Redirect URL theme={null}
  {
    "success": false,
    "error": {
      "code": "INVALID_REDIRECT_URL",
      "message": "Redirect URL is not whitelisted for this tenant"
    }
  }
  ```
</ResponseExample>

***

## Verify Token

<Note>Verifies a consent using the token from the verification email or magic link.</Note>

### Request

<ParamField path="token" type="string" required>
  Verification token from email or magic link
</ParamField>

<ParamField header="X-Tenant-ID" type="string" required>
  Tenant identifier
</ParamField>

### Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://sandbox.finhub.cloud/api/v2.1/consent/verification/verify/eyJhbGciOiJIUzI1NiIs..." \
    -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
    -H "X-Forwarded-From: e2e-test" \
    -H "User-Agent: YourApp/1.0" \
    -H "platform: web" \
    -H "deviceId: 356938035643809"
  ```

  ```javascript JavaScript theme={null}
  const token = 'eyJhbGciOiJIUzI1NiIs...';

  const response = await fetch(
    `https://sandbox.finhub.cloud/api/v2.1/consent/verification/verify/${token}`,
    {
      headers: {
        'X-Tenant-ID': '97e7ff29-15f3-49ef-9681-3bbfcce4f6cd',
        'X-Forwarded-From': 'e2e-test',
        'User-Agent': 'YourApp/1.0',
        'platform': 'web',
        'deviceId': '356938035643809'
      }
    }
  );

  const { data } = await response.json();
  if (data.verified) {
    console.log('Consent verified successfully!');
    console.log('Redirect to:', data.redirectUrl);
  }
  ```

  ```python Python theme={null}
  import requests

  token = 'eyJhbGciOiJIUzI1NiIs...'

  response = requests.get(
      f'https://sandbox.finhub.cloud/api/v2.1/consent/verification/verify/{token}',
      headers={
          'X-Tenant-ID': '97e7ff29-15f3-49ef-9681-3bbfcce4f6cd',
          'X-Forwarded-From': 'e2e-test',
          'User-Agent': 'YourApp/1.0',
          'platform': 'web',
          'deviceId': '356938035643809'
      }
  )

  data = response.json()['data']
  if data['verified']:
      print('Consent verified successfully!')
      print(f"Redirect to: {data['redirectUrl']}")
  ```
</CodeGroup>

<ResponseExample>
  ```json 200 - Success theme={null}
  {
    "success": true,
    "data": {
      "verified": true,
      "customerId": "cust_12345",
      "consentId": "cons_67890",
      "consentType": "TERMS",
      "verifiedAt": "2024-01-15T10:35:00Z",
      "redirectUrl": "https://your-app.com/consent-confirmed"
    }
  }
  ```

  ```json 400 - Invalid Token theme={null}
  {
    "success": false,
    "error": {
      "code": "INVALID_TOKEN",
      "message": "Verification token is invalid or malformed"
    }
  }
  ```

  ```json 410 - Token Expired theme={null}
  {
    "success": false,
    "error": {
      "code": "TOKEN_EXPIRED",
      "message": "Verification token has expired"
    }
  }
  ```
</ResponseExample>

***

## Verification Flow

<Steps>
  <Step title="Request Verification">
    Call `/resend` or `/send-magic-link` to send verification to customer
  </Step>

  <Step title="Customer Clicks Link">
    Customer receives email and clicks the verification link
  </Step>

  <Step title="Token Validation">
    System validates the token via `/verify/{token}`
  </Step>

  <Step title="Consent Confirmed">
    Consent status updated to `ACCEPTED` and customer redirected
  </Step>
</Steps>

## Delivery Channels

| Channel | Description                            |
| ------- | -------------------------------------- |
| `EMAIL` | Verification sent via email            |
| `SMS`   | Verification sent via SMS (if enabled) |

## Response Codes

| Code  | Description                   |
| ----- | ----------------------------- |
| `200` | Operation successful          |
| `400` | Invalid request data or token |
| `401` | Not Authorized                |
| `403` | Not Allowed                   |
| `404` | Consent or customer not found |
| `410` | Token expired                 |
| `429` | Rate limit exceeded           |
| `500` | Internal server error         |
