Customer API
Base URL https://api.plunk.io/cx/v1. Versioned,
key-scoped, and self-describing: start every integration at
GET /capabilities.
Authentication
Every request carries an API key, issued from your workspace. Send it as a bearer
token, or in the X-Api-Key header; both are
equivalent.
curl https://api.plunk.io/cx/v1/capabilities \
-H "Authorization: Bearer sk_live_XXXXXXXXXXXX"
# or
curl https://api.plunk.io/cx/v1/capabilities \
-H "X-Api-Key: sk_live_XXXXXXXXXXXX"
| Key class | Prefix | Where it lives | Rules the API enforces |
|---|---|---|---|
| Publishable pk | pk_live_ / pk_test_ |
Browser JS and mobile bundles: shippable, public | Origin-locked: requests are accepted only from the web origins registered on the key. Reads are aggregate and non-PII; revenue fields and person-level data never appear. The one write is event ingest. |
| Secret sk | sk_live_ / sk_test_ |
Your server only | Full scope your workspace exposes, including revenue-bearing analytics and identity-scoped resources. A secret key presented from a browser origin is rejected outright. |
Each key also carries scopes (e.g.
products:read). A key with no explicit scope grant
holds every scope its class allows; a key with a grant is limited to exactly those.
The scope each endpoint requires is listed with the endpoint below, and the pk/sk
pill on each section shows the minimum key class.
Errors & limits
| Status | Meaning | Body |
|---|---|---|
401 |
Missing or invalid key; a publishable key from an unregistered origin; a secret key from a browser. | Message text with WWW-Authenticate: ApiKey |
403 |
The key is valid but the scope isn't permitted; the resource family isn't enabled for your workspace, isn't available to the key's class, or wasn't granted to the key. | { "error": "scope_not_permitted", "scope": "…" } |
404 |
The resource doesn't exist; each endpoint returns a named error, e.g.
product_not_found,
dealer_not_found,
contact_not_found. |
{ "error": "…", … } |
400 |
Invalid request: a required field or parameter is missing or unsupported. The body names the field and what's accepted. | { "error": "…", "note": "…" } |
429 |
Rate limit exceeded for the key. Back off and retry. | Message text |
Every response is scoped to your workspace by the key; there is no cross-workspace surface. Requests are metered per key.
Date ranges
Endpoints with a {range} segment share one
vocabulary: a named token, or a custom window as
custom_YYYYMMDD_YYYYMMDD
(e.g. custom_20260101_20260630).
An unrecognized token falls back to this_year.
today · yesterday · last_7_days · last_30_days · last_90_days this_month · last_month · ytd · this_year · last_year · all_time custom_YYYYMMDD_YYYYMMDD
Exception: /markets reads
pre-aggregated snapshots and accepts its own named set (listed there) without
custom_ windows.
Capabilities pksk
The discovery document and your integration contract. It lists exactly the resource families the presented key can reach: publishable keys never see secret-only families, and families light up as the matching data exists in your workspace. Fetch it once at startup and code against it, not a static list.
GET/cx/v1/capabilities
{
"tenant": "yourworkspace",
"tenantType": "retailer", // manufacturer | retailer | vertical
"mode": "live", // live | test, from the key
"aggregationFloor": 5,
"labels": {
"location": "Showroom" // white-label terms, when configured
},
"families": [
{
"name": "products",
"key": "publishable",
"scopes": ["products:read", "recommendations:read"],
"label": null,
"endpoints": [
"GET /cx/v1/products/top/{range}",
"GET /cx/v1/products/{id}",
"GET /cx/v1/products/search",
"GET /cx/v1/products/trending",
"GET /cx/v1/recommendations",
"GET /cx/v1/recommendations/model"
]
},
{
"name": "store-performance",
"key": "secret",
"scopes": ["store-performance:read"],
"label": "Showroom",
"endpoints": [
"GET /cx/v1/stores/{range}",
"GET /cx/v1/stores/{range}/{storeId}"
]
}
]
}
Ingest pk
The write path: behavioral events from your storefront or app into your workspace.
Scope ingest:write. A 202
with an event id means the event is recorded on the tracking rail; if it cannot be
recorded you get a 503 with
ingest_unavailable. Retry with backoff on 503.
POST/cx/v1/ingest/event
| Field | Type | Notes |
|---|---|---|
type | string | Required. e.g. page_view, product_view, add_to_cart, conversion, or a custom name |
visitorRef | string | Your anonymous visitor reference |
url | string | Page URL |
productId | string | Product the event concerns |
value | number | Monetary value (e.g. conversion amount) |
properties | object | Free-form additional attributes |
curl -X POST https://api.plunk.io/cx/v1/ingest/event \
-H "Authorization: Bearer pk_live_XXXX" -H "Content-Type: application/json" \
-d '{
"type": "product_view",
"visitorRef": "v_84af",
"productId": "L-2750-52"
}'
# 202 Accepted
{
"accepted": true,
"eventId": "9d1c…",
"type": "product_view"
}
POST/cx/v1/ingest/identify
Associates an anonymous visitor with a known identity.
visitorRef is required, plus at least one of
email, hashedEmail,
userId; optional traits
object.
{
"accepted": true,
"eventId": "41be…",
"visitorRef": "v_84af"
}
POST/cx/v1/ingest/sale sk
Record a settled order as real sales data: revenue dashboards, product and
store performance, customer purchase history, and lifecycle stages all read
from it. This is the endpoint a payment integration calls from its webhook
handler; wire it to Stripe's checkout.session.completed
or invoice.paid and your sales arrive as they happen.
Posting the same orderId again replaces that
order's lines, so webhook retries and corrections are safe. The buyer behind
customerRef is created on first sight and linked
to the sale; a first sale advances them to the Customer lifecycle stage
automatically.
| Field | Type | Notes |
|---|---|---|
orderId | string | Required. Stable per order (e.g. the Stripe session or invoice id). Reposting it replaces the order's lines. |
customerRef | string | Required. Your stable id for the buyer (e.g. the Stripe customer id). |
lines[].productId | string | Required. Joins your catalog when the id matches; unknown ids still count as revenue. |
lines[].price | number | Required. The extended line total (already multiplied by quantity). |
lines[].quantity | integer | Optional; defaults to 1 |
lines[].description | string | Optional line description |
email | string | Optional but recommended; fills the buyer's contact record |
customerName | string | Optional; defaults to email or customerRef |
orderDate | datetime | Optional; defaults to now |
storeId · channel · currency | string | Optional; channel defaults to api |
status | string | Optional; defaults to Shipped (settled). Pass an open-order status only for unsettled orders; they report as backlog, not revenue. |
curl -X POST "https://api.plunk.io/cx/v1/ingest/sale" \
-H "Authorization: Bearer sk_live_..." -H "Content-Type: application/json" \
-d '{
"orderId": "cs_a1B2c3",
"customerRef": "cus_R8xT2m",
"email": "buyer@example.com",
"channel": "stripe",
"currency": "USD",
"lines": [
{"productId": "230-00", "description": "Skyline Sofa", "quantity": 2, "price": 2398.00}
]
}'
# 200 OK
{
"accepted": true,
"orderId": "cs_a1B2c3",
"linesWritten": 1,
"customerId": "43f7…",
"customerCreated": true
}
POST/cx/v1/ingest/inventory sk
Push stock levels from your own system. Secret key only, scope
inventory:write: this updates business data and
flips product availability. The same numbers can arrive by CSV feed or the
Shopify connector instead; all three write identically, so use whichever your
stack produces most easily.
| Field | Type | Notes |
|---|---|---|
items[].sku | string | Required. Must match a product id in your catalog; unknown SKUs are skipped and counted in the response. Connect the product feed first. |
items[].source | string | Required. Warehouse or location name. A source containing "transit" counts as sellable inbound stock. |
items[].qtyOnHand | number | Units on hand at that source |
items[].qtyBackordered | number | Optional |
items[].availableDate | date | Optional; when inbound units become sellable |
items[].asOf | datetime | Optional; defaults to now |
curl -X POST "https://api.plunk.io/cx/v1/ingest/inventory" \
-H "Authorization: Bearer sk_live_..." -H "Content-Type: application/json" \
-d '{"items":[
{"sku":"230-00","source":"Main Warehouse","qtyOnHand":6,"qtyBackordered":4},
{"sku":"230-00","source":"In Transit","qtyOnHand":30,"availableDate":"2026-10-12"}
]}'
{
"accepted": true,
"itemsWritten": 2,
"skusAggregated": 1,
"availabilityUpdated": 1,
"unknownSkusSkipped": 0,
"sources": ["Main Warehouse", "In Transit"]
}
Each request replaces the sources it carries and leaves other sources alone, so a snapshot per warehouse is safe to send independently. Up to 5,000 items per request; page larger snapshots. Availability on your products becomes a consequence of these numbers: on hand means in stock, inbound-only means backorder, neither means out of stock.
Products pk
Product intelligence from your sales rail. Scope
products:read.
GET/cx/v1/products/top/{range}
| Param | Default | Notes |
|---|---|---|
groupBy | product | product | category |
category | Filter to one category | |
limit | 20 | 1–100 |
Ranked by revenue. Publishable keys receive
rank, units and
orders, with an aggregation floor (rows under 5
orders are suppressed). Secret keys additionally receive
revenue and aov,
with no floor.
curl "https://api.plunk.io/cx/v1/products/top/this_month?limit=3" \
-H "Authorization: Bearer sk_live_XXXX"
{
"range": "this_month",
"groupBy": "product",
"keyClass": "secret",
"count": 3,
"items": [
{
"rank": 1,
"id": "L-2750-52",
"title": "Track-Arm Sofa",
"category": "Sofas",
"units": 41,
"orders": 38,
"revenue": 61250.00,
"aov": 1611.84
}
]
}
GET/cx/v1/products/{id}
The public product card, safe for a storefront. Never includes cost.
{
"id": "L-2750-52",
"title": "Track-Arm Sofa",
"category": "Sofas",
"price": 1899.00,
"salePrice": null,
"image": "https://…",
"link": "https://…",
"availability": "in stock",
"brand": "…"
}
GET/cx/v1/products/search
Semantic search. Matches on meaning rather than keywords, so "something for a small entryway" finds narrow console tables even when none of those words appear in a title. Results are then re-ranked by a blend of relevance, units sold and conversion rate, applied only among products that already matched.
| Param | Default | Notes |
|---|---|---|
q | Required. What to search for, in plain language. | |
filter | Optional keyword filter applied on top of the semantic match. | |
rank | blended | similarity returns pure semantic order, with no commercial weighting. Useful for comparing the two. |
limit | 20 | 1–100 |
curl "https://api.plunk.io/cx/v1/products/search?q=dresser&limit=3" \ -H "Authorization: Bearer pk_live_..."
{
"query": "dresser",
"ranking": "blended",
"count": 3,
"items": [
{
"rank": 1,
"id": "…",
"title": "Carino Dresser - Frost",
"category": "Bedroom",
"link": "https://…",
"imageLink": "https://…",
"price": 1299.00,
"availability": "in stock",
"unitsSold": 24
}
]
}
GET/cx/v1/products/trending
What is getting attention, which is a different question from
/products/top/{range}. That one ranks by
revenue actually booked; this one ranks the tracker's rollups by views,
engagements, conversions or units.
| Param | Default | Notes |
|---|---|---|
range | this_month | Any range token. The default is deliberate: scoped to all_time, "trending" would mean "best ever" rather than "moving now". |
sort | sales_quantity | views, engagements or conversions. |
filter | Optional keyword filter. | |
limit | 20 | 1–100 |
{
"range": "this_month",
"sort": "views",
"count": 20,
"items": [
{ "rank": 1, "id": "…", "title": "Pacifico Dining Chair", "category": "Seating",
"link": "https://…", "imageLink": "https://…", "price": 449.00,
"availability": "in stock" }
]
}
Recommendations pk
"Customers also bought," computed from real purchase history. Two endpoints:
one counts co-occurrence live, the other reads a model rebuilt nightly. Scope
recommendations:read covers both. Returns rank
and co-purchase evidence, never revenue.
GET/cx/v1/recommendations
| Param | Default | Notes |
|---|---|---|
product | With it: products most often in the same order as this one. Without: top sellers (popular fallback). | |
limit | 10 | 1–50 |
{
"basis": "co_purchase",
"product": "L-2750-52",
"count": 10,
"items": [
{
"rank": 1,
"id": "L-2750-OTT",
"title": "Matching Ottoman",
"category": "Ottomans",
"coPurchasedOrders": 19
}
]
}
GET/cx/v1/recommendations/model
The same question answered from a model rebuilt nightly instead of counted live. Prefer this one. The endpoint above counts products in the same order; this counts distinct accounts that bought both over 24 months, weights each pair by how much evidence supports it, and keeps freight, fabric surcharges and card fees out of the results. Both are kept so existing integrations do not change under you.
| Param | Default | Notes |
|---|---|---|
product | What is bought alongside this product. | |
account | What this account should buy next, excluding what it already owns. | |
contact | A person id. Resolves to the account or accounts that contact belongs to and recommends across all of them. Pass exactly one of product, account or contact. | |
limit | 10 | 1–50 |
curl "https://api.plunk.io/cx/v1/recommendations/model?product=5422-22LF&limit=3" \ -H "Authorization: Bearer pk_live_..."
{
"basis": "co_purchase_model",
"product": "5422-22LF",
"account": null,
"count": 3,
"items": [
{
"rank": 1,
"id": "5422-22RF",
"title": "One Arm Curved Loveseat",
"category": "Seating",
"score": 0.594166, // 0-1, higher is stronger
"accounts": 22 // accounts that bought both
}
]
}
An empty items array is a real answer, not an
error. It means the product is new, has too little purchase history to be
confident, or the model has not been built for that catalog yet.
Sectional and modular goods often pair a product with its own mirror half (a left-facing piece with its right-facing twin), so two results can share a title while differing by SKU. That is the strongest signal in the data rather than a duplicate. Render the SKU, not the title alone.
On ?product, score
compares pairs across the whole catalog. On ?account
it is scaled to the strongest hit in that response, so it ranks items within one
answer and is not comparable between accounts.
Reviews pk
Aggregated review ratings from your connected social profiles: trust badges for
your storefront. Scope reviews:read; available once
a social account is connected to the workspace.
GET/cx/v1/reviews
| Param | Default | Notes |
|---|---|---|
locationRef | Filter to one location's reviews | |
limit | 10 | Recent reviews returned, 1–50 |
{
"locationRef": null,
"averageRating": 4.6,
"reviewCount": 212,
"recent": [
{
"author": "…",
"rating": 5,
"text": "…",
"date": "2026-08-14T00:00:00",
"sentiment": "positive"
}
]
}
Locations pk
Your physical stores and outlets: the feed behind a store locator. Scope
locations:read; available for workspaces with a
retail channel.
GET/cx/v1/locations
{
"locations": [
{
"id": "S01",
"name": "Main Street Showroom",
"type": "store",
"city": "Charlotte",
"region": "NC",
"postalCode": "28202",
"lat": 35.2271,
"lng": -80.8431
},
{
"id": "O02",
"name": "Clearance Outlet",
"type": "outlet"
}
]
}
Markets pk
Where your demand comes from: sessions, views and conversions by city, with
coordinates for maps. Scope markets:read.
GET/cx/v1/markets
| Param | Default | Notes |
|---|---|---|
range | this_year | Named snapshots only: today, day, this_week, last_week, this_month, last_month, this_quarter, last_quarter, this_year, last_7_days |
limit | 25 | 1–200 |
Secret keys additionally receive
conversionValue per market.
{
"range": "this_month",
"keyClass": "publishable",
"count": 25,
"items": [
{
"rank": 1,
"city": "Charlotte",
"region": "NC",
"sessions": 4210,
"uniqueUsers": 3384,
"views": 11840,
"conversions": 96,
"lat": 35.22,
"lng": -80.84
}
]
}
Catalog sk
The full product catalog, cursor-paged, with incremental sync, built for a trade
site or portal that mirrors your line. Scope
catalog:read.
GET/cx/v1/catalog
| Param | Default | Notes |
|---|---|---|
after | Cursor from the previous page's nextCursor | |
category | Filter to one category | |
updatedSince | ISO date-time; only products modified since (incremental sync) | |
limit | 50 | 1–200 |
{
"count": 50,
"nextCursor": "L-2750-52",
"items": [
{
"id": "…",
"title": "…",
"category": "…",
"price": 1899.00,
"salePrice": null,
"image": "https://…",
"link": "https://…",
"availability": "in stock",
"brand": "…",
"modifiedDate": "2026-08-20T03:10:00"
}
]
}
# Page forward with ?after=nextCursor until nextCursor is null.
Visitor sk
Personalization for a resolved contact: which audiences they belong to, for
content targeting and gating on your site. Scope
visitor:read. {reference}
is the numeric contact id in your workspace.
GET/cx/v1/visitor/{reference}/profile
{
"reference": "18442",
"firstName": "…",
"lastName": "…",
"lifecycleStage": null,
"segmentCount": 3,
"segments": [
{
"id": "…",
"name": "High-intent sofas",
"type": "behavioral"
}
]
}
GET/cx/v1/visitor/{reference}/segments
Just the audience memberships:
{
"reference": "18442",
"count": 3,
"segments": [
{
"id": "…",
"name": "High-intent sofas",
"type": "behavioral"
}
]
}
Dealers sk
Wholesale account analytics for manufacturers: every dealer, ranked and
trended. Scopes dealers:read and
dealer-performance:read; available for workspaces
with wholesale sales.
GET/cx/v1/dealers
The directory with lifetime totals. ?limit= 1–200,
default 50.
{
"count": 50,
"items": [
{
"id": "D-1042",
"revenue": 412870.00,
"orders": 214,
"units": 1130,
"firstOrder": "2023-02-11T00:00:00",
"lastOrder": "2026-08-19T00:00:00"
}
]
}
GET/cx/v1/dealers/performance/{range}
Ranked by revenue in the window, with percent change vs the prior equal-length
period. Scope dealer-performance:read.
{
"range": "this_quarter",
"count": 50,
"items": [
{
"id": "D-1042",
"revenue": 88450.00,
"orders": 41,
"aov": 2157.32,
"deltaPct": 12.4
}
]
}
GET/cx/v1/dealers/{id}
One dealer's totals plus its top products.
{
"dealer": {
"id": "D-1042",
"revenue": 412870.00,
"orders": 214,
"units": 1130,
"aov": 1929.30,
"firstOrder": "…",
"lastOrder": "…"
},
"topProducts": [
{
"id": "…",
"title": "…",
"revenue": 61200.00,
"units": 84
}
]
}
Stores sk
Retail store performance: the retailer twin of dealer analytics. Scope
store-performance:read; available for workspaces
with a retail channel.
GET/cx/v1/stores/{range}
The roster with chain totals, percent change vs the prior equal-length period, and each store's share of chain revenue.
{
"range": "this_month",
"chainRevenue": 2410083.00,
"chainOrders": 1181,
"count": 5,
"stores": [
{
"id": "S01",
"name": "Main Street",
"type": "store",
"revenue": 612044.00,
"orders": 292,
"units": 631,
"aov": 2096.04,
"deltaPct": 7.9,
"sharePct": 25.4
}
]
}
GET/cx/v1/stores/{range}/{storeId}
One store's KPIs and top categories.
{
"range": "this_month",
"id": "S01",
"name": "Main Street",
"type": "store",
"kpi": {
"revenue": 612044.00,
"orders": 292,
"units": 631,
"aov": 2096.04
},
"topCategories": [
{
"category": "Sofas",
"revenue": 228412.00,
"units": 121
}
]
}
Audiences sk
Audience performance: membership, engagement, and conversion value per audience.
Scope audience-performance:read. Named ranges read
the latest snapshot; custom_ windows aggregate the
daily series (flows sum, membership takes the window max).
GET/cx/v1/audiences/{range}
{
"range": "this_month",
"count": 12,
"audiences": [
{
"name": "High-intent sofas",
"audienceId": "…",
"members": 1840,
"conversions": 44,
"conversionValue": 96410.00,
"engagements": 3120,
"engagementValue": 8140.00,
"views": 20110,
"sessions": 6120,
"uniqueUsers": 1710,
"avgTimespan": 84.2
}
]
}
GET/cx/v1/audiences/{range}/{audienceId}/trend
Daily membership counts across the window.
{
"range": "last_90_days",
"audienceId": "…",
"name": "High-intent sofas",
"points": [
{
"date": "2026-06-01",
"members": 1502
}
]
}
Customer sales sk
Identified-customer purchase analytics: summary KPIs, repeat rate, and top
customers by revenue. Scope customer-sales:read.
GET/cx/v1/customers/sales/{range}
?top= customers returned, 1–100, default 25.
{
"range": "ytd",
"summary": {
"revenue": 1804210.00,
"orders": 902,
"units": 1911,
"customers": 781,
"aov": 2000.23,
"repeatCustomers": 84,
"repeatRatePct": 10.8
},
"topCustomers": [
{
"customerId": "C-2201",
"revenue": 41210.00,
"orders": 6,
"units": 14,
"aov": 6868.33,
"lastOrder": "2026-08-12"
}
]
}
Contact interest sk
The behavioral profile behind one contact: what they viewed, did, and bought.
Scope contact-interest:read. PII in, PII out:
server-to-server only.
GET/cx/v1/contacts/interest
| Param | Default | Notes |
|---|---|---|
email | Required. The contact's email | |
range | all_time | Any shared range token |
{
"range": "all_time",
"email": "…",
"lastSeen": "2026-08-21T14:02:11Z",
"impressions": 214,
"engagements": 38,
"conversions": 2,
"conversionValue": 4210.00,
"topPages": [
{
"url": "/sofas/track-arm",
"views": 31
}
],
"topActions": [
{
"type": "form",
"action": "quote_request",
"count": 2
}
]
}
GET/cx/v1/contacts/interest/top/{range}
The most-engaged contacts in the window. ?top=
1–100, default 25.
{
"range": "last_30_days",
"count": 25,
"contacts": [
{
"email": "…",
"engagements": 41,
"lastSeen": "2026-08-22T09:12:44Z",
"conversions": 1,
"conversionValue": 2210.00
}
]
}
Forecasting sk
The demand-forecast rail: projected demand per product, and similarity forecasts
for designs that don't exist yet, built from your own comparable products. Scope
forecast:read.
GET/cx/v1/forecast/top/{range}
Products ranked by projected views in the window.
?top= 1–100, default 25.
{
"range": "this_month",
"count": 25,
"products": [
{
"productId": "L-2750-52",
"title": "Track-Arm Sofa",
"imageLink": "https://…",
"projectedViews": 4210,
"projectedUniqueUsers": 3180,
"contacts": 112,
"locations": 3,
"places": 14
}
]
}
GET/cx/v1/products/{id}/forecast/{range}
One product's forecast: the prediction series plus projected units by store.
{
"range": "this_quarter",
"productId": "L-2750-52",
"title": "Track-Arm Sofa",
"series": [
{
"date": "2026-09-01",
"grain": "day",
"views": 140,
"uniqueUsers": 104
}
],
"projectedSalesByStore": [
{
"storeId": "S01",
"projectedUnits": 9
}
]
}
GET/cx/v1/forecast/similarity
All similarity forecasts, newest first. Returns
404 similarity_forecast_not_available until the
similarity engine has produced output for your workspace.
{
"count": 4,
"forecasts": [
{
"id": "…",
"name": "Curved-back lounge concept",
"category": "Chairs",
"status": "complete",
"imageLink": "https://…",
"projectedViews": 1840,
"projectedUniqueUsers": 1420,
"contacts": 40,
"locations": 2,
"places": 8,
"modified": "2026-08-14",
"similarProducts": 6
}
]
}
GET/cx/v1/forecast/similarity/{id}
One similarity forecast in full: the prediction series, the comparable products it was built from (with similarity scores), and projected units by store.
{
"forecast": {
"id": "…",
"name": "…",
"category": "…",
"description": "…",
"status": "complete",
"imageLink": "…",
"projectedViews": 1840
},
"series": [
{
"date": "2026-09-01",
"grain": "day",
"views": 61,
"uniqueUsers": 48
}
],
"similarProducts": [
{
"productId": "…",
"title": "…",
"link": "…",
"imageLink": "…",
"similarityScore": 0.9142
}
],
"projectedSalesByStore": [
{
"storeId": "S01",
"projectedUnits": 4
}
]
}
Enrichment sk
Contact append from the workspace's enrichment cache: name, address and
demographics for an email you already hold. Scope
enrich:read. PII-bearing: server-to-server only.
POST/cx/v1/enrich/contact
Body: { "email": "…" } (required).
{
"matched": true,
"source": "cache",
"contact": {
"firstName": "…",
"lastName": "…",
"email": "…",
"phone": "…",
"address": "…",
"address2": null,
"city": "…",
"region": "…",
"postalCode": "…",
"country": "US",
"age": 44
}
}
# No cached match:
{
"matched": false,
"email": "…",
"source": "cache",
"note": "…"
}