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

# Create Onboarding Consent

> Create a new consent set during user onboarding before a userId exists

## Overview

Creates a new consent set during user onboarding using the `onboardingId` from the registration flow. This endpoint is typically called **after** personal details submission and **before** address submission during the [registration flow](/guides/user/registration).

<Warning>
  Use the `onboardingId` returned from email verification (`POST /v1/auth/register/email/verify`) - do NOT generate a new ID. This links the consent to the user's registration session.
</Warning>

## Use Cases

<CardGroup cols={2}>
  <Card title="Mobile App Registration" icon="mobile">
    Collect consent during mobile app onboarding flows
  </Card>

  <Card title="Web Registration" icon="browser">
    Capture consent on web registration forms
  </Card>

  <Card title="KYC Processes" icon="id-card">
    Record consent during identity verification
  </Card>

  <Card title="Pre-Registration Consent" icon="clipboard-check">
    Collect consent before user account creation
  </Card>
</CardGroup>

## Endpoint

```
POST https://api.baanx.com/v2/consent/onboarding
```

## Headers

| Header         | Required | Description                         |
| -------------- | -------- | ----------------------------------- |
| `x-client-key` | ✅        | Your public API key                 |
| `x-secret-key` | ✅        | Your secret API key (keep secure)   |
| `Content-Type` | ✅        | Must be `application/json`          |
| `x-us-env`     | ❌        | Set to `true` for US region routing |

<Warning>
  **Security:** The `x-secret-key` should only be used in server-side code. Never expose it in client-side applications.
</Warning>

## Request Body

### Parameters

| Parameter      | Type   | Required | Description                                             |
| -------------- | ------ | -------- | ------------------------------------------------------- |
| `onboardingId` | string | ✅        | Unique temporary identifier for this onboarding session |
| `tenantId`     | string | ✅        | Your tenant identifier (provided by Baanx)              |
| `policyType`   | string | ✅        | Policy type: `global` or `US`                           |
| `consents`     | array  | ✅        | Array of consent items to record (min 1 item)           |
| `metadata`     | object | ❌        | Additional metadata about the consent capture session   |

### Consent Item Structure

| Field           | Type   | Required | Description                                           |
| --------------- | ------ | -------- | ----------------------------------------------------- |
| `consentType`   | string | ✅        | Type of consent (see [Consent Types](#consent-types)) |
| `consentStatus` | string | ✅        | Status: `granted` or `denied`                         |
| `metadata`      | object | ❌        | Additional context for this specific consent          |

### Consent Types

| Type                     | Description                                            | Required In    |
| ------------------------ | ------------------------------------------------------ | -------------- |
| `eSignAct`               | Electronic signature agreement (E-Sign Act compliance) | US policy only |
| `termsAndPrivacy`        | Terms of service and privacy policy                    | All policies   |
| `marketingNotifications` | Marketing communications opt-in                        | All policies   |
| `smsNotifications`       | SMS/text message notifications                         | All policies   |
| `emailNotifications`     | Email notifications                                    | All policies   |

### Metadata Fields (Optional)

| Field       | Type   | Description                                  |
| ----------- | ------ | -------------------------------------------- |
| `ipAddress` | string | User's IP address at time of consent         |
| `userAgent` | string | Browser/device user agent string             |
| `timestamp` | string | ISO 8601 timestamp when consent was captured |
| `clientId`  | string | Client application identifier                |
| `version`   | string | API or app version                           |

<Info>
  Additional custom fields can be included in `metadata`. All fields must be JSON-serializable.
</Info>

## Examples

### US Policy (All 5 Consents)

```json theme={null}
{
  "onboardingId": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "tenantId": "tenant_baanx_prod",
  "policyType": "US",
  "consents": [
    {
      "consentType": "eSignAct",
      "consentStatus": "granted"
    },
    {
      "consentType": "termsAndPrivacy",
      "consentStatus": "granted"
    },
    {
      "consentType": "marketingNotifications",
      "consentStatus": "granted"
    },
    {
      "consentType": "smsNotifications",
      "consentStatus": "denied"
    },
    {
      "consentType": "emailNotifications",
      "consentStatus": "granted"
    }
  ],
  "metadata": {
    "ipAddress": "192.168.1.1",
    "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)",
    "timestamp": "2024-01-15T10:30:00Z",
    "clientId": "mobile-app-ios-v2.1.0"
  }
}
```

### Global Policy (4 Consents, No eSignAct)

```json theme={null}
{
  "onboardingId": "200b88de-e39c-52e5-8cd9-3f9944b31fcc",
  "tenantId": "tenant_baanx_global",
  "policyType": "global",
  "consents": [
    {
      "consentType": "termsAndPrivacy",
      "consentStatus": "granted"
    },
    {
      "consentType": "marketingNotifications",
      "consentStatus": "granted"
    },
    {
      "consentType": "smsNotifications",
      "consentStatus": "granted"
    },
    {
      "consentType": "emailNotifications",
      "consentStatus": "granted"
    }
  ]
}
```

## Response

### 201 Created

**Success Response:**

```json theme={null}
{
  "consentSetId": "550e8400-e29b-41d4-a716-446655440001",
  "onboardingId": "onboarding_abc123xyz",
  "tenantId": "tenant_baanx_prod",
  "createdAt": "2024-01-15T10:30:00Z",
  "_links": {
    "self": {
      "href": "https://api.baanx.com/v2/consent/consentSet/550e8400-e29b-41d4-a716-446655440001",
      "method": "GET"
    }
  }
}
```

**Response Fields:**

| Field          | Type              | Description                                      |
| -------------- | ----------------- | ------------------------------------------------ |
| `consentSetId` | string (UUID)     | Generated unique identifier for this consent set |
| `onboardingId` | string            | Your provided onboarding identifier              |
| `tenantId`     | string            | Your tenant identifier                           |
| `createdAt`    | string (ISO 8601) | Timestamp when consent set was created           |
| `_links`       | object            | HATEOAS links for related resources              |

<Info>
  **Store the `consentSetId`**: You'll need this to link the user after account creation completes.
</Info>

### 400 Bad Request - Missing Required Consents

```json theme={null}
{
  "error": "Validation error",
  "details": [
    "Missing required consent: termsAndPrivacy for policy type: global"
  ]
}
```

**Cause:** Not all required consents for the policy type are present.

**Required Consents:**

* **US Policy**: All 5 types (including `eSignAct` for E-Sign Act compliance)
* **Global Policy**: 4 types (excludes `eSignAct`)

### 400 Bad Request - Invalid Consent Type

```json theme={null}
{
  "error": "Validation error",
  "details": [
    "Invalid consentType: 'pushNotifications'. Must be one of: eSignAct, termsAndPrivacy, marketingNotifications, smsNotifications, emailNotifications"
  ]
}
```

**Cause:** Using an unsupported consent type.

### 409 Conflict - Duplicate Onboarding ID

```json theme={null}
{
  "error": "Conflict",
  "details": [
    "Consent set with onboardingId 'onboarding_abc123' already exists"
  ]
}
```

**Cause:** The `onboardingId` has already been used.

**Solution:** Generate a new unique `onboardingId` and retry.

### 498 Invalid Client Key

```json theme={null}
{
  "error": "Invalid client key",
  "details": [
    "The provided x-client-key is invalid or expired"
  ]
}
```

**Cause:** Invalid or expired API credentials.

### 499 Missing Client Key

```json theme={null}
{
  "error": "Missing client key",
  "details": [
    "x-client-key header is required for all requests"
  ]
}
```

**Cause:** Missing `x-client-key` header.

## Validation Rules

<AccordionGroup>
  <Accordion title="Onboarding ID Requirements">
    * Must be the `onboardingId` from registration email verification
    * Do NOT generate a new ID - use the ID from `POST /v1/auth/register/email/verify`
    * Format: UUID string (e.g., `100a99cf-f4d3-4fa1-9be9-2e9828b20ebb`)

    ```typescript theme={null}
    // ✅ Correct: Use onboardingId from registration
    const { onboardingId } = await verifyEmail(email, code);
    await createConsent(onboardingId, consents);

    // ❌ Wrong: Do not generate new ID
    // const onboardingId = `onboarding_${uuid()}`;
    ```
  </Accordion>

  <Accordion title="Policy Type Requirements">
    **US Policy** requires all 5 consent types (E-Sign Act compliance):

    * `eSignAct` (required for E-Sign Act compliance)
    * `termsAndPrivacy`
    * `marketingNotifications`
    * `smsNotifications`
    * `emailNotifications`

    **Global Policy** requires 4 consent types (excludes `eSignAct`):

    * `termsAndPrivacy`
    * `marketingNotifications`
    * `smsNotifications`
    * `emailNotifications`
  </Accordion>

  <Accordion title="Consent Status Values">
    Only two status values are valid for creation:

    * `granted`: User has provided consent
    * `denied`: User has explicitly refused consent

    <Note>
      Both `granted` and `denied` are acceptable. However, if required consents are `denied`, the user's overall consent status will be `incomplete`.
    </Note>
  </Accordion>

  <Accordion title="Metadata Best Practices">
    Include these fields for comprehensive audit trails:

    ```typescript theme={null}
    metadata: {
      ipAddress: req.ip,
      userAgent: req.headers['user-agent'],
      timestamp: new Date().toISOString(),
      clientId: 'web-app-v1.2.0',
      sessionId: req.session.id,
      privacyPolicyVersion: 'v2.1',
      termsVersion: 'v3.0'
    }
    ```

    All values must be JSON-serializable (no functions, circular references, or undefined).
  </Accordion>
</AccordionGroup>

## Code Examples

### TypeScript

```typescript theme={null}
async function createOnboardingConsent(
  onboardingId: string, // From registration email verification
  consents: Array<{ type: string; status: 'granted' | 'denied' }>,
  userIp: string,
  userAgent: string
) {
  const response = await fetch('https://api.baanx.com/v2/consent/onboarding', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-client-key': process.env.BAANX_CLIENT_KEY!,
      'x-secret-key': process.env.BAANX_SECRET_KEY!
    },
    body: JSON.stringify({
      onboardingId, // Use ID from registration, don't generate new one
      tenantId: 'tenant_baanx_prod',
      policyType: 'US',
      consents: consents.map(c => ({
        consentType: c.type,
        consentStatus: c.status
      })),
      metadata: {
        ipAddress: userIp,
        userAgent: userAgent,
        timestamp: new Date().toISOString(),
        clientId: 'web-app-v1.2.0'
      }
    })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Consent creation failed: ${error.details.join(', ')}`);
  }

  const { consentSetId } = await response.json();
  return consentSetId;
}

