Placements
Control where and when offers appear across in-app, push, and email
Overview
Kard’s placements, content strategy, and marketing delivery functionality give you control over where and when offers appear, so the right users see the right loyalty opportunities at the right times. Every placement is configurable: you choose the medium it delivers on, the schedule it follows, and the offers it surfaces by linking a content strategy.
By pairing configurable placements with reusable content strategies, you can personalize the offer experience across in-app, push, and email from a single setup. This guide walks you through how placements work, the mediums they support, how content strategies select offers, and how to send offer notifications on a recurring cadence or on demand for one-time sends.
Setting up follows three steps:
- Create a content strategy: define which offers to show and how to rank them.
- Create a placement: choose where and how offers are delivered, and link the content strategy to it.
- Send notifications: reach users directly with a recurring push or a one-time on-demand push or email.
Content Strategies
A content strategy defines which offers to show and how to order them — independent of medium or timing, so one strategy can be reused everywhere. You create and manage strategies through the Content Strategies API.
Create a strategy
The response returns 201 with the new strategy, including the id you’ll reference when creating a placement:
Link that id to any placement through contentStrategyId. Updating the strategy changes every placement that uses it — no per-channel rework.
Placements
Placements are the building blocks for delivering offers, and a placement’s type decides how and where offers reach the user:
placement: renders offers inside your app, holding multiple offers viaavailableSlots.placementPushNotification: sends a single offer as a push notification on a recurring schedule.placementEmail: sends offers as an email on a recurring schedule, filling up toavailableSlotsoffers per send.placementOnDemand: sends a one-time push or email, outside of any schedule.
The first three are created once and link to a content strategy through a contentStrategyId — Kard selects and surfaces the offers, and any update to the strategy flows through automatically. On-demand sends are fired as you need them, reusing a placement’s strategy or a set of offers you specify. The sections below walk through each.
Create a placement
Create a placement through the Placements API, setting type to the kind you want to create. This example creates an in-app main-page placement with five slots, linked to the content strategy created above:
Mediums
Mediums are configured as part of your placements, and the same content strategy can power offers across all three:
- In-app: a
placementrenders offers when the user opens the screen. It’s evaluated at request time, so no schedule is needed — to display it, call Get Placement Content for the user, and Kard returns the offers the placement’s content strategy selects asstandardOfferresources (up toavailableSlots), ready to render. - Push: offers are sent to the user’s device as a notification (see Placement notifications).
- Email: offers are sent on a recurring
cadence(aplacementEmail) or as a one-time on-demand send.
Curating the in-app placement
Get Placement Content is how you curate the in-app placement experience. When a user opens the screen, call the endpoint with their userId and the placementId, and Kard resolves the linked content strategy in real time — handing back the offers already selected and ranked for that user. Render them exactly as they arrive; there’s no client-side filtering or sorting to do. Pass supportedComponents to shape which UI components come back.
A standard (in-app) placement returns offers — render these in the order returned, up to the placement’s availableSlots:
The data array holds the offers to display, included carries the referenced categories (when requested), and meta.placementName echoes the placement’s display name. Because selection and ranking happen server-side from the content strategy, updating that strategy re-curates the in-app placement automatically — no client changes needed.
This endpoint serves in-app placements only. Push and email placements return 400 and deliver their offers through the content-file webhook instead.
Placement Notifications
Placements can also reach users as notifications, over push or email. These come in two forms: recurring sends on a cadence, and one-time on-demand sends.
Cadence notifications
A placementPushNotification delivers a single offer to the user on the recurring schedule you define. Its availableSlots is fixed at 1, so the linked content strategy picks the most relevant offer for each run. You set the schedule with a cadence object:
Create type placementPushNotification through the Placements API. This example sends a daily offer at 09:00 UTC:
For a weekly send, set frequency to WEEKLY and add a dayOfWeek — for example, { "frequency": "WEEKLY", "timeOfDay": "14:00", "dayOfWeek": "FRI" }.
Email on a cadence
Email placements follow the same schedule model. Create a placementEmail with a cadence and an availableSlots count — unlike push (fixed at one offer), an email send can feature several offers, so the linked content strategy fills up to availableSlots:
Receiving the content file
Kard selects the offers for a scheduled send, but you deliver the message to your users. On each run, Kard resolves the linked content strategy, compiles the selected offers into a gzipped JSONL file, and notifies you through your notification webhook.
Kard does not push to devices or send email on your behalf. Every scheduled send hands you a content file to deliver through your own channels.
The handoff has three steps:
- Subscribe once. Register a webhook for the event with the Create Subscriptions endpoint. Use
pushNotificationPlacementFilefor push placements andemailNotificationPlacementFilefor email placements. - The cadence fires. At the scheduled time, Kard builds the file and
POSTs a notification to your subscribedwebhookUrl. - Download and send. The payload carries a presigned
downloadUrl;GETit before it expires to retrieve the gzipped JSONL, then deliver the offers to your users.
Subscribe to the push placement-file event:
When the cadence runs, Kard delivers a webhook payload like the one below (push shown; email uses emailNotificationPlacementFile):
Email placement files
An email placement (placementEmail) hands off its file the same way, on the event emailNotificationPlacementFile — subscribe to it just as you would the push event. Because an email send isn’t capped at a single offer, availableSlots tells you how many offers the file holds.
The downloadUrl resolves to the same gzipped JSONL format as the push file (one record per eligible user). Download it before it expires, decompress, and render the offers into your email template. The field reference below applies to both the push and email payloads.
Inside the content file
The downloadUrl points to a gzipped JSONL file: decompress it, then parse one line per eligible user — not one line per offer. Each line is a self-contained JSON:API data envelope whose id is the placement the content was generated for. Push and email use different record types.
The title and message are identical for every user in the file — Kard derives them from the linked content strategy’s sort and categories, so they aren’t set per send.
Push — each line is a pushNotificationPlacementContent record. The content strategy’s top offer is already resolved into the title, message, and a per-user attributionUrl, so you deliver the line as-is.
Two records follow, one per user — id, title, and message are placement-level (identical across users), while userId and attributionUrl are per-user. The bodies are expanded below for readability; in the file each record is written as a single line.
Email — each line is an emailNotificationPlacementContent record. Because an email send can feature several offers, the attributes carry an offers array (up to availableSlots) plus a single per-user attributionToken; append that token to each offer’s img URL when you render it.
Two records follow, one per user — id, title, and message are placement-level, while userId, attributionToken, and the offers array are per-user (each user gets the offers they’re eligible for, up to availableSlots). The bodies are expanded below for readability; in the file each record is written as a single line.
See the Attributions guide for how to track engagement on the links and tokens these records carry.
One-time sends (on-demand)
When you need to reach users outside of a schedule, fire a one-time, on-demand send. Set the medium to push or email, and pin the audience with exactly one of placementId (to reuse an existing placement’s strategy) or offerIds (to feature a specific set of offers).
The request returns 202 with a queued status, and the send is processed asynchronously.
On-demand sends are limited to once per 24 hours per issuer. A request inside that window returns 429 with a Retry-After header telling you how many seconds to wait.
Receiving the on-demand file
On-demand fires hand off the content file exactly like cadence sends. Once the queued job finishes building the file, Kard posts a notification to your subscribed webhook — pushNotificationPlacementFile when medium is push, emailNotificationPlacementFile when it’s email — carrying the presigned downloadUrl for the gzipped JSONL. Subscribe and consume the payload exactly as described in Receiving the content file above.
The file itself uses the same per-user JSONL records documented in Inside the content file — pushNotificationPlacementContent or emailNotificationPlacementContent, one line per eligible user. What fills those records depends on how you fired the send:
- By
placementId: the send reuses that placement’s content strategy,availableSlots, and derived copy, so the file matches the placement’s cadence send — records carry the placement’sid, andtitle/messagecome from the strategy’ssortandcategories. - By
offerIds:availableSlotsequals the number of offers you pinned and the copy falls back to the default template.
A pinned-offer (offerIds) email send — like the on-demand request above — produces records like this:
Firing the same pinned offer with medium: "push" produces a pushNotificationPlacementContent record instead — same default copy, with the offer resolved into a per-user attributionUrl: