Prices in Frisbii Media follow a three-level hierarchy:
Offer → Contract → Price Issue → Price Segments
An Offer contains one or more Products, each of which has Steps (billing phases). Each step references a Price Issue by ID. A Price Issue contains Price Segments — time-limited price entries, of which the most recently activated one is the current price.
This indirection means you cannot simply read a price directly off an offer object — you need to resolve it through the price issues. The example below shows how.
Step-by-step: get the current price for an offer
1. Get the offer
// @see https://api.frisbii-media.com/#tag/Offers/operation/searchProductOffers
$response = json_decode($client->request('GET',
'/api/v3.0/products/offers?plenigoOfferId=O_KJHKJHIUZIUZ',
['headers' => ['X-plenigo-token' => eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9]]
)->getBody()->getContents(), true);
$offer = $response['items'][0];
2. Get all price issues and resolve the active price per issue
A price issue can have multiple segments with different validFrom dates. The active price is the segment with the most recent validFrom that is still in the past.
$now = new DateTime();
$activePriceIssues = [];
// getList() is the reusable pagination helper — see Pagination: Iterating API Lists
$priceIssues = getList('/products/priceIssues');
foreach ($priceIssues as $issue) {
$segments = [];
foreach ($issue['priceSegments'] as $segment) {
$validFrom = new \DateTime($segment['validFrom']);
if ($validFrom > $now) {
// Segment not yet active — skip
continue;
}
// Use Unix timestamp as key so we can sort chronologically
$segments[$validFrom->getTimestamp()] = $segment;
}
// Sort ascending; the last entry is the most recently activated segment
ksort($segments);
$activePriceIssues[$issue['priceIssueId']] = end($segments);
}
3. Collect the steps and calculate the price per step
Products may appear in products or inside productGroups. Steps are shared across products — only the first product's steps need to be iterated for the structure, but prices must be summed across all products.
// Collect products from both possible locations in the offer
$products = ($offer['products'] ?? []);
if (!empty($offer['productGroups'][0]['products'])) {
$products = array_merge($products, $offer['productGroups'][0]['products']);
}
$steps = [];
// Use the first product to get the step structure
foreach ((reset($products)['steps'] ?? []) as $step) {
$step['price'] = 0.00;
$steps[$step['position']] = $step; // keyed by position for sorting
}
ksort($steps); // ensure steps are in order
// Sum up prices across all products per step
foreach ($products as $product) {
foreach ($product['steps'] as $step) {
$priceIssue = $activePriceIssues[$step['priceIssueId']] ?? null;
if (empty($priceIssue)) {
echo "Price issue not found: {$step['priceIssueId']}";
continue;
}
$steps[$step['position']]['price'] += $priceIssue['price'];
}
}
4. Output the results
foreach ($steps as $step) {
// If durationPeriod is 0, the runtime is unlimited
echo "{$step['position']}) "
. "runtime: {$step['durationPeriod']} {$step['durationTimespan']}, "
. "accounting period: {$step['accountingPeriod']} {$step['accountingTimespan']} "
. "— {$step['price']}\n";
}
Example output:
1) runtime: 0 MONTH, accounting period: 4 WEEK — 23.96
Means: pay €23.96 every 4 weeks, unlimited runtime.
1) runtime: 12 MONTH, accounting period: 1 MONTH — 13.00
2) runtime: 0 MONTH, accounting period: 1 MONTH — 19.00
Means: €13.00/month for the first 12 months, then €19.00/month indefinitely.
Key concepts
Term | Description |
|---|---|
Step | A billing phase of a subscription. An offer can have multiple steps with different durations and prices (e.g. intro price followed by regular price). |
Position | The order of steps. Position 1 is the first billing phase. |
durationPeriod | How long this step lasts. |
durationTimespan | Unit of |
accountingPeriod | How often the customer is billed during this step. |
accountingTimespan | Unit of |
Price Issue | The container for price history. Multiple segments allow price changes over time without creating new products. |
Price Segment | A specific price with a |