---
title: "Create a new decision monitor"
method: POST
path: "/v1/monitors"
tags: ["Decision Monitors"]
---

# Create a new decision monitor

`POST /v1/monitors`

## Request

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

Creates a new monitor that watches for rate changes matching the specified criteria. When rates change and meet the monitor's conditions, a webhook is delivered to your configured endpoint.

**Two monitor types** (discriminated by `target_type`):
- **Decision monitor** (default, omit `target_type`): watches the aggregate market-best decision for a state + product.
- **Competitor monitor** (`target_type: "competitor"`): watches a single named credit union's published rate and alerts on changes — useful for tracking a specific competitor rather than the whole market.

**Key Features:**
- **Subscription-based**: Watch specific states and product types for rate changes
- **Condition filtering**: Only trigger when savings or confidence thresholds are met
- **Cooldown protection**: Prevent webhook spam with configurable cooldown periods
- **Webhook delivery**: Secure HTTPS webhooks with signature verification

**Important**: The webhook signing secret is only returned once at creation time. Store it securely.

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

## Headers

- `Idempotency-Key` string

## Request body

- union
  - CreateMonitorRequest: Request body for creating a new monitor
    - `name` string, required: Human-readable name for the monitor
    - `decision_context` DecisionContextInput, required: Full decision context provided at monitor creation. This is minimized to bands before storage for privacy.
      - `state` string, required: 2-letter US state code
      - `product_type` 'mortgage' | 'mortgage_arm' | 'auto_loan' | 'personal_loan' | 'heloc' | 'student_loan' | 'credit_card': Type of financing product (defaults to 'mortgage' if not provided) Use `mortgage_arm` for an adjustable-rate mortgage (5/1, 5/5, 7/1, 10/1, ...). ARMs are a separate market from fixed-rate mortgages: an ARM's introductory rate sits structurally below a comparable fixed rate, so a blended list would rank every ARM on top and present it as cheaper — true only until it resets. All initial fixed periods share one `mortgage_arm` bucket. Within `mortgage`, `term_months` selects 15- vs 30-year; it has no meaning for `mortgage_arm`.
      - `intent` 'purchase' | 'refinance' | 'cash_out' | 'balance_transfer' | 'new_credit': Purpose of the financing
      - `amount` number, required: Loan amount in dollars
      - `term_months` integer: Loan term in months
      - `credit_score` integer: FICO credit score (300-850)
      - `income_annual` number: Annual gross income in dollars
      - `rate_type` 'fixed' | 'adjustable' | 'variable': Interest rate structure preference
      - `no_points` boolean: Whether to prefer no-points loans
      - `prefer_credit_unions` boolean: Whether to prefer credit unions
    - `conditions` object[]: Conditions that must be met for a monitor to trigger
      - `field` string, required: Field to compare (e.g., 'apr', 'rate', 'monthly_savings')
      - `operator` 'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'ne', required: Comparison operator
      - `value` number, required: Value to compare against
    - `subscribed_states` string[]: States to watch for rate changes. Defaults to decision_context.state if not provided. Use ["*"] for all states.
    - `subscribed_product_types` string[]: Product types to watch. Defaults to decision_context.product_type if not provided. Use ["*"] for all types.
    - `cooldown_hours` integer: Hours to wait between triggers (default: 24)
    - `webhook_url` string, uri, required: Webhook URL for notifications. Must use HTTPS.
  - CreateCompetitorMonitorRequest: Request body for creating a named-competitor rate monitor. Watches a single credit union's published rate and alerts on changes. Discriminated by target_type='competitor'. One of credit_union_id or credit_union_name is required.
    - `target_type` 'competitor', required: Discriminator. Must be 'competitor' for this variant.
    - `name` string, required: Human-readable name for the monitor
    - `credit_union_id` string: Credit union id to watch. One of credit_union_id or credit_union_name is required.
    - `credit_union_name` string: Credit union name (case-insensitive substring match). One of credit_union_id or credit_union_name is required.
    - `product_type` 'mortgage' | 'auto_loan' | 'heloc' | 'personal_loan' | 'student_loan' | 'credit_card': Which published product of the credit union to watch. Default 'mortgage'.
    - `loan_program` string: Optional loan program label, e.g. '30-year-fixed'.
    - `state` string: Optional 2-letter US state code (validated).
    - `conditions` object: Alert conditions on the named credit union's rate.
      - `change_direction` 'up' | 'down' | 'any': Which direction of rate move should trigger the monitor.
      - `min_change_bps` number: Minimum basis-point move to alert.
    - `cooldown_hours` integer: Minimum hours between alerts.
    - `webhook_url` string, uri, required: HTTPS webhook endpoint. Required.

## Response `201`

Monitor created successfully

