Campaigns & PRM

Campaigns and Partner Relationship Management (PRM) are the two tools suppliers use to activate their retailer network: run co-marketing campaigns and collect retailer commitments, and organize retailers into named tiers (Gold/Silver/Bronze or your own) with published benefits. This guide is for supplier admins and covers creating campaigns, sending invites to individual retailers and groups, tracking responses, and managing tiers and benefits. The companion Messaging feature for one-to-one supplier↔retailer conversations is covered at the end.

Feature flags

Campaigns, PRM, and Messaging are each gated by a per-tenant feature flag (campaigns, prm, messaging). If a feature is not enabled for your tenant, its API returns 403 and the section will not appear in your dashboard. Contact your Stockisto account contact to have a feature enabled.


Roles and access

All Campaigns and PRM actions require you to be signed in. Specific actions are restricted by role:

  • SupplierAdmin — full access: create/send campaigns, advance status, manage tiers, assign retailers.
  • SupplierViewer — read-only access to the campaign list and campaign detail.
  • RetailerAdmin — the retailer side: view their campaign invite inbox, respond to invites, and view the tiers they have been assigned to.

Every supplier's data is tenant-isolated. You only ever see campaigns, tiers, and assignments that belong to your own tenant.


Campaigns

A campaign is a supplier-initiated co-marketing proposal. You describe what you want to run, send it to selected retailers, and each retailer accepts or declines from their own inbox.

Campaign lifecycle

A campaign moves through these statuses:

StatusMeaning
DraftCreated but not yet sent. No invites exist.
SentInvites have been created and emailed to retailers.
ResponsesInRetailers are responding (manual stage).
ActiveCampaign is live (manual stage).
CompleteCampaign has finished (manual stage).

A new campaign always starts in Draft. Sending it (see below) moves it to Sent automatically. You can then advance it manually through ResponsesIn → Active → Complete as the campaign progresses.

Status is a label, not automation

Advancing status beyond Sent does not trigger any sending or notifications — it only updates the label used on your kanban board. Use it to track where each campaign stands.

Creating a campaign

Create a campaign as a SupplierAdmin. The required fields are:

  • Name — shown on the invite and on the kanban board.
  • Description — the full description of the campaign.
  • Participation ask — exactly what you want retailers to do (for example: feature a display, run a promotion).
  • Start date and End date — the End date must be after the Start date.
POST /api/v1/campaigns
{
  "name": "Spring Showroom Push",
  "description": "Co-branded spring promotion across showroom partners.",
  "participationAsk": "Feature the spring display for 4 weeks and run the 10% bundle offer.",
  "startDate": "2026-04-01T00:00:00Z",
  "endDate": "2026-05-15T00:00:00Z"
}

The campaign is created in Draft status. At this point no retailer has been contacted.

End date validation

If the End date is on or before the Start date, the request is rejected with a validation error. Name is also required — an empty name is rejected.

Campaign proposals (optional fields)

Campaigns created through the Proposal Wizard can carry extra structured fields. These are all optional and are null for campaigns created without them:

  • Asset URLs — a list of creative asset URLs to share with retailers.
  • Targeting criteria — a JSON string describing who the proposal targets, e.g. {"geoRadius":50,"categories":["HVAC"]}.
  • Budget — a proposed budget amount.
  • Currency — the currency for the budget. Defaults to SEK.
  • Proposal type — set to "Proposal" for wizard-created campaigns.
POST /api/v1/campaigns
{
  "name": "HVAC Installer Co-Marketing",
  "description": "Lead-gen push targeting HVAC installers within 50 km.",
  "participationAsk": "Co-fund local ads and accept routed installer leads.",
  "startDate": "2026-06-01T00:00:00Z",
  "endDate": "2026-07-01T00:00:00Z",
  "assetUrls": ["https://cdn.example.com/banner-a.png"],
  "targetingCriteria": "{\"geoRadius\":50,\"categories\":[\"HVAC\"]}",
  "budget": 25000,
  "currency": "SEK",
  "proposalType": "Proposal"
}

Sending a campaign to retailers and groups

Sending a campaign generates one invite per targeted retailer, emails each retailer, and moves the campaign to Sent. You can target retailers directly, by group, or both.

  • RetailerIds — specific retailers to invite.
  • GroupIds — retailer groups; every retailer in each group is expanded into the recipient list.

You must supply at least one retailer or one group — sending with both lists empty is rejected.

POST /api/v1/campaigns/{id}/send
{
  "retailerIds": ["8f3c…", "a91b…"],
  "groupIds": ["2d7e…"]
}

Retailer IDs and the members of every selected group are combined into a single de-duplicated recipient list, so a retailer who appears both directly and via a group is invited only once. Sending the same campaign again later only creates invites for retailers who do not already have one — existing invites are left untouched, so previously sent retailers are never invited twice or reset.

Use groups to keep targeting maintainable

Build retailer groups once (see the Sharing + Groups guide) and target campaigns by group. As you add retailers to a group, future campaign sends pick them up automatically — no need to re-select individuals each time.

Each newly invited retailer is sent an email notification with the campaign name. Email delivery is best-effort and runs in the background: a failed email never blocks the campaign from sending, and the invite is still created.

Tracking responses

The campaign list (the kanban board data) and the campaign detail view both report aggregate invite counts:

  • Invite count — total invites created for the campaign.
  • Accepted count — retailers who accepted.
  • Declined count — retailers who declined.
  • Pending count — retailers who have not yet responded.

