---
title: "Send Opportunity Alert"
method: POST
path: "/v1.0/agent/send-notification"
tags: ["Opportunity"]
---

# Send Opportunity Alert

`POST /v1.0/agent/send-notification`

Sends an in-app notification to the agent(s) assigned to the given lead, representing a buyer/seller activity signal (e.g. viewed a listing, saved a search, requested CMA). Certain notificationType values also trigger SMS and Email delivery.

**Use case:** a partner system observes a user action on its own site and wants that action to surface as an opportunity in the assigned agent's Lofty inbox.

## Delivery channels

| Channel | Trigger |
|---|---|
| In-app push | All notificationType values |
| SMS + Email | Browse (11/48/138), Saved listing (9/52/136), Saved search (27/140), Mortgage calculator (89), Return-to-site (166) |

If the lead belongs to a lead pond, the notification is broadcast to all pond members instead of the single assignee.

## Important notes

- The leadId **must** belong to the caller's own team.
- Agents whose team has the OPPORTUNITY resource disabled are silently skipped.
- This endpoint is **not idempotent**. Repeated calls produce repeated deliveries.
- The `data` field in the response is a best-effort success hint, not a strict delivery confirmation. See the 200 response description for details.

## Headers

- `Authorization` string, required
- `Content-Type` string, required

## Request body

- OpportunityNotificationRequest
  - `leadId` integer, required — Lead ID. Must belong to the caller's team.
  - `description` string — Free-text description shown in the notification body. description and link form a combo; both must be non-empty for the details block to render.
  - `link` string — Companion URL to description (see description field). Typically a listing / search / CMA URL.
  - `message` string — Optional free-text message. Rendered only for notificationType values that carry a leave-message context (e.g. 65); ignored by all other types.
  - `notificationType` 9 | 10 | 11 | 27 | 46 | 47 | 48 | 50 | 52 | 65 | 66 | 89 | 136 | 137 | 138 | 139 | 140 | 141 | 162 | 164 | 165 | 166 | 167 | 168, required — Opportunity trigger type. Must match one of the supported activity codes. Site-origin values: 9 = Saved a listing 10 = Searched 11 = Viewed a listing 27 = Saved a search 46 = Requested to sell a house 47 = Requested home evaluation 65 = Left a message 66 = Requested a showing 89 = Used mortgage calculator 162 = Requested CMA 164 = Requested financing options NewHome-origin equivalents: 48 = Browsed a home 50 = Searched a home 52 = Favorited a home CApp-origin equivalents: 136 = Favorited 137 = Searched 138 = Browsed 139 = Showing request 140 = Saved search 141 = House evaluation Other: 165 = Re-inquired on text code 166 = Back to site (view a listing) 167 = Submitted a form 168 = Viewed CMA

## Response `200`

Request accepted. Response body = {status:{code:0,msg:"success"}, data:<bool>}. data=true  => notification(s) dispatched to at least one assignee (non-pond path). data=false => one of the silent-failure conditions: leadId=0, notificationType=null, lead not found, no agent-role assignee, or the lead is a lead-pond lead (where broadcast is still triggered but the API returns false due to a known quirk). Callers SHOULD NOT rely on data=true/false as a strict delivery confirmation.

- SendOpportunityNotificationResponse — Wrapped response for POST /v1.0/agent/send-notification.
  - `status` SendOpportunityNotificationResponseStatus — Status envelope; code=0 indicates the request was processed.
    - `code` integer — Response code; 0 indicates success.
    - `msg` string — Response message.
  - `data` boolean — Rough success flag. true = notification dispatched. false = silent-failure condition (missing lead, no assignee) or pond-broadcast quirk (see endpoint description). Callers should not treat this as a strict delivery confirmation.

## Other responses

- `400` — Invalid token / rate-limited / package quota exceeded (handled by the common filter chain before reaching this endpoint; see RateLimitFilter / PackageLimitFilter).
- `500` — Internal error (error code 20005).

---

[API](https://skmtc.net/lofty/apis/lofty-service-open-apis.md) · [All operations](https://skmtc.net/lofty/apis/lofty-service-open-apis/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/lofty/lofty-service-open-apis/versions/23e640467118/schema)