// Get onboardingId from registration flow (Step 2)
const { onboardingId } = await verifyEmailCode(email, verificationCode);

// Create consent during registration (Step 4 - before address submission)
const consentSetId = await createOnboardingConsent(
  onboardingId, // From registration
  [
    { type: 'eSignAct', status: 'granted' },
    { type: 'termsAndPrivacy', status: 'granted' },
    { type: 'marketingNotifications', status: 'granted' },
    { type: 'smsNotifications', status: 'denied' },
    { type: 'emailNotifications', status: 'granted' }
  ],
  '192.168.1.1',
  'Mozilla/5.0...'
);

console.log(`Consent set created: ${consentSetId}`);
```

### Python

```python theme={null}
import requests
from datetime import datetime

def create_onboarding_consent(onboarding_id, consents, user_ip, user_agent):
    """Create consent using onboardingId from registration flow"""
    response = requests.post(
        'https://api.baanx.com/v2/consent/onboarding',
        headers={
            'Content-Type': 'application/json',
            'x-client-key': os.getenv('BAANX_CLIENT_KEY'),
            'x-secret-key': os.getenv('BAANX_SECRET_KEY')
        },
        json={
            'onboardingId': onboarding_id,  # From registration, don't generate new
            'tenantId': 'tenant_baanx_prod',
            'policyType': 'US',
            'consents': [
                {'consentType': c['type'], 'consentStatus': c['status']}
                for c in consents
            ],
            'metadata': {
                'ipAddress': user_ip,
                'userAgent': user_agent,
                'timestamp': datetime.utcnow().isoformat() + 'Z',
                'clientId': 'web-app-v1.2.0'
            }
        }
    )

    response.raise_for_status()
    data = response.json()

    return data['consentSetId']

# Get onboardingId from registration flow (Step 2)
onboarding_id = verify_email_code(email, verification_code)['onboardingId']

# Create consent during registration (Step 4 - before address submission)
consent_set_id = create_onboarding_consent(
    onboarding_id,  # From registration
    [
        {'type': 'eSignAct', 'status': 'granted'},
        {'type': 'termsAndPrivacy', 'status': 'granted'},
        {'type': 'marketingNotifications', 'status': 'granted'},
        {'type': 'smsNotifications', 'status': 'denied'},
        {'type': 'emailNotifications', 'status': 'granted'}
    ],
    '192.168.1.1',
    'Mozilla/5.0...'
)

print(f"Consent set created: {consent_set_id}")
```

### cURL

```bash theme={null}
curl -X POST https://api.baanx.com/v2/consent/onboarding \
  -H "Content-Type: application/json" \
  -H "x-client-key: your_client_key" \
  -H "x-secret-key: your_secret_key" \
  -d '{
    "onboardingId": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
    "tenantId": "tenant_baanx_prod",
    "policyType": "US",
    "consents": [
      {
        "consentType": "eSignAct",
        "consentStatus": "granted"
      },
      {
        "consentType": "termsAndPrivacy",
        "consentStatus": "granted"
      },
      {
        "consentType": "marketingNotifications",
        "consentStatus": "granted"
      },
      {
        "consentType": "smsNotifications",
        "consentStatus": "denied"
      },
      {
        "consentType": "emailNotifications",
        "consentStatus": "granted"
      }
    ],
    "metadata": {
      "ipAddress": "192.168.1.1",
      "userAgent": "Mozilla/5.0...",
      "timestamp": "2024-01-15T10:30:00Z",
      "clientId": "web-app-v1.2.0"
    }
  }'
```

## Next Steps

After creating the consent set:

1. **Store the `consentSetId`**: You'll need it to link the user later
2. **Complete user registration**: Finalize account creation in your system
3. **Link user to consent**: Call [Link User to Consent Set](/api-reference/consent/link-user-to-consent)

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Link User to Consent" icon="link" href="/api-reference/consent/link-user-to-consent">
    Associate userId with consent set after registration
  </Card>

  <Card title="Get User Consent Status" icon="circle-check" href="/api-reference/consent/get-user-consent">
    Check user's consent status
  </Card>

  <Card title="Get Consent Audit Trail" icon="clock-rotate-left" href="/api-reference/consent/get-consent-audit">
    Retrieve complete consent change history
  </Card>

  <Card title="Implementation Guide" icon="book" href="/guides/consent/implementation">
    Full integration guide with examples
  </Card>
</CardGroup>
