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

# Capture Clickwrap Event

> Record a clickwrap acceptance or interaction event for an end user

## Endpoint

```
POST /v2/server/clickwrap/{slug}/capture
```

## Authentication

This endpoint requires an OAuth access token. Send it as a bearer token:

```bash theme={null}
Authorization: Bearer your_access_token
```

**Required scope:** `clickwrap:write`

<Info>
  Clickwrap is the one `/v2` surface with no acting user. The subject of a clickwrap event is
  `user_identifier`, an opaque string you supply for your own end user, which is never resolved
  against Chamelio's users. These endpoints are authorized by organization and scope alone, so
  `client_credentials` tokens work here without restriction.
</Info>

## Path Parameters

| Parameter | Type   | Required | Description                         |
| --------- | ------ | -------- | ----------------------------------- |
| `slug`    | string | Yes      | Unique identifier for the clickwrap |

## Request Body

| Field             | Type           | Required | Description                                                                                                                |
| ----------------- | -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `user_identifier` | string         | Yes      | Stable identifier for the end user (e.g. email or internal user ID)                                                        |
| `event_type`      | string         | Yes      | Type of interaction: `accepted`, `viewed`, `checked`, `scrolled_to_bottom`                                                 |
| `metadata`        | object or null | No       | Arbitrary key-value pairs to attach to the event record                                                                    |
| `ip_address`      | string or null | No       | End user's IP address at the time of acceptance. Recommended for legal validity - the API caller's IP is never substituted |
| `user_agent`      | string or null | No       | End user's user agent string. Recommended for legal validity - the API caller's user agent is never substituted            |

## Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://platform.chamelio.ai/v2/server/clickwrap/privacy-policy/capture" \
    -H "Authorization: Bearer your_access_token" \
    -H "Content-Type: application/json" \
    -d '{
      "user_identifier": "user@example.com",
      "event_type": "accepted",
      "ip_address": "203.0.113.42",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...",
      "metadata": {"session_id": "sess_abc123", "product": "checkout"}
    }'
  ```

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

  slug = "privacy-policy"

  url = f"https://platform.chamelio.ai/v2/server/clickwrap/{slug}/capture"
  headers = {
      "Authorization": "Bearer your_access_token",
      "Content-Type": "application/json"
  }
  body = {
      "user_identifier": "user@example.com",
      "event_type": "accepted",
      "ip_address": "203.0.113.42",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...",
      "metadata": {"session_id": "sess_abc123", "product": "checkout"}
  }

  response = requests.post(url, headers=headers, json=body)
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const slug = "privacy-policy";

  const response = await fetch(
    `https://platform.chamelio.ai/v2/server/clickwrap/${slug}/capture`,
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer your_access_token',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        user_identifier: 'user@example.com',
        event_type: 'accepted',
        ip_address: '203.0.113.42',
        user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...',
        metadata: { session_id: 'sess_abc123', product: 'checkout' }
      })
    }
  );

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

## Response

### Success Response

**Status Code:** `200 OK`

```json theme={null}
{
  "acknowledged": true
}
```

### Response Fields

| Field          | Type    | Description                                            |
| -------------- | ------- | ------------------------------------------------------ |
| `acknowledged` | boolean | Always `true` when the event was recorded successfully |

## Error Responses

### 401 Unauthorized

Returned when the access token is missing, unknown, revoked, or expired, or when an `X-API-Key` was
sent instead of a bearer token. See [OAuth error responses](/api-reference/oauth-apps#error-responses).

```json theme={null}
{
  "detail": "Invalid access token"
}
```

### 403 Forbidden

Returned when the token does not carry the required scope.

```json theme={null}
{
  "detail": "Insufficient scope; this endpoint requires: clickwrap:write"
}
```

### 404 Not Found

Returned when no active clickwrap or active version exists for the given slug.

```json theme={null}
{
  "detail": "Not found"
}
```

### 422 Unprocessable Entity

Returned when an acceptance is recorded before its prerequisite events. An `accepted` event requires
a prior `viewed` event, and a `scroll_and_accept` clickwrap additionally requires a prior
`scrolled_to_bottom` event.

```json theme={null}
{
  "detail": "View event is required before acceptance"
}
```

```json theme={null}
{
  "detail": "Scroll to bottom event is required before acceptance"
}
```

### 429 Too Many Requests

Returned when your organization exceeds its per-minute request limit.

```json theme={null}
{
  "detail": "Rate limit exceeded"
}
```

### 500 Internal Server Error

Returned when the request fails due to a server error.

```json theme={null}
{
  "detail": "Failed to capture clickwrap event"
}
```

## Notes

<Warning>
  Capture always targets the **currently active version**. You cannot capture an event against an older or draft version via this endpoint.
</Warning>

<Info>
  Because this is a server-to-server endpoint, the API caller's IP address and user agent are never used as the end user's origin data. Always pass the actual end user's `ip_address` and `user_agent` in the request body for legally valid acceptance records.
</Info>

<Tip>
  Record the interaction events in order - `viewed`, then `scrolled_to_bottom` for a `scroll_and_accept` clickwrap, then `accepted`. Sending `accepted` first returns `422`.
</Tip>

## Use Cases

This endpoint is useful for:

* **Server-side consent capture** - Record acceptance from a backend flow where the clickwrap was rendered in your own UI
* **Audit trails** - Store `ip_address`, `user_agent`, and `metadata` (e.g. session ID, product context) for compliance records
* **Multi-step flows** - Record intermediate events (`viewed`, `scrolled_to_bottom`) before the final `accepted` event