- union
  - CreateMonitorResponse: Response for monitor creation
    - `monitor` Monitor, required: Monitor configuration as returned in API responses
      - `id` string, required: Unique monitor ID
      - `name` string, required: Human-readable name
      - `status` 'active' | 'paused' | 'disabled', required: Current status of the monitor
      - `decision_context` MinimizedDecisionContext, required: Privacy-preserving context stored long-term (no PII). The original decision context is minimized to bands for privacy.
        - `credit_score_band` 'excellent' | 'good' | 'fair' | 'poor': Privacy-preserving credit score band
        - `income_band` 'high' | 'medium' | 'low': Income band (high/medium/low)
        - `loan_amount_band` 'under_100k' | '100k_250k' | '250k_500k' | '500k_750k' | '750k_1m' | 'over_1m', required: Privacy-preserving loan amount band
        - `state` string, required: 2-letter US state code
        - `product_type` 'mortgage' | 'mortgage_arm' | 'auto_loan' | 'personal_loan' | 'heloc' | 'student_loan' | 'credit_card', required: Type of financing product Use `mortgage_arm` for an adjustable-rate mortgage (5/1, 5/5, 7/1, 10/1, ...). ARMs are a separate market from fixed-rate mortgages: an ARM's introductory rate sits structurally below a comparable fixed rate, so a blended list would rank every ARM on top and present it as cheaper — true only until it resets. All initial fixed periods share one `mortgage_arm` bucket. Within `mortgage`, `term_months` selects 15- vs 30-year; it has no meaning for `mortgage_arm`.
        - `intent` 'purchase' | 'refinance' | 'cash_out' | 'balance_transfer' | 'new_credit': Purpose of the financing
        - `term_months` integer: Loan term in months
        - `rate_type` 'fixed' | 'adjustable' | 'variable': Interest rate structure preference
        - `no_points` boolean: Whether to prefer no-points loans
        - `prefer_credit_unions` boolean: Whether to prefer credit unions
      - `conditions` object[], required: Conditions that must be met for a monitor to trigger
        - `field` string, required: Field to compare (e.g., 'apr', 'rate', 'monthly_savings')
        - `operator` 'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'ne', required: Comparison operator
        - `value` number, required: Value to compare against
      - `subscribed_states` string[], required: States to watch for rate changes. Use ["*"] for all states.
      - `subscribed_product_types` string[], required: Product types to watch. Use ["*"] for all types.
      - `cooldown_hours` integer, required: Hours to wait between triggers
      - `webhook_url` string, uri, required: Webhook URL for notifications (HTTPS only)
      - `webhook_signing_secret_prefix` string, required: First 10 characters of the signing secret, for identifying WHICH secret a monitor is on without storing or re-showing the secret itself. The full secret is returned only once, at creation.
      - `last_evaluated_at` string, date-time, nullable: Last time this monitor was evaluated
      - `last_triggered_at` string, date-time, nullable: Last time this monitor triggered a webhook
      - `created_at` string, date-time, required: When the monitor was created
      - `updated_at` string, date-time, required: When the monitor was last updated
    - `webhook_signing_secret` string, required: The webhook signing secret. Only returned once at creation - store it securely!
  - CreateCompetitorMonitorResponse: Response from creating a competitor monitor. webhook_signing_secret is shown ONCE.
    - `monitor` object, required: The monitor that was created.
      - `id` string: Identifier of the monitor, used on the get, update, and delete routes.
      - `name` string: Caller-supplied name for the monitor.
      - `status` 'active': Lifecycle state of the monitor. A newly created monitor is always active.
      - `target_type` 'competitor': What the monitor watches. This route always creates a competitor monitor.
      - `competitor` object: The credit union being watched.
        - `credit_union_id` string: Canonical identifier of the watched credit union.
        - `credit_union_name` string: Name of the watched credit union.
        - `state` string, nullable: Two-letter US state code of the watched credit union, or null when unknown.
      - `product_type` string: Product type whose rate is being watched.
      - `loan_program` string, nullable: Loan program narrowing the watched product, or null when the monitor covers all programs.
      - `conditions` object: What has to happen before the monitor fires.
        - `change_direction` string: Which direction of rate move triggers the monitor: up, down, or any.
        - `min_change_bps` number: Smallest move, in basis points, that will trigger the monitor.
      - `cooldown_hours` integer: Hours the monitor stays quiet after firing before it can fire again.
      - `webhook_url` string: Where a triggered monitor delivers its payload.
      - `webhook_signing_secret_prefix` string: Leading characters of the webhook signing secret, so you can tell which secret to verify against. The full secret is returned only once, at creation.
      - `current_rate` object: Snapshot of the credit union's latest published rate at creation. Fields are null when the credit union has no live rate for the product_type.
        - `apr` number, nullable: APR observed for the watched product when the monitor was created, or null when none was served.
        - `rate` number, nullable: Note rate observed for the watched product when the monitor was created, or null when none was served.
        - `as_of` string, nullable: When that observed rate was published, or null when no rate was served.
      - `last_evaluated_at` string, nullable: When the monitor was last evaluated, or null if it has not run yet.
      - `last_triggered_at` string, nullable: When the monitor last fired, or null if it never has.
      - `created_at` string: When the monitor was created.
      - `updated_at` string: When the monitor was last modified.
    - `webhook_signing_secret` string, required: Full webhook signing secret. Shown ONCE — store it securely.

## Other responses

- `400`: Invalid request - validation errors
- `401`: Missing or invalid API key
- `422`: Idempotency-Key was reused with a different request body.
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[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)
