---
title: "Record Connect Attempt"
method: POST
path: "/v1/auth/oauth/connect-attempts"
tags: ["auth-oauth"]
---

# Record Connect Attempt

`POST /v1/auth/oauth/connect-attempts`

## Request

- Base URL: `https://api.usekeel.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.usekeel.io/v1/auth/oauth/connect-attempts`
- Auth: none declared

Record a connect attempt from the keel-app server render (Q-2381).

Unauthenticated, best-effort, always 200 once the body validates, with
``{"experiment_arm": ...}`` -- the arm stored on the row
(connect-onboarding §1.3). A database failure is logged and still
answers 200 with ``null``, so the page never depends on it. A malformed
body (bad id, enum or length, or any field the model does not declare)
is a 422 and writes nothing.

## Request body

- ConnectAttemptRecordRequest: Body of the unauthenticated ``POST /v1/auth/oauth/connect-attempts`` (Q-2381). Sent by the keel-app SERVER render of the connect flow, best-effort. It carries only facts the page already holds. ``device_class`` is the page's reduction of the request's user agent: the raw user agent and the IP are never sent and never stored, and ``extra="forbid"`` turns any attempt to send them into a 422 rather than a silently dropped field. Monotonic by construction: a later call with the same ``attempt_id`` can only STAMP ``consent_shown_at`` once and record a first ``cancelled`` decision. It can never set a principal or an ``approved`` decision; only the authenticated authorize-complete does that.
  - `attempt_id` string, required
  - `signed_in_at_start` boolean, required
  - `client_name` string, nullable
  - `client_id` string, nullable
  - `redirect_host` string, nullable
  - `device_class` 'desktop' | 'ios' | 'android' | 'unknown'
  - `referrer_host` string, nullable
  - `consent_shown` boolean
  - `decision` 'cancelled', nullable

## Response `200`

Successful Response

- ConnectAttemptRecordResponse: ``200`` body of ``POST /v1/auth/oauth/connect-attempts`` (connect-onboarding spec 01 §1.3). ``experiment_arm`` is the arm STORED on the attempt row -- written once, on the first INSERT, from ``WELCOME_BONUS_PCT`` -- so a replay reports the original assignment. ``null`` when the row predates the arm, or on any internal failure (the endpoint is best-effort and still answers 200). keel-app treats ``null``, a non-200 or a network error alike as "no bonus line".
  - `experiment_arm` 'control' | 'welcome_bonus', nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/usekeel/apis/keel-api.md) · [All operations](https://skmtc.dev/usekeel/apis/keel-api/llms.txt) · [OpenAPI document](https://skmtc.dev/usekeel/apis/keel-api/revisions/3191ca10b0ab?raw)
