Skip to main content

Promotions API

This guide covers how external integrators read promotion data from DRE.

info
There is no /pos-integration/Promotions endpoint

Older notes referenced a read-only GET /pos-integration/Promotions OData collection. That path does not exist. The POS Service (/pos) is action-based (POST /pos/v2/evaluate, /confirm, …) and exposes no readable Promotions entity. To read promotion master data, use the Admin Service OData V4 collection GET /admin/Promotions, documented here. See the Admin Service reference for the full entity catalogue.

Fetching Active Promotions

Retrieve all currently active promotions via the Admin Service (OData V4):

GET /admin/Promotions?$filter=status eq 'ACTIVE'

status is a code-list value (DRAFT, ACTIVE, INACTIVE, EXPIRED, ARCHIVED, PENDING_APPROVAL, APPROVED, REJECTED, PILOT). The temporarily-disabled status is INACTIVE. Filter on the literal you need.

Selecting Fields

Trim the payload to the fields your POS needs with $select:

GET /admin/Promotions?$filter=status eq 'ACTIVE'&$select=ID,name,status,type,validFrom,validTo

Promotions expose these navigation properties (see the Admin Service reference for the full list):

Navigation propertyTargetDescription
posGroupsPromotionPosGroupsPOS group assignments (empty = all POS groups)
calculationConfigCalculationConfigsCalculation mode, rounding, precision
campaignCampaignsOptional campaign grouping

Expand them in a single request:

GET /admin/Promotions?$filter=status eq 'ACTIVE'&$expand=posGroups,calculationConfig,campaign
warning
Conditions are NOT an $expand on Promotions

DRE uses a flat, per-promotion condition model — there is no conditionGroups navigation and no nested condition tree. Conditions (and DiscountActions) point back to their promotion via a promotion association, so you query them with a filter, not an expand:

GET /admin/Conditions?$filter=promotion_ID eq <promotionID>
GET /admin/DiscountActions?$filter=promotion_ID eq <promotionID>

Pagination

For large result sets, use server-driven pagination with $top / $skip:

GET /admin/Promotions?$top=50&$skip=0
GET /admin/Promotions?$top=50&$skip=50

Add $count=true to obtain the total row count alongside the page.

Polling Strategy

  1. Poll interval: Every 5–15 minutes depending on business requirements.
  2. Filter on modifiedAt: Only fetch promotions changed since your last sync. modifiedAt is the managed timestamp on every entity (CAP managed aspect, @sap/cds/common); there is no changedAt field.
GET /admin/Promotions?$filter=modifiedAt gt 2026-05-01T00:00:00Z&$orderby=modifiedAt
  1. Cache locally: Store promotion data in your POS system and sync incrementally on each poll.

Error Handling

HTTP StatusMeaningAction
200SuccessProcess response
401UnauthorizedRefresh auth token
403ForbiddenCheck role/scope assignment
429Rate limitedBack off and retry
500Server errorRetry with exponential backoff

Response Format

All responses follow OData v4 JSON format:

{
"@odata.context": "$metadata#Promotions",
"value": [
{
"ID": "b1a2c3d4-0001-4000-8000-000000000001",
"name": "Summer Sale 2025",
"status": "ACTIVE",
"type": "RECEIPT",
"validFrom": "2025-06-01T00:00:00Z",
"validTo": "2025-08-31T23:59:59Z",
"modifiedAt": "2025-05-28T09:14:02Z"
}
]
}

Writing promotion data via the Public API

This page covers reading promotion master data. To write from an external system (create promotions, campaigns, templates, pilot configs, or bulk-import master data), use the stable Public API at /api/v1 — not the Admin Service (which is Fiori/draft-coupled).

Relevant writable paths for promotion-centric integrations:

GoalPathScope
Create / update a promotionPOST / PATCH /api/v1/PromotionsPublicApi.Write
Bulk-import promotionsPOST /api/v1/Promotions:bulk-import (track via ImportJobs)PublicApi.Write
Create a campaign and attach promotionsPOST /api/v1/Campaigns + Campaigns(<ID>)/addPromotionsPublicApi.Write
Instantiate a promotion from a templatePOST /api/v1/createPromotionFromTemplatePublicApi.Write
Configure an A/B pilot for a promotionPOST /api/v1/PromotionPilotConfigsPublicApi.Write

Every writable /api/v1 collection is tenant-scoped — a caller only sees and writes its own tenant's rows (cross-tenant access returns 404). See the Public API reference for the full collection catalogue, read/write matrix, action contracts, and tenant-isolation rules, and Article Import API for the bulk-import body schema.

See Also

  • Public API reference/api/v1 collection catalogue, read/write matrix, OAuth scopes, tenant isolation, and the Campaigns / PromotionTemplates / PromotionPilotConfigs write paths.
  • Admin Service reference — full entity catalogue, navigation properties, draft lifecycle, and custom actions.
  • API Reference overview — all six DRE services and their base paths.