1 operation. Every schema and example on this page is generated from the platform contract.
One feed of every marketing message that actually left the store, from every source: Moments the system sent by itself, retention journeys, and campaigns somebody wrote. Each row carries the person, the reason, the channel, what was said and what happened. Nothing appears here that was queued, suppressed, capped or held back, so the list is exactly what customers received. Figures are counted from the store own rows: a store that has sent nothing gets zeroes.
Store whose marketing to list (also authorises the merchant).
Page size (default 50, max 200).
Keyset cursor: the previous page's `next_before`. Returns older sends.
The previous page's `next_before_id`. Breaks the tie between two sends sharing a timestamp. Omitting it is safe but can repeat one row at a page boundary.
Everything this one person has had from the store.
One rule's own history ('near_reward', 'lapsed_30', 'campaign').
ISO timestamp for the summary window. Defaults to 30 days back.
Is this store sending on its own, or still working a queue by hand? Read from the switch itself, never inferred from the rows.
Start of the window these figures cover.
Messages that actually left, in the window.
How many of those the system sent by itself.
Distinct PEOPLE, not messages.
Distinct people who did something afterwards.
Real money taken, in pence.
How many bounced. Zero is a good number and worth printing.
Who it went to. Null only for a send with no single recipient.
Resolved at read time through the reportable-customers guard. Null when the person has since been deleted: the send stays in the merchant history, the name does not come back.
momentjourneycampaignStable machine name of the rule: a moment slug, a journey_type, or 'campaign'.
What to print. Frozen at send time.
appemailpushTrue when the system decided and sent it; false when a person at the store did.
Plain text of what was actually sent, capped at 500 characters and frozen. Null on rows backfilled from before the ledger existed, where the stored body may have been edited since.
It left and came back. Email only.
What they did afterwards, inside the attribution window: stamp, order, checkin, redeem, returned.
Real money, only where a real transaction was matched.
Cursor for the next page: pass back as `before`, together with `next_before_id`.
The other half of the cursor. `sent_at` carries no uniqueness constraint and automatic sends are written concurrently in batches, so a timestamp alone would skip the second of two rows sharing an instant whenever a page boundary fell between them. Pass both.
curl -G "https://www.membber.com/api/v1/marketing/ledger" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
--data-urlencode "store_id=6659c139-0000-4000-8000-d0c500000066"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/marketing/ledger", {
params: { query: { store_id: "6659c139-0000-4000-8000-d0c500000066" } },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.listMarketingSends(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"automatic_marketing_enabled": true,
"summary": {
"since": "<since>",
"sent": 1,
"automatic": 1,
"peopleReached": 1,
"peopleReturned": 1,
"valuePence": 1,
"bounced": 1
},
"sends": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"customerId": "a1c10999-0000-4000-8000-d0c5000000a1",
"customerName": "Alex Example",
"source": "moment",
"ruleKey": "<ruleKey>",
"ruleName": "<ruleName>",
"channel": "app",
"automatic": true,
"subject": "<subject>",
"bodyPreview": "<bodyPreview>",
"sentAt": "<sentAt>",
"openedAt": "<openedAt>",
"clickedAt": "<clickedAt>",
"bouncedAt": "<bouncedAt>",
"resultKind": "<resultKind>",
"resultAt": "<resultAt>",
"resultValuePence": 1
}
],
"has_more": true,
"next_before": "<next_before>",
"next_before_id": "76ca3f8f-0000-4000-8000-d0c500000076"
}