# List sign-in audit events

GET

/v1/audit/sign-ins

```sh
curl --request GET \
  --url 'https://example.com/v1/audit/sign-ins?limit=25&kind=signed-in&order=asc' \
  --header 'Authorization: Bearer <token>'
```

The tenant’s sign-in history: who signed in and out, how (`method`), when and from where (`clientAddress`), what was refused and why, and emailed links sent or capped. `?userId=` narrows to one person’s own sign-ins and sign-outs. Oldest first; `?order=desc` for newest first. A tenant admin’s to read (403 `permission-denied` otherwise). Only mounted when `CreateAppInput.auditEvents` is wired.

## Authorizations

- **[bearerAuth](https://docs.kindgi.com/v0.1.9/reference/api.md#bearerauth)**

## Parameters

### Query Parameters

**limit**

integer

default: 25 >= 1 <= 100

1..100. Default 25.

**cursor**

string

Where the previous page ended: its `nextCursor`, as it came. A runtime that seals cursors takes one only for the same list, filters and caller, within a day; otherwise `400 bad-input`, and the list starts again without it. Absent → first page.

**userId**

string

One person’s own sign-ins and sign-outs.

**kind**

string

Allowed values: signed-in signed-out sign-in-refused sign-in-link-sent sign-in-link-capped sessions-revoked sessions-ended

One kind of event.

**from**

string format: date-time

Inclusive lower bound on `timestamp`.

**to**

string format: date-time

Inclusive upper bound on `timestamp`.

**order**

string

Allowed values: asc desc

`asc` (the default): oldest first. `desc`: newest first. `nextCursor` continues in the same order.

## Responses

### 200

A page of sign-in audit events.

application/json

object

**data**

required

Array\<object>

One sign-in audit event, flattened: who signed in or out, how, from where, and what was refused.

object

**id**

required

string

**timestamp**

required

string format: date-time

**kind**

required

`signed-in` / `signed-out`; `sign-in-refused` (with `reason`); `sign-in-link-sent` / `sign-in-link-capped` (an emailed link, for `userId`; `reason` is the limit that held); `sessions-revoked` (“sign out everywhere”, or removing a person; `byUserId` is the admin who did it, if not the person); `sessions-ended` (a changed boot token, or a session made without a second factor in a workspace that requires one: `reason` says which); `second-factor-set-up`, `second-factor-removed` (`byUserId` is the admin who removed it, if not the person) and `recovery-codes-replaced`. Never a key or a code.

string

Allowed values: signed-in signed-out sign-in-refused sign-in-link-sent sign-in-link-capped sessions-revoked sessions-ended second-factor-set-up second-factor-removed recovery-codes-replaced

**outcome**

required

`succeeded` or `denied`.

string

**userId**

The person the event is about: who signed in or out, whose sessions ended, or whom a link was for. Absent on a refusal that names no one.

string

**method**

How: `api-token`, `email-link`, `google`, `microsoft`, `github`, or a workspace identity provider’s id.

string

**clientAddress**

The client’s address, as the runtime trusts it.

string

**reason**

Why a sign-in was refused, or which limit held.

string

**sessionId**

string

**byUserId**

Who acted, when it isn’t `userId`: the admin who ended this person’s sessions.

string

**hasMore**

required

boolean

**nextCursor**

string

##### Example

```json
{
  "data": [
    {
      "kind": "signed-in"
    }
  ]
}
```

### 400

Malformed cursor, `kind`, `from`, `to`, or `order`.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 401

Missing / malformed / expired / revoked bearer token.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 403

Not a tenant admin (`permission-denied`).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

## See also

- [Operate a self-hosted runtime](https://docs.kindgi.com/v0.1.9/deploy/self-hosted/operate.md)
- [Error code `permission-denied`](https://docs.kindgi.com/v0.1.9/reference/errors.md#permission-denied)
- [Every error code](https://docs.kindgi.com/v0.1.9/reference/errors.md)
