Skip to main content

Metrics Webhook

Push your Marqo index metrics to any HTTPS endpoint on a configurable schedule. Each delivery is an OTLP JSON payload signed with HMAC-SHA256, so you can verify authenticity and feed the data directly into any OpenTelemetry-compatible observability system.

Base URL

https://ecom.marqo-ep.ai/api/v1/webhooks/metrics

Authentication

Include your API key in the Authorization header of every request using the Bearer scheme:

Authorization: Bearer {api_key}

Create a Webhook

Register a new HTTPS endpoint to receive metrics pushes.

POST /api/v1/webhooks/metrics

Request Body

ParameterTypeRequiredDefaultDescription
webhookUrlstringYesHTTPS endpoint to receive deliveries
metricSetsstring[]YesOne or more of: request_latency, index_stats, jobs
cadencestringNo1hHow often the webhook fires: 5m, 15m, 30m, 1h
periodstringNo1hData point granularity: 5m, 15m, 30m, 1h
timeRangestringNo12hHow far back each delivery covers: 1h, 6h, 12h, 1d, 3d, 7d
indexAllowliststring[] or nullNonullIndex names to include. null means all indexes

Example Request

curl -X POST "https://ecom.marqo-ep.ai/api/v1/webhooks/metrics" \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{
"webhookUrl": "https://your-endpoint.example.com/marqo-metrics",
"metricSets": ["request_latency", "index_stats", "jobs"],
"cadence": "1h",
"period": "1h",
"timeRange": "12h"
}'

Example Response (201)

{
"webhookId": "b69c30b4-198a-4dae-ab7a-6e75304e57b8",
"webhookUrl": "https://your-endpoint.example.com/marqo-metrics",
"metricSets": ["request_latency", "index_stats", "jobs"],
"cadence": "1h",
"period": "1h",
"timeRange": "12h",
"indexAllowlist": null,
"signingSecret": "whsec_Xge2WnZ_ebTmHfAbZ9S5vNRGsOH...",
"enabled": true,
"createdAt": "2026-04-22T04:29:51.435748+00:00"
}
Save Your Signing Secret

The signingSecret is only returned at creation time. Store it securely — you will need it to verify webhook signatures. It cannot be retrieved later.

List Webhooks

Retrieve all webhook configurations for your account.

GET /api/v1/webhooks/metrics

Example Response (200)

{
"webhooks": [
{
"webhookId": "b69c30b4-198a-4dae-ab7a-6e75304e57b8",
"webhookUrl": "https://your-endpoint.example.com/marqo-metrics",
"metricSets": ["request_latency", "index_stats", "jobs"],
"cadence": "1h",
"period": "1h",
"timeRange": "12h",
"indexAllowlist": null,
"enabled": true,
"createdAt": "2026-04-22T04:29:51.435748+00:00"
}
]
}
note

The signingSecret is not included in list responses.

Delete a Webhook

Remove a webhook configuration. Deliveries stop immediately.

DELETE /api/v1/webhooks/metrics/{webhookId}

Response: 204 No Content


Configuration

Metric Sets

Choose which categories of metrics to receive. You can select one or more per webhook:

Metric SetDescription
request_latencyAPI request duration (p50/p90/p99) and request counts by endpoint and HTTP status
index_statsCurrent document count and vector count per index
jobsIndexing job counts, document processing counts, average job duration and delay

Cadence

How often the webhook fires. Each cadence interval triggers a delivery to your endpoint.

ValueDescription
5mEvery 5 minutes
15mEvery 15 minutes
30mEvery 30 minutes
1hEvery hour (default)

Period

The granularity of each data point in the payload. A shorter period produces more data points per delivery.

ValueDescription
5mOne data point every 5 minutes
15mOne data point every 15 minutes
30mOne data point every 30 minutes
1hOne data point every hour (default)

Time Range

How far back each delivery covers. The number of data points per delivery is timeRange ÷ period.

ValueDescription
1hLast 1 hour
6hLast 6 hours
12hLast 12 hours (default)
1dLast 1 day
3dLast 3 days
7dLast 7 days

To keep payload sizes reasonable, the maximum timeRange depends on the period:

PeriodMax Time RangeMax Data Points
5m1d288
15m3d288
30m7d336
1h7d168

Index Allowlist

By default (null), metrics for all indexes in your account are delivered. Each index produces a separate delivery. To limit to specific indexes:

{
"indexAllowlist": ["my-products", "my-articles"]
}

Configuration Examples

High-Frequency Monitoring

Monitor a single production index every 5 minutes with fine-grained data points:

curl -X POST "https://ecom.marqo-ep.ai/api/v1/webhooks/metrics" \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{
"webhookUrl": "https://your-endpoint.example.com/marqo-metrics",
"metricSets": ["request_latency", "index_stats"],
"cadence": "5m",
"period": "5m",
"timeRange": "1h",
"indexAllowlist": ["production-index"]
}'

This delivers 12 data points (1h ÷ 5m) every 5 minutes for one index.

Hourly Summary

Get a broad view of all indexes with hourly granularity:

curl -X POST "https://ecom.marqo-ep.ai/api/v1/webhooks/metrics" \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{
"webhookUrl": "https://your-endpoint.example.com/marqo-metrics",
"metricSets": ["request_latency", "index_stats", "jobs"],
"cadence": "1h",
"period": "1h",
"timeRange": "1d"
}'

This delivers 24 data points (1d ÷ 1h) every hour for all indexes.