Open a campaign's detail view to see the full per-invite list, including each retailer's response status, their optional note, when they were invited, and when they responded.

GET /api/v1/campaigns            → list with aggregate counts (kanban)
GET /api/v1/campaigns/{id}       → detail with full invite list

How retailers respond

From the retailer side, a RetailerAdmin sees a campaign invite inbox and responds to each invite:

  • Accepted or Declined, with an optional note (for example, explaining a decline or asking a question).
  • An invite can only be responded to once. After a retailer accepts or declines, the invite is locked and cannot be changed.
GET  /api/v1/campaigns/invites                       → retailer inbox
POST /api/v1/campaigns/invites/{inviteId}/respond    → accept or decline

As soon as a retailer responds, the accepted/declined/pending counts on your campaign update accordingly.


Partner Relationship Management (PRM)

PRM lets you define tiers for your retailer network and publish a list of benefits for each tier. Assign retailers to a tier, and that retailer sees their tier and its benefits from their own dashboard. Tier names are entirely up to you — Gold, Silver, and Bronze are common, but any name works.

Tiers and benefits

A tier has:

  • Name — e.g. "Gold", "Silver", "Bronze" or any custom name.
  • Description — optional text shown to assigned retailers.
  • Sort order — controls display ordering; lower numbers appear first.
  • Benefits — an ordered list of benefit lines (e.g. "Priority lead routing", "Co-op marketing fund", "Volume rebate"). Benefits are displayed in the order you list them.
POST /api/v1/prm/tiers
{
  "name": "Gold",
  "description": "Top-tier partners with full co-marketing support.",
  "sortOrder": 0,
  "benefits": [
    "Priority installer lead routing",
    "Co-op marketing fund eligibility",
    "Featured placement in the consumer locator"
  ]
}

Tier limit

A supplier can define up to 10 tiers. Attempting to create an 11th tier is rejected.

Updating and deleting tiers

Updating a tier replaces its name, description, sort order, and its entire benefit list. The benefits you submit on an update become the new complete list — any benefit you omit is removed, and the new list is renumbered in the order you provide.

GET    /api/v1/prm/tiers          → list your tiers (with benefits + assignment counts)
POST   /api/v1/prm/tiers          → create a tier
PUT    /api/v1/prm/tiers/{id}     → update a tier (replaces all benefits)
DELETE /api/v1/prm/tiers/{id}     → delete a tier

Editing benefits is a full replace

To keep an existing benefit while editing, include it in the update request. Anything not in the list you send is dropped.

Assigning retailers to a tier

Assign a retailer to a tier to grant them that tier's status and benefits. Two rules govern assignment:

  • A relationship must already exist. You can only assign a retailer that has a supplier-retailer relationship with you. Trying to assign an unrelated retailer is rejected.
  • One tier per retailer, per supplier. A retailer can be on only one of your tiers at a time. Assigning a retailer who is already on another of your tiers moves them — the previous assignment is removed automatically and replaced with the new one.
POST   /api/v1/prm/tiers/{id}/assign                       → assign a retailer
DELETE /api/v1/prm/tiers/{id}/assign/{retailerId}          → unassign a retailer
GET    /api/v1/prm/tiers/{id}/assignments                  → list a tier's retailers

To assign, send the retailer's ID:

POST /api/v1/prm/tiers/{id}/assign
{
  "retailerId": "8f3c…"
}

Each tier reports an assignment count, and you can list the retailers currently on any tier from the tier's assignments endpoint.

What the retailer sees

A RetailerAdmin can view all the tiers they have been assigned to across every supplier they work with. For each, the retailer sees the tier name, the supplier's name, and the full list of that tier's benefits.

GET /api/v1/prm/my-tiers    → retailer's tier status across all linked suppliers

Benefits are your value proposition

Retailers see the benefit list you publish for their tier — make each benefit concrete and specific. This is what motivates retailers to engage with your campaigns and move up a tier.


Messaging

Messaging provides one-to-one conversation threads between a supplier and an individual retailer. A thread is always between exactly two parties — your tenant and one retailer's tenant.

Starting a thread

Only a SupplierAdmin can start a thread, and only with a retailer you already have a relationship with. A thread requires a subject and a first message, which is recorded as the opening system message.

POST /api/v1/messaging/threads
{
  "retailerId": "8f3c…",
  "subject": "Spring campaign artwork",
  "firstMessage": "Hi — here is the artwork for the spring push. Let me know if it works."
}

If no supplier-retailer relationship exists for that retailer, the request is rejected.

Replying and reading

Once a thread exists, either participant — the supplier or the retailer — can post messages and read the conversation. Posting a message bumps the thread to the top of the list and sends a background email notification to the other party.

GET  /api/v1/messaging/threads                   → list your threads
GET  /api/v1/messaging/threads/{id}              → thread detail
GET  /api/v1/messaging/threads/{id}/messages     → paginated messages (page, pageSize)
POST /api/v1/messaging/threads/{id}/messages     → post a message
PUT  /api/v1/messaging/threads/{id}/read         → mark the thread read
GET  /api/v1/messaging/threads/unread-count      → unread badge count
  • The thread list shows a short preview of the last message and an unread count per thread.
  • A thread counts as unread for you when its newest message was sent by the other party and you have not marked it read since.
  • Messages are paginated; the default page size is 20.

Notifications and digests

New-message email notifications are sent in the background and are best-effort — a failed email never blocks the message from posting. Periodic daily/weekly digest emails are scaffolded but delivery is not yet active.


Where to go next