---
title: "Consumer rate-alert subscription (double opt-in email)"
method: POST
path: "/v1/alerts"
tags: ["Data & Analytics"]
---

# Consumer rate-alert subscription (double opt-in email)

`POST /v1/alerts`

## Request

- Base URL: `https://api.rateapi.dev`
- URL: `https://api.rateapi.dev/v1/alerts`
- Auth: API key in header `X-API-Key`

Consent-first, EMAIL-delivered rate alerts: a borrower (or an AI agent on their behalf) is notified when the live market meets their target (rate/apr/monthly_payment crossing a threshold). Action-discriminated: `subscribe` creates a pending alert and sends a double-opt-in confirmation email (the alert only activates after the recipient confirms); `confirm` activates it; `list` returns a borrower's alerts; `unsubscribe` is a one-click token unsubscribe. Stores only email + alert criteria; never sold; one-click unsubscribe in every email (CAN-SPAM). This route is the single source of truth; the MCP `subscribe_rate_alert`/`list_rate_alerts`/`unsubscribe_rate_alert` tools call it.

**Authentication required**: Pass your API key in the `X-API-Key` header.

## Request body

- union
  - object
    - `action` 'subscribe', required: Which operation to perform.
    - `email` string, email, required: Email address the alert belongs to.
    - `state` string, required: Two-letter US state code.
    - `product_type` 'mortgage' | 'auto_loan' | 'heloc' | 'personal_loan' | 'student_loan', required: Loan or deposit product this applies to.
    - `intent` 'purchase' | 'refinance' | 'cash_out' | 'balance_transfer' | 'new_credit', required: What the borrower is trying to do — for example purchase or refinance.
    - `amount` number: Loan amount in US dollars.
    - `term_months` integer: Loan term in months.
    - `credit_score` integer: Borrower FICO score used to scope which offers apply.
    - `target` object, required: The threshold that should fire the alert.
      - `field` 'rate' | 'apr' | 'monthly_payment', required: Which figure the threshold is measured against.
      - `operator` 'lte' | 'gte', required: How the threshold is compared: `lte` fires at or below the value, `gte` at or above it.
      - `value` number, required: The threshold itself, in the units of `field` — a percentage for rate and APR, US dollars for monthly payment.
  - object
    - `action` 'confirm', required: Which operation to perform.
    - `confirm_token` string, required: The token from the confirmation email, which activates a pending alert.
  - object
    - `action` 'list', required: Which operation to perform.
    - `email` string, email: Email address the alert belongs to.
    - `unsubscribe_token` string: The token from an alert email, which identifies the subscriber without needing their address.
  - object
    - `action` 'unsubscribe', required: Which operation to perform.
    - `unsubscribe_token` string, required: The token from an alert email, which identifies the subscriber without needing their address.

## Response `200`

Action result. `subscribe` returns pending_confirmation; `confirm` returns active; `list` returns alerts; `unsubscribe` returns unsubscribed.

- RateAlertActionResult: Result of a `/v1/alerts` action. The discriminant is `status`: `pending_confirmation` (subscribe — a double-opt-in email has been sent and the alert is INERT until confirmed), `active` (confirm), `unsubscribed` (unsubscribe), or an `alerts` array (list).
  - `status` 'pending_confirmation' | 'active' | 'unsubscribed' | 'ok', required: Outcome of the requested action.
  - `alert_id` string: Identifier of the alert the action applied to. Absent on `list`.
  - `email` string, email: Recipient the alert is bound to.
  - `target` object: Threshold the alert fires on.
    - `field` 'rate' | 'apr' | 'monthly_payment': Which figure the alert threshold is measured against.
    - `operator` 'lte' | 'gte': How the threshold is compared: `lte` fires at or below the value, `gte` at or above it.
    - `value` number: The threshold itself, in the units of `field` — a percentage for rate and APR, US dollars for monthly payment.
  - `message` string: Human-readable next step, e.g. "Check your inbox to confirm".
  - `assumed_defaults` object: Values filled in where the caller supplied none, so a payment threshold is reproducible.
    - `amount` number, nullable: Loan amount assumed when evaluating a monthly-payment threshold, or null when the caller supplied none.
    - `term_months` integer, nullable: Loan term in months assumed when evaluating a monthly-payment threshold, or null when the caller supplied none.
  - `alerts` object[]: Present on `list` only: the alerts registered to this email.
    - `alert_id` string: Identifier of the alert.
    - `status` 'pending_confirmation' | 'active' | 'unsubscribed' | 'bounced': Lifecycle state of the alert.
    - `product_type` string: Product type the alert watches.
    - `state` string, nullable: Legacy single-state scalar, kept byte-compatible for existing consumers. Read `states` for the full coverage.
    - `states` string[]: Every two-letter US state code the alert covers, expanded at write time so a later change to a region preset never re-scopes an existing alert.
    - `region_preset` string, nullable: Named region the alert was created from, or null when states were given explicitly.
    - `intent` string, nullable: What the subscriber intends to do — for example purchase or refinance.
    - `target` object: The threshold that fires the alert.
      - `field` 'rate' | 'apr' | 'monthly_payment': Which figure the threshold is measured against.
      - `operator` 'lte' | 'gte': How the threshold is compared: `lte` fires at or below the value, `gte` at or above it.
      - `value` number: The threshold itself, in the units of `field`.
    - `created_at` string: When the alert was created.
    - `last_notified_at` string, nullable: When the alert last sent a notification, or null if it never has.
  - `next_actions` string[]: Follow-up calls that make sense from here.
  - `disclosures` string[]: Consent and CAN-SPAM statements that apply to this alert.

## Other responses

- `400`: The request was malformed — a missing required field, an unparseable body, or a parameter outside its allowed range. The `error` field names what was wrong; retrying the identical request will fail identically.
- `401`: No API key, or a key that is unknown or disabled. Send it in the `X-API-Key` header. Free keys are issued instantly by POST /keys with an email address. The response carries `WWW-Authenticate` pointing at this host's protected-resource metadata, and the `RateLimit-*` headers describing the Free-tier budget a key issued now would carry (scope `anonymous`) — a rejected request spends none of it, so `Remaining` equals `Limit`.
- `404`: No resource matches the identifier supplied. For rate queries an empty result set is a 200 with an empty array, so a 404 here means the resource itself does not exist.
- `429`: Quota exhausted for the current window. `Retry-After` gives the seconds to wait; `upgradeInfo` explains how to lift the cap. Retrying before the reset will fail again and still counts as a request.

---

[API](https://skmtc.dev/rateapi/apis/rate-api.md) · [All operations](https://skmtc.dev/rateapi/apis/rate-api/llms.txt) · [OpenAPI document](https://skmtc.dev/rateapi/apis/rate-api/revisions/06a6db76995f?raw)