Payload Format

Each delivery is an OTLP JSON payload. One delivery is sent per index, per webhook, per cadence interval.

Structure

{
"resourceMetrics": [
{
"resource": {
"attributes": [
{ "key": "service.name", "value": { "stringValue": "marqo" } },
{ "key": "marqo.index.name", "value": { "stringValue": "my-index" } }
]
},
"scopeMetrics": [
{
"scope": {
"name": "marqo.metrics.webhook",
"version": "1.0.0"
},
"metrics": [...]
}
]
}
]
}

Delivery Headers

HeaderValue
Content-Typeapplication/json
Content-Encodinggzip
X-Webhook-Signaturet=1713758400,v1=a1b2c3d4...

The body is gzip-compressed. Decompress it before parsing.


Metrics Reference

request_latency

marqo.request.duration — Summary (ms)

Request latency percentiles grouped by API operation. Each data point includes p50, p90, and p99 values.

{
"name": "marqo.request.duration",
"unit": "ms",
"summary": {
"dataPoints": [
{
"startTimeUnixNano": "1713754800000000000",
"timeUnixNano": "1713758400000000000",
"quantileValues": [
{ "quantile": 0.5, "value": 47.80 },
{ "quantile": 0.9, "value": 125.30 },
{ "quantile": 0.99, "value": 450.00 }
],
"attributes": [
{ "key": "operation", "value": { "stringValue": "POST /api/v1/indexes/:index/search" } }
]
}
]
}
}

marqo.request.count — Sum (monotonic)

Total request count grouped by endpoint and status_class (2XX, 4XX, 5XX).

index_stats

marqo.index.doc_count — Gauge

Current number of documents in the index. Single data point per delivery.

marqo.index.vector_count — Gauge

Current number of vectors in the index. Single data point per delivery.

jobs

marqo.jobs.total — Sum (monotonic)

Indexing job count grouped by status (COMPLETED, FAILED).

marqo.jobs.documents_total — Sum (monotonic)

Processed document count grouped by result (processed, failed, skipped, conflict).

marqo.jobs.avg_duration — Gauge (seconds)

Average job processing time per period window.

marqo.jobs.avg_delay — Gauge (seconds)

Average time between job creation and processing start per period window.

Summary Table

MetricMetric SetTypeUnitAttributes
marqo.request.durationrequest_latencysummarymsoperation
marqo.request.countrequest_latencysum1endpoint, status_class
marqo.index.doc_countindex_statsgauge1
marqo.index.vector_countindex_statsgauge1
marqo.jobs.totaljobssum1status
marqo.jobs.documents_totaljobssum1result
marqo.jobs.avg_durationjobsgauges
marqo.jobs.avg_delayjobsgauges

Signature Verification

Every delivery includes an X-Webhook-Signature header for authenticity verification. The signature is computed as HMAC-SHA256(signing_secret, "{timestamp}.{uncompressed_body}").

Python

import gzip
import hashlib
import hmac
import json


def verify_webhook(
raw_body: bytes, signature_header: str, signing_secret: str
) -> dict:
"""Verify and parse a Marqo metrics webhook delivery."""
# Decompress
body = gzip.decompress(raw_body)

# Parse header: "t=TIMESTAMP,v1=SIGNATURE"
parts = dict(p.split("=", 1) for p in signature_header.split(","))
timestamp = parts["t"]
signature = parts["v1"]

# Compute expected signature
message = f"{timestamp}.".encode("utf-8") + body
expected = hmac.new(
signing_secret.encode("utf-8"), message, hashlib.sha256
).hexdigest()

if not hmac.compare_digest(signature, expected):
raise ValueError("Invalid webhook signature")

return json.loads(body)

Node.js

const crypto = require("crypto");
const zlib = require("zlib");

function verifyWebhook(rawBody, signatureHeader, signingSecret) {
const body = zlib.gunzipSync(rawBody);

const parts = Object.fromEntries(
signatureHeader.split(",").map((p) => p.split("=", 2))
);

const expected = crypto
.createHmac("sha256", signingSecret)
.update(`${parts.t}.`)
.update(body)
.digest("hex");

if (parts.v1 !== expected) {
throw new Error("Invalid webhook signature");
}

return JSON.parse(body);
}

Endpoint Requirements

Your webhook endpoint must:

  • Accept HTTPS POST requests
  • Return a 2xx status code within 10 seconds
  • Handle gzip-compressed request bodies

If your endpoint is unreachable or returns a non-2xx status, the delivery is retried automatically. After repeated failures, the delivery is dropped.


FAQ

How many webhooks can I create?

You can create multiple webhooks with different configurations — different metric sets, cadences, or index filters.

Can I use different cadences for different metric sets?

Yes. Create separate webhooks, each with its own cadence and metric set selection.

What happens if my endpoint is down?

Deliveries are retried automatically. If your endpoint remains unreachable after all retries, the delivery is dropped.

What happens when I create a new index?

Metrics appear in webhook deliveries after the index has been active long enough for data to be collected (typically a few minutes).

Are deliveries per-index or aggregated?

Per-index. If you have 3 indexes and no indexAllowlist, you receive 3 separate deliveries per cadence interval.

Can I recover my signing secret?

No. The signing secret is shown only at creation time. If you lose it, delete the webhook and create a new one.

What do startTimeUnixNano and timeUnixNano mean?

These define the time window for each data point. The difference between them equals your configured period. For example, with period: "1h", each data point covers a 1-hour window.