# Report account security events

Send account security observations to Stripe to help assess account takeover risk.

> #### Private preview
> 
> Account security events are available in private preview. You must have preview access to use them.

Use the [Create an Account Activity API](https://docs.stripe.com/api/v2/signals/account-activities/create.md?api-version=2026-10-28.preview) to report security events that have occurred on your customers’ accounts with your business. Changes to authentication methods and credentials, along with reports of account takeover, give Stripe context to help assess account takeover risk.

These events are observations you report. Creating an `AccountActivity` records an event without returning a risk assessment or taking action on the account. You decide how to respond to these events in your application.

## Before you begin

Before you report security events:

- Use an existing [Customer](https://docs.stripe.com/api/customers/create.md) ID in `account_details.customer`, or a v2 account ID with a customer configuration in `account_details.account`. Use the same ID across activities. The object must belong to the same sandbox or live environment as your request.
- You must provide one of these IDs. Entityless reporting with `account_details.data` is unsupported for security events.
- Send requests from your server using API version `2026-10-28.preview`. Store your API key in an environment variable or secrets manager. When using a restricted key, grant the `account_evaluations_write` permission. See [best practices for managing secret keys](https://docs.stripe.com/keys-best-practices.md).

## Security event types

Set `type` to the event you observed. Except for mitigation, include the matching type-specific object and its required parameter:

| Type | When to report it | Required type-specific parameter |
| --- | --- | --- |
| `mfa_addition` | A multi-factor authentication (MFA) method was added to the account. | `mfa_addition.mfa_type` |
| `mfa_removal` | An MFA method was removed from the account. | `mfa_removal.mfa_type` |
| `credential_change` | An account credential changed, such as a login password or API key. | `credential_change.credential_type` |
| `account_takeover_report` | The account holder reported an account takeover to your business. | `account_takeover_report.credential_type` |
| `account_takeover_confirmation` | Your business confirmed that an account takeover occurred. | `account_takeover_confirmation.credential_type` |
| `account_takeover_mitigation` | An account takeover attempt was mitigated or ended. | None. Don’t send an `account_takeover_mitigation` object. |

Use these supported values for the type-specific parameters:

- `mfa_type`: `sms`, `email`, `authenticator_app`, `hardware_key`, or `other`.
- `credential_type`: `login_password`, `api_key`, or `other`.

Send only the credential type, never the password, API key, or authentication code itself.

## Report a security event

Send a request to `POST /v2/signals/account_activities` for each event. Every security event requires `type`, an existing customer or eligible account ID in `account_details`, and the type-specific parameters listed in the table.

For example, report the removal of an SMS authentication method:

```curl
curl -X POST https://api.stripe.com/v2/signals/account_activities \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "account_details": {
        "customer": "cus_****"
    },
    "type": "mfa_removal",
    "mfa_removal": {
        "mfa_type": "sms"
    },
    "occurred_at": "2026-10-28T12:00:00Z"
  }'
```

To report an addition instead, set `type` to `mfa_addition` and provide `mfa_addition.mfa_type`.

To report a credential change, identify the type of credential that changed:

```curl
curl -X POST https://api.stripe.com/v2/signals/account_activities \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "account_details": {
        "customer": "cus_****"
    },
    "type": "credential_change",
    "credential_change": {
        "credential_type": "api_key"
    }
  }'
```

Report an account holder’s takeover report separately from your own confirmation:

```curl
curl -X POST https://api.stripe.com/v2/signals/account_activities \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "account_details": {
        "customer": "cus_****"
    },
    "type": "account_takeover_report",
    "account_takeover_report": {
        "credential_type": "login_password"
    }
  }'
```

If your business confirms the takeover, send another activity with `type` set to `account_takeover_confirmation` and provide `account_takeover_confirmation.credential_type`.

After a takeover attempt is mitigated or ends, send a mitigation event with no type-specific object:

```curl
curl -X POST https://api.stripe.com/v2/signals/account_activities \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "account_details": {
        "customer": "cus_****"
    },
    "type": "account_takeover_mitigation"
  }'
```

Stripe returns an `AccountActivity` containing the reported event. In a sandbox, confirm that its `type`, account or customer ID, and type-specific details match your request. A successful response confirms that Stripe recorded your observation.

## Event timestamps

Use the optional `occurred_at` parameter to report when the event happened, especially when reporting it later. Provide an ISO 8601 timestamp, such as `2026-10-28T12:00:00Z`. If you omit it, Stripe uses the activity’s creation time.

## Report MFA challenge outcomes

When reporting a `login_decision`, you can include the optional `login_decision.mfa_challenges` list. Each entry requires an `mfa_type` and a `status` of `succeeded`, `failed`, or `other`. Include multiple entries when the login involved multiple challenges.

The required `login_decision.status` describes your overall decision: `allowed`, `blocked`, or `restricted`. Each challenge’s `status` describes that individual authentication outcome. For example, report a failed SMS challenge followed by a successful authenticator app challenge and an allowed login:

```curl
curl -X POST https://api.stripe.com/v2/signals/account_activities \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "account_details": {
        "customer": "cus_****"
    },
    "type": "login_decision",
    "login_decision": {
        "status": "allowed",
        "mfa_challenges": [
            {
                "mfa_type": "sms",
                "status": "failed"
            },
            {
                "mfa_type": "authenticator_app",
                "status": "succeeded"
            }
        ]
    }
  }'
```

Confirm that the returned activity includes both challenge outcomes.

### Interested in trying this?

Request access to the private preview to report account security events.

```bash
curl https://docs.stripe.com/preview/register \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Referer: https://docs.stripe.com/radar/account-security-events" \
  -d '{"email": "EMAIL", "preview": "radar_account_security_preview"}'
```
