Direct Marketing Tariff Upload API Documentation
Overview
The /tariff-management/direct-marketing/upload endpoint allows clients to upload direct marketing tariff data in JSON format. This endpoint supports both single offer uploads and batch uploads of multiple offers.
The system uses capacity tiers defined at the configuration level. Each capacity tier creates a separate offer in the database.
Understanding the Structure
Before uploading pricing data, it's important to understand how offers, configurations, and price matrices work together.
Visual Hierarchy
┌─────────────────────────────────────────────────────────────┐
│ OFFER: "Solar Direct Marketing 100-250kW" │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ CONFIGURATION │ │
│ │ - Technology: Solar │ │
│ │ - Marketing Type: EEG │ │
│ │ - Enumeration: Spot │ │
│ │ - Fee Type: Relative │ │
│ │ - Capacity Tier: 100-250kW │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ PRICE MATRIX (Array of Contracts) │ │
│ │ │ │
│ │ Contract 1: Start 2026M02, Tenor 11M ─────┐ │ │
│ │ Contract 2: Start 2026M02, Tenor 1Y ─────┤ │ │
│ │ Contract 3: Start 2026M02, Tenor 2Y ─────┤ │ │
│ │ Contract 4: Start 2026M02, Tenor 3Y ─────┤ │ │
│ │ Contract 5: Start 2026M03, Tenor 10M ─────┤ │ │
│ │ ... │ │ │
│ │ Contract 23: Start 2028, Tenor 1Y ─────┘ │ │
│ │ │ │
│ │ ⚠️ All different tenors and start dates │ │
│ │ must be in THIS array │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Key Concepts
IMPORTANT: All contract tenors and start dates for a configuration must be within the same offer's priceMatrix array, even if they have different runtimes (Month, Quarter, Year).
You cannot:
- Upload the same start + tenor combination twice (validation will fail)
- Split tenors across multiple offers with the same configuration
You can:
- Mix monthly, quarterly, and yearly tenors in the same
priceMatrix - Have multiple start dates with different tenors
- Include dozens of contracts in a single offer
Endpoint Details
- URL:
POST /tariff-management/direct-marketing/upload - Content-Type:
multipart/form-data - Authentication: Required (Bearer token)
- File Format: JSON file upload
Request Format
The endpoint accepts a JSON file upload with the following structure:
Simplified Example
This basic example shows how to structure multiple contract durations under one configuration:
{
"offer": {
"name": "Solar EEG Spot - Direct Marketing",
"tariffType": 3,
"countryCode": "DE",
"description": "Basic example with multiple tenors",
"configuration": {
"technology": "Solar",
"directMarketingType": "EEG",
"enumerationType": "Spot",
"serviceFeeType": "Relative",
"capacityTiers": [
{ "min": 100, "max": 250 }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.5,
"basicFeePerYear": 1000
},
"priceMatrix": [
{
"start": "2026M02",
"tenor": "11M",
"prices": {
"2026M02": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M03": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M04": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M05": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M06": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M07": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M08": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M09": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M10": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M11": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2026M12": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 }
}
},
{
"start": "2026M02",
"tenor": "1Y",
"prices": {
"2026": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 }
}
},
{
"start": "2026M02",
"tenor": "3Y",
"prices": {
"2026": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2027": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2028": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 }
}
}
],
"otherPriceComponents": {
"basicFeePerYear": "None"
}
}
}
What this example shows:
- Three different contract durations (11 months, 1 year, 3 years) all starting in February 2026
- All grouped under ONE configuration in the
priceMatrixarray - Monthly tenor uses monthly price keys ("2026M02", "2026M03", etc.)
- Yearly tenors use yearly price keys ("2026", "2027", "2028")
Real-World Example
This example demonstrates a comprehensive pricing structure with multiple start dates and tenors (23 total contracts):
{
"offer": {
"name": "Marktprämie - Geförderte Direktvermarktung - Spotmarkt - 100-250 kW",
"tariffType": 3,
"countryCode": "DE",
"description": "",
"configuration": {
"technology": "Solar",
"directMarketingType": "EEG",
"capacityTiers": [
{ "min": 100, "max": 250 }
],
"enumerationType": "Spot",
"serviceFeeType": "Relative"
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.5,
"basicFeePerYear": 1000
},
"priceMatrix": [
// Monthly rolling contracts (Feb-Jun 2026)
{ "start": "2026M02", "tenor": "11M", "prices": { /* ... */ } },
{ "start": "2026M03", "tenor": "10M", "prices": { /* ... */ } },
{ "start": "2026M04", "tenor": "9M", "prices": { /* ... */ } },
{ "start": "2026M05", "tenor": "8M", "prices": { /* ... */ } },
{ "start": "2026M06", "tenor": "7M", "prices": { /* ... */ } },
// 1-year contracts starting monthly (Feb-Jun 2026)
{ "start": "2026M02", "tenor": "1Y", "prices": { "2026": { /* ... */ } } },
{ "start": "2026M03", "tenor": "1Y", "prices": { "2026": { /* ... */ } } },
{ "start": "2026M04", "tenor": "1Y", "prices": { "2026": { /* ... */ } } },
{ "start": "2026M05", "tenor": "1Y", "prices": { "2026": { /* ... */ } } },
{ "start": "2026M06", "tenor": "1Y", "prices": { "2026": { /* ... */ } } },
// 2-year contracts starting monthly (Feb-Jun 2026)
{ "start": "2026M02", "tenor": "2Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ } } },
{ "start": "2026M03", "tenor": "2Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ } } },
{ "start": "2026M04", "tenor": "2Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ } } },
{ "start": "2026M05", "tenor": "2Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ } } },
{ "start": "2026M06", "tenor": "2Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ } } },
// 3-year contracts starting monthly (Feb-May 2026)
{ "start": "2026M02", "tenor": "3Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ }, "2028": { /* ... */ } } },
{ "start": "2026M03", "tenor": "3Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ }, "2028": { /* ... */ } } },
{ "start": "2026M04", "tenor": "3Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ }, "2028": { /* ... */ } } },
{ "start": "2026M05", "tenor": "3Y", "prices": { "2026": { /* ... */ }, "2027": { /* ... */ }, "2028": { /* ... */ } } },
// Yearly contracts starting in calendar years
{ "start": "2027", "tenor": "1Y", "prices": { "2027": { /* ... */ } } },
{ "start": "2027", "tenor": "2Y", "prices": { "2027": { /* ... */ }, "2028": { /* ... */ } } },
{ "start": "2028", "tenor": "1Y", "prices": { "2028": { /* ... */ } } }
],
"otherPriceComponents": {
"basicFeePerYear": "None"
}
}
}
What this pattern provides:
- Flexibility: Customers can start contracts in different months
- Choice: Multiple duration options (short-term monthly, 1-year, 2-year, 3-year)
- Coverage: Comprehensive pricing for 2026-2028 period
- All grouped: 23 different contracts under ONE offer configuration
Batch Upload
You can upload multiple offers at once using the offers array:
{
"offers": [
{
"name": "Solar EEG Spot 100-250kW",
"tariffType": 3,
"configuration": { /* ... */ },
"priceMatrix": [ /* ... */ ]
},
{
"name": "Solar EEG Spot 251-500kW",
"tariffType": 3,
"configuration": { /* ... */ },
"priceMatrix": [ /* ... */ ]
}
]
}
Recommended Approach: Create separate offers for each capacity tier (one tier per offer) for clarity and easier maintenance.
Field Descriptions
Root Level Fields
| Field | Type | Required | Description |
|---|---|---|---|
offer |
object | Yes* | Single offer object (for single upload) |
offers |
array | Yes* | Array of offer objects (for batch upload) |
*Either offer or offers must be provided, but not both.
Offer Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Name of the tariff offer |
tariffType |
integer | Yes | Must be 3 for direct marketing |
countryCode |
string | Yes | ISO country code (e.g., "DE") |
description |
string | No | Optional description of the offer |
configuration |
object | Yes | Technology and marketing type configuration |
fees |
object | Yes | Fee structure |
priceMatrix |
array | Yes | Array of contract periods with pricing |
otherPriceComponents |
object | Yes | Additional price components |
Configuration Object
| Field | Type | Required | Description |
|---|---|---|---|
technology |
string | Yes | Technology type: "Solar" or "Wind" |
directMarketingType |
string | Yes | Marketing type: "EEG" or "Other" |
enumerationType |
string | Yes | Enumeration type: "Spot" or "MarketValue" |
serviceFeeType |
string | Yes | Service fee type: "Relative" or "Absolute" |
capacityTiers |
array | No | Array of capacity range objects. Recommended: Use one tier per offer for clarity. |
Capacity Tiers
Each capacity tier object in the capacityTiers array has:
| Field | Type | Required | Description |
|---|---|---|---|
min |
decimal | No | Minimum capacity in kW (default: 0) |
max |
decimal | No | Maximum capacity in kW. Use null for unlimited upper bound (e.g., ">1000kW") |
Recommended Approach:
Create separate offers for each capacity tier:
// Offer 1
{
"name": "Solar Direct Marketing 100-250kW",
"configuration": {
"capacityTiers": [{ "min": 100, "max": 250 }]
}
}
// Offer 2
{
"name": "Solar Direct Marketing 251-500kW",
"configuration": {
"capacityTiers": [{ "min": 251, "max": 500 }]
}
}
Benefits:
- Clearer pricing structure
- Easier to maintain and update
- Better user experience when selecting offers
Note: While multiple capacity tiers in one offer is supported, single tier per offer is clearer and the recommended approach.
Fees Object
| Field | Type | Required | Description |
|---|---|---|---|
guaranteeOfOriginFeeEurPerMWh |
decimal | No | Guarantee of origin fee per MWh in EUR |
basicFeePerYear |
decimal | No | Basic annual fee in EUR |
Price Matrix Structure
⚠️ CRITICAL RULE: All tenors for a configuration must be defined in the same offer's priceMatrix array, even if they have different runtimes (Month, Quarter, Year).
The priceMatrix is an array of contract objects. Each contract defines pricing for a specific time period:
"priceMatrix": [
{
"start": "2026M02", // Start period
"tenor": "11M", // Contract duration
"prices": {
"2026M02": { // Monthly price keys for monthly tenor
"marketValuePercent": 10.0,
"variableFixedFeeEurPerMWh": 50.0
},
"2026M03": { /* ... */ }
}
},
{
"start": "2026M02", // Same start, different tenor
"tenor": "1Y", // Yearly tenor
"prices": {
"2026": { // Yearly price key for yearly tenor
"marketValuePercent": 10.0,
"variableFixedFeeEurPerMWh": 50.0
}
}
}
]
Contract Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
start |
string | Yes | Start period. See format table below. |
tenor |
string | Yes | Contract duration. See tenor format table below. |
prices |
object | Yes | Pricing schedule with period keys as keys |
Start Period Formats
| Format | Example | Description |
|---|---|---|
| Monthly | "2026M01", "2026M02", ..., "2026M12" |
Month-specific start (YYYYMNN where NN is 01-12) |
| Quarterly | "2026Q1", "2026Q2", "2026Q3", "2026Q4" |
Quarter-specific start (YYYYQN where N is 1-4) |
| Yearly | "2026", "2027", "2028" |
Year-specific start (YYYY) |
Tenor Formats
| Format | Example | Description |
|---|---|---|
| Monthly | "1M", "6M", "11M", "12M" |
Contract duration in months |
| Quarterly | "1Q", "2Q", "4Q" |
Contract duration in quarters |
| Yearly | "1Y", "2Y", "3Y", "5Y" |
Contract duration in years |
Price Key Format Rules
The price keys within the prices object must match the tenor format:
| Tenor Format | Price Keys Must Use |
|---|---|
| Monthly (e.g., "11M") | Monthly keys: "2026M02", "2026M03", etc. |
| Quarterly (e.g., "4Q") | Quarterly keys: "2026Q1", "2026Q2", etc. |
| Yearly (e.g., "3Y") | Yearly keys: "2026", "2027", "2028" |
Valid Combinations
✅ Valid:
{
"start": "2026M02",
"tenor": "11M",
"prices": {
"2026M02": { /* ... */ },
"2026M03": { /* ... */ }
}
}
✅ Valid:
{
"start": "2026M02",
"tenor": "2Y",
"prices": {
"2026": { /* ... */ },
"2027": { /* ... */ }
}
}
❌ Invalid - Wrong price key format:
{
"start": "2026M02",
"tenor": "11M",
"prices": {
"2026": { /* ... */ } // Should use monthly keys like "2026M02"
}
}
Price Entry Object
Each entry in the prices object has the period key (year, quarter, or month) and pricing details:
| Field | Type | Required | Description |
|---|---|---|---|
fixedFeeEurPerMWh |
decimal | No | Fixed fee per MWh in EUR |
marketValuePercent |
decimal | No | The percentage fee of the Spot or Market Value revenues generated in a given hour |
variableFixedFeeEurPerMWh |
decimal | No | Variable fixed fee per MWh in EUR |
guaranteeOfOriginFeeEurPerMWh |
decimal | No | Guarantee of origin fee per MWh in EUR (overrides fees level) |
basicFeePerYear |
decimal | No | Basic annual fee in EUR (overrides fees level) |
Note: At least one pricing field must be provided per entry.
Other Price Components Object
| Field | Type | Required | Description |
|---|---|---|---|
basicFeePerYear |
string | Yes | Additional price component configuration. Use string "None" when no additional components apply, or "Location factor" when location-based pricing is used. |
Examples:
// No additional components
"otherPriceComponents": {
"basicFeePerYear": "None"
}
// With location factor
"otherPriceComponents": {
"basicFeePerYear": "Location factor"
}
Common Patterns
Here are typical pricing patterns you can implement using the priceMatrix array:
Pattern 1: Rolling Monthly Start Dates with Multiple Durations
Scenario: Offer customers flexibility to start contracts in different months with various durations
Structure:
- 5 monthly starts (Feb-Jun 2026)
- Each start has 3 tenors (11M, 1Y, 3Y)
- = 15 priceMatrix entries in one offer
Example:
"priceMatrix": [
{ "start": "2026M02", "tenor": "11M", "prices": { /* ... */ } },
{ "start": "2026M02", "tenor": "1Y", "prices": { /* ... */ } },
{ "start": "2026M02", "tenor": "3Y", "prices": { /* ... */ } },
{ "start": "2026M03", "tenor": "10M", "prices": { /* ... */ } },
{ "start": "2026M03", "tenor": "1Y", "prices": { /* ... */ } },
{ "start": "2026M03", "tenor": "3Y", "prices": { /* ... */ } },
// ... continues for Apr, May, Jun
]
Pattern 2: Multiple Year Contracts with Same Start
Scenario: Same start date, different contract lengths
Structure:
- Start: "2027"
- Tenors: 1Y, 2Y, 3Y
- = 3 priceMatrix entries
Example:
"priceMatrix": [
{
"start": "2027",
"tenor": "1Y",
"prices": {
"2027": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 }
}
},
{
"start": "2027",
"tenor": "2Y",
"prices": {
"2027": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2028": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 }
}
},
{
"start": "2027",
"tenor": "3Y",
"prices": {
"2027": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2028": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 },
"2029": { "marketValuePercent": 10.0, "variableFixedFeeEurPerMWh": 50.0 }
}
}
]
Pattern 3: Monthly Contracts Through Year-End
Scenario: Short-term monthly contracts for remaining months of year
Structure:
- Feb: 11M (through end of year)
- Mar: 10M
- Apr: 9M
- ...
- Jun: 7M
- = 5 priceMatrix entries with decreasing durations
Example:
"priceMatrix": [
{ "start": "2026M02", "tenor": "11M", "prices": { /* Feb-Dec */ } },
{ "start": "2026M03", "tenor": "10M", "prices": { /* Mar-Dec */ } },
{ "start": "2026M04", "tenor": "9M", "prices": { /* Apr-Dec */ } },
{ "start": "2026M05", "tenor": "8M", "prices": { /* May-Dec */ } },
{ "start": "2026M06", "tenor": "7M", "prices": { /* Jun-Dec */ } }
]
Enumeration Types
Enumeration Type (Market Type)
Spot- Spot market pricingMarketValue- Market value pricing
Service Fee Type
Relative- Relative pricing modelAbsolute- Absolute pricing model
Response Format
The endpoint returns a DirectMarketingImportResult object:
{
"success": true,
"results": [
{
"offerId": "guid",
"success": true,
"message": "Imported successfully"
}
]
}
Note: When using capacity tiers, multiple results will be returned - one for each capacity tier that created a separate offer.
Response Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Overall success status (true if all offers imported successfully) |
results |
array | Array of import results. Multiple results per JSON offer if capacity tiers are used. |
results[].offerId |
guid | ID of the created offer (null if failed) |
results[].success |
boolean | Success status for this specific offer |
results[].message |
string | Status message for this offer |
Example Usage
cURL Example
curl -X POST \
https://api.example.com/tariff-management/direct-marketing/upload \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "data=@tariff_data.json"
JavaScript Example
const formData = new FormData();
formData.append('data', fileInput.files[0]);
fetch('/tariff-management/direct-marketing/upload', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN'
},
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
PowerShell Example
$filePath = 'C:\path\to\tariff_data.json'
$headers = @{ Authorization = 'Bearer YOUR_TOKEN' }
$form = @{ data = Get-Item $filePath }
Invoke-RestMethod -Uri 'https://api.example.com/tariff-management/direct-marketing/upload' `
-Method Post `
-Headers $headers `
-Form $form
Error Handling
The API returns appropriate HTTP status codes:
200 OK- Successful upload400 Bad Request- Invalid request or file format401 Unauthorized- Missing or invalid authentication500 Internal Server Error- Server error during processing
Error responses include detailed messages in the results array for each failed offer.
Validation Rules
Capacity Tiers:
- Each tier must have
min < max(if both are specified) - Capacity values must be non-negative
- Capacity overlap between different start periods is allowed
- Each tier must have
Required Fields: All required fields must be present and non-null
Data Types: All values must match the specified data types
Enumeration Values: Technology, marketing type, and other enums must use valid values
File Format: Must be valid JSON format
Pricing Data: At least one pricing component must be provided per price entry
Unique Tenor Combinations: You cannot upload the same start + tenor combination twice within the same offer. Each priceMatrix entry must be unique.
- ✅ Valid:
{"start": "2026M02", "tenor": "1Y"}and{"start": "2026M03", "tenor": "1Y"} - ❌ Invalid: Two entries with
{"start": "2026M02", "tenor": "1Y"}
- ✅ Valid:
Configuration Grouping: All tenors for a pricing configuration must be within the same offer's
priceMatrixarray. You cannot split tenors across multiple offers with the same configuration.- ✅ Valid: One offer with 23 priceMatrix entries covering all start dates and tenors
- ❌ Invalid: Multiple offers with same configuration, each with subset of tenors
Price Key Format Consistency:
- Monthly tenors (e.g., "11M") must use monthly price keys ("2026M02", "2026M03")
- Quarterly tenors (e.g., "4Q") must use quarterly price keys ("2026Q1", "2026Q2")
- Yearly tenors (e.g., "1Y", "3Y") must use yearly price keys ("2026", "2027")
Years: Schedule years cannot be in the past
Frequently Asked Questions
Q: Can I mix monthly and yearly tenors in the same priceMatrix?
A: Yes! You can mix different time periods and contract durations within the same offer's priceMatrix array. This is actually a common pattern. See the "Common Patterns" section for examples.
Q: How many priceMatrix entries can one offer have?
A: There is no hard limit, but each entry must be unique (unique start + tenor combination). Real-world examples show 23+ entries in a single offer for comprehensive pricing coverage.
Q: What happens if I upload the same tenor twice for the same start date?
A: The API will reject the upload with a validation error. Each start + tenor combination must be unique within an offer. For example, you cannot have two entries with {"start": "2026M02", "tenor": "1Y"}.
Q: Can I use quarterly periods (2026Q1) instead of monthly (2026M01)?
A: Yes, the API supports quarterly format "YYYYQN" where N is 1-4. Use "2026Q1" for Q1 2026, "2026Q2" for Q2, etc. The same rules apply - quarterly tenors must use quarterly price keys.
Q: Should I create one offer with multiple capacity tiers, or multiple offers with one tier each?
A: The recommended approach is one capacity tier per offer. This makes pricing clearer and easier to manage. For example, create separate offers for "100-250kW", "251-500kW", etc., each with their own priceMatrix.
Q: Can I have different pricing for different start dates in the same offer?
A: Yes! That's the entire purpose of the priceMatrix array. Each entry can have a different start date and different pricing, all under one configuration.
Important Notes on Capacity Tiers
Recommended Approach: One Tier Per Offer
While the API supports multiple capacity tiers in one offer, the recommended approach is to create separate offers for each capacity tier.
Example:
Instead of this:
{
"offer": {
"name": "Solar Direct Marketing",
"configuration": {
"capacityTiers": [
{ "min": 100, "max": 250 },
{ "min": 251, "max": 500 },
{ "min": 501, "max": 750 }
]
}
}
}
Do this:
{
"offers": [
{
"name": "Solar Direct Marketing 100-250kW",
"configuration": {
"capacityTiers": [{ "min": 100, "max": 250 }]
}
},
{
"name": "Solar Direct Marketing 251-500kW",
"configuration": {
"capacityTiers": [{ "min": 251, "max": 500 }]
}
},
{
"name": "Solar Direct Marketing 501-750kW",
"configuration": {
"capacityTiers": [{ "min": 501, "max": 750 }]
}
}
]
}
Benefits:
- Each capacity tier has its own offer with distinct pricing
- Easier to maintain and update specific capacity ranges
- Clearer for customers when selecting appropriate offers
- Better tracking and reporting per capacity tier
How Capacity Tiers Work
If you do use multiple tiers in one offer, each tier creates a separate offer in the database:
"capacityTiers": [
{ "min": 100, "max": 250 },
{ "min": 251, "max": 500 }
]
Creates:
"Your Offer Name (100-250kW)""Your Offer Name (251-500kW)"
Each offer will have all schedules from the priceMatrix but with different capacity ranges at the offer level.
Without Capacity Tiers
If you omit capacityTiers, the system creates 1 offer with no capacity restrictions:
"configuration": {
"technology": "Wind",
"directMarketingType": "EEG",
"enumerationType": "MarketValue",
"serviceFeeType": "Absolute"
// No capacityTiers
}
Result: One offer with MinCapacity = null, MaxCapacity = null
Format Detection
The system automatically detects the import type based on the presence of specific fields in the uploaded JSON file. This detection happens at the service layer before processing begins.
Detection Logic
Direct Marketing Format:
- Has
configurationobject withenumerationTypeandserviceFeeTypefields - Has
priceMatrixas an array of contract objects - Each contract has
start,tenor, andpricesfields
PPA Format (Separate format):
- Has PPA-specific configuration fields (e.g.,
ppaStructure,guaranteeOfOrigin) - Different structure entirely
The endpoint intelligently routes the import to the correct processing logic based on the detected format.
Notes
- The endpoint supports both single offer and batch uploads
- All monetary values are in EUR
- Capacity values are in kW
- Multiple database offers may be created from a single JSON offer if capacity tiers are defined
- The system performs validation on offer-level capacity ranges
- Failed offers in batch uploads do not prevent successful offers from being processed
- Offer names are automatically formatted to include capacity range (e.g., "(100-250kW)", "(>1000kW)")
- All tenors for a configuration must be in the same
priceMatrixarray - this is a fundamental rule of the API