For the complete documentation index, see llms.txt. This page is also available as Markdown.

Webhooks

Receive signed market, asset and portfolio insight notifications and retrieve the published content.

Subscribe to assessment.published to receive notifications about eligible new market, asset and portfolio assessments. Motif posts to your backend; your backend verifies the notification and reads the published content through the API. Start with Integrate insights into your app for the complete integration.

Motif must enable event-driven assessment publication in your environment. A subscription does not enable it automatically. Notifications are sent after eligible event-driven research is published; they are not receipts for every data upload, calculation, scheduled refresh or card recomposition. Owner-scoped private assessments are not sent to organization webhooks.

Register your endpoint

Use Settings → Webhooks, or choose your backend integration below. The SDK examples require the SDK version described in release coverage and configured motif client from Integrate insights into your app. REST paths are relative to your API base URL.

POST /v1/sdk/webhooks
Content-Type: application/json
x-api-key: <motif-api-key>

{
  "name": "Partner insights",
  "url": "https://partner.example.com/webhooks/motif",
  "events": ["assessment.published"]
}

Inspect schemas in Swagger UI for sandbox or production, or import the OpenAPI JSON for sandbox or production. Swagger requests target the environment you opened.

const subscription = await motif.webhooks.create({
  name: 'Partner insights',
  url: 'https://partner.example.com/webhooks/motif',
  events: ['assessment.published'],
})

Save subscription.id and subscription.secret securely before testing.

Replace the example URL with your public HTTPS receiver on port 443. Private network addresses and redirects are not supported. Save the returned endpoint id and signing secret (whsec_…). The secret is shown only at creation or rotation.

Method
Path
Purpose

GET

/v1/sdk/webhooks

List subscriptions in your organization

POST

/v1/sdk/webhooks

Create a subscription

PATCH

/v1/sdk/webhooks/{id}

Change URL, events or enabled status

DELETE

/v1/sdk/webhooks/{id}

Delete the subscription and its delivery history

POST

/v1/sdk/webhooks/{id}/rotate-secret

Issue a new secret; the old one stops working immediately

POST

/v1/sdk/webhooks/{id}/test

Send a signed webhook.test request

GET

/v1/sdk/webhooks/{id}/deliveries

Inspect attempts; supports limit (1–100) and cursor

Test the saved subscription and inspect delivery attempts:

Set MOTIF_WEBHOOK_ID to the returned endpoint ID and use the configured base URL and API key:

The test endpoint returns { success, statusCode, duration, error }. Require success: true and a 2xx receiver status; the API can return HTTP 200 with success: false. Confirm the receiver recorded the test as well.

A test checks connectivity and signing. It does not generate an insight and has no assessment event ID. After it succeeds, verify real publications for all three surfaces in the agreed pilot window.

Create the subscription once and persist its ID. After a lost create response, reconcile GET /v1/sdk/webhooks by endpoint URL/name before creating another. The secret cannot be recovered from that list; rotate it if the original response was lost.

Publication payload

Illustrative portfolio notification:

Treat id as opaque. Use it for deduplication; data.revision is an assessment revision and is independent of your portfolio snapshot revision.

data.surface

subjectId

portfolioId

Subscription scope

MARKET

GLOBAL for the shared market assessment

null

Enabled subscribing organizations

ASSET

Motif asset ID

null

Organizations with an active portfolio holding the asset, subject to the assessment's scope

PORTFOLIO

Motif portfolio ID

Same portfolio ID

The organization owning that active portfolio

An asset notification represents the asset-level read; it is not sent once per holding. Use your asset-to-portfolio mapping to identify affected books. Notifications contain metadata, not the full prose or evidence. They do not carry your external portfolio ID.

Verify each request

Motif sends JSON with these headers:

Header
Meaning

X-Webhook-Event

assessment.published, or webhook.test for a test

X-Webhook-Id

Registered endpoint ID

X-Webhook-Event-Id

Publication event ID; matches payload id, absent on tests

X-Webhook-Timestamp

Signing time as Unix seconds; distinct from the payload's publication time

X-Webhook-Signature

v1= followed by the HMAC-SHA256 signature

For a receiver that does not use the SDK, reproduce the current signing contract exactly:

The derived signing key is the UTF-8 hex string, not decoded hash bytes. Reject missing or malformed headers and timestamps outside the accepted tolerance; compare signatures in constant time. Do not sign re-serialized JSON or use the displayed secret directly as the final HMAC key. Test requests use the same signature format.

A Node.js implementation using the original body buffer:

This function verifies authenticity and timestamp freshness. Your receiver still validates the payload, expected organization/endpoint and event uniqueness before processing it.

Use a released SDK version containing verifyWebhookSignature. Pass the original UTF-8 request body before JSON parsing, the two signature headers and the displayed secret. The helper checks the signature and a five-minute timestamp tolerance by default:

Capture the raw bytes before JSON middleware runs. Header names are case-insensitive; reject repeated or missing signature/timestamp headers. Select the stored secret by the registered endpoint ID.

After signature verification, branch on the event type before validating an assessment. The test body has a different schema:

A test has no id, version or organizationId. Check data.webhookId against X-Webhook-Id and your endpoint configuration, record the test and return 2xx.

For an assessment, validate version 1, the expected organization, positive integer revision and the documented surface/subject relationship. Check endpoint/event headers and X-Webhook-Event-Id === body.id. Keep the receiver's clock synchronized.

Acknowledge and retrieve the insight

Durably save or queue the verified event before returning 2xx, within ten seconds. Use a unique (organizationId, eventId) record to deduplicate publications and process the insight asynchronously. If durable storage fails, return 5xx; if processing fails after acknowledgment, your own worker must retry it. If the event is already saved, acknowledge the duplicate successfully.

Use the event's language and your stored identity mapping to fetch the current content:

Surface
Read endpoint
Request context

MARKET

POST /v1/sdk/clarity/market-update

x-api-key; body { "language": "en" }

ASSET

GET /v1/sdk/clarity/assets/{assetId}

x-api-key; use subjectId as assetId, with language query

PORTFOLIO

GET /v1/sdk/clarity/portfolios/{portfolioId}

x-api-key; use portfolioId, with language and optional window query

Request and response schemas: Swagger UI for sandbox or production.

Surface
SDK call
Request context

MARKET

motif.clarity.marketUpdate({ language })

Organization API key from client setup

ASSET

motif.clarity.assetById(subjectId, {language})

Exact asset subject ID

PORTFOLIO

motif.clarity.portfolioById(portfolioId, {language, window: '1D'})

Exact native account ID; no user header

Use event.data.language and the stored mapping, not a guessed user or ticker. See the complete retrieval examples.

Use exact subject IDs for all asset categories, including custom assets. A foreign or archived subject returns 404; an authorized subject without an authored insight returns null or nullable content members. See the complete integration.

For a portfolio read, use the notification’s portfolioId directly with the exact-ID GET endpoint. Anonymous client accounts and several portfolios per client are supported. A chat partner-context ID is a different identifier.

These endpoints return the latest stored content, not a revision-specific copy of the notification. Another publication may have occurred before you read. Handle unavailable content (null or nullable fields) and stale status without labeling it a fresh insight. See Integrate Clarity and the API reference for the response shapes and source-document retrieval.

Retries, ordering and operations

Motif treats 2xx as success. Network failures, HTTP 408, 429 and 5xx are retried with exponential backoff, capped at one hour between attempts, up to eight attempts. Other unsuccessful HTTP statuses are terminal for that delivery. Redirects are not followed. Heavy processing should happen after acknowledgment so it does not cause timeouts and duplicate deliveries.

Delivery can be repeated and is not an ordered audit log. Newer assessment work can supersede a queued notification; Motif skips superseded deliveries. A disabled or deleted subscription, or loss of portfolio access, can also prevent a pending delivery. Use the latest-content read to reconcile after an outage rather than expecting every intermediate edition to arrive.

The delivery list shows HTTP status, success, duration, error and time. The admin delivery detail also exposes the sent payload; receiver response bodies are not retained. After a terminal failure, inspect the cause, correct the receiver and reconcile the current insights. Use the replay endpoint below for assessment attempts and reconcile current content with the exact subject ID.

The event picker also includes user, profile, strategy, report, KYC and order event names. Their presence does not establish automatic delivery for those workflows. The insight integration described here uses assessment.published for all three surfaces.

Replay an assessment notification

Use POST /v1/sdk/webhooks/{id}/deliveries/{deliveryId}/replay or motif.webhooks.replay(id, deliveryId), selecting the attempt ID from delivery history. The response is {eventId,status:"QUEUED"}. The original event ID is retained and current subscription, access and supersession checks still apply. Test events cannot be replayed. Reconcile current content when an older notification has been superseded.

Last updated