PPA Upload API - Complete User Guide
Overview
This guide explains how to upload Power Purchase Agreement (PPA) offers to the system using JSON files. You can upload single or multiple offers with different configurations for capacity ranges, pricing models, and time periods.
Endpoint: POST /tariff-management/ppa/upload
File Type: JSON uploaded as multipart/form-data
Note: For information on how versioning, price updates, and the contract-options API work, see the Price Upload Guide.
Table of Contents
- Quick Start
- What is a PPA Offer
- JSON Structure Overview
- Field Reference
- Complete JSON Examples - All Combinations
- How to Upload
- Response Format
- Validation Rules
- Common Mistakes
- Troubleshooting
Quick Start
- Create a JSON file with your PPA offer data
- Validate the JSON structure matches one of the examples below
- Upload using the API endpoint with Bearer authentication
- Check response for success or error messages
What is a PPA Offer
A PPA (Power Purchase Agreement) offer defines pricing and terms for buying or selling energy through long-term contracts:
- Energy type: Solar, Wind, or Biomass
- Direction: Upstream (selling) or Downstream (buying)
- Payment structure: Pay As Forecasted or Pay As Produced
- Pricing granularity: Yearly, quarterly, or monthly
- Contract details: Start period, duration (tenor), hedge percentage
- Capacity ranges: Optional tiers that create separate offers
- Certificate handling: Guarantee of Origin (GOO) management
JSON Structure Overview
Single Offer Upload
{
"offer": {
"name": "Offer Name",
"tariffType": 5,
"countryCode": "DE",
"configuration": { ... },
"fees": { ... },
"priceMatrix": [ ... ]
}
}
Batch Upload (Multiple Offers)
{
"offers": [
{ "name": "First Offer", ... },
{ "name": "Second Offer", ... }
]
}
Note: Use either offer (singular) or offers (plural), not both.
Field Reference
Root Level
| Field | Type | Required | Description |
|---|---|---|---|
offer |
object | Yes* | Single offer (for uploading one offer) |
offers |
array | Yes* | Array of offers (for batch upload) |
*Use one or the other, not both.
Offer Object
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
name |
string | Yes | Descriptive name for the offer | "Solar PPA Q2-Q4 2026" |
tariffType |
integer | Yes | 5 for Upstream (selling), 6 for Downstream (buying) |
5 |
countryCode |
string | Yes | ISO 3166-1 alpha-2 country code | "DE", "AT" |
description |
string | No | Optional detailed description | "Solar PPA with GOO" |
configuration |
object | Yes | Technical configuration | See below |
fees |
object | Yes | Default fee structure | See below |
priceMatrix |
array | Yes | Array of pricing contracts | See below |
Configuration Object
| Field | Type | Required | Allowed Values | Description |
|---|---|---|---|---|
technology |
string | Yes | "Solar", "Wind", "Biomass" |
Energy source type |
ppaStructure |
string | Yes | "PayAsForecasted", "PayAsProduced" |
Payment calculation method |
guaranteeOfOrigin |
string | Yes | "None", "Provider", "Customer" |
Who handles GOO certificates |
negativePrices |
string | Yes | "Included", "Excluded" |
Negative price hours handling |
hedgeSharePercent |
decimal | No | 0-100 | Percentage of production hedged |
capacityTiers |
array | No | Array of capacity ranges | Creates separate offers per tier |
Capacity Tiers
capacityTiers is an array of capacity range objects. Each tier creates a separate offer in the database.
Capacity Range Object:
| Field | Type | Required | Description |
|---|---|---|---|
min |
decimal | No | Minimum value (defaults to 0 if omitted). Unit depends on PPA type - see below. |
max |
decimal | No | Maximum value (use null for unlimited). Unit depends on PPA type - see below. |
Unit of Measurement:
- Upstream PPAs (tariffType: 5): Capacity tiers are specified in installed capacity (kW)
- Downstream PPAs (tariffType: 6): Capacity tiers are specified in energy volume (MWh)
Examples:
{ "min": 0, "max": 499 }→ Creates offer named "Your Offer (0-499kW)"{ "min": 500, "max": 999 }→ Creates offer named "Your Offer (500-999kW)"{ "min": 1000, "max": null }→ Creates offer named "Your Offer (>1000kW)"
Important Behavior:
- If
capacityTiersis provided with 3 tiers, 3 separate offers are created - If
capacityTiersis omitted, 1 offer is created with no capacity restrictions - All tiers share the same
priceMatrixschedules
Offer Uniqueness Requirements
Each offer must have a unique configuration in the system. You cannot upload two offers with identical configuration settings (same combination of technology, ppaStructure, guaranteeOfOrigin, negativePrices, hedgeSharePercent, and capacityTiers).
If you need to provide different pricing schedules, group them as multiple contracts within the priceMatrix array of a single offer rather than creating separate offers with the same configuration. This approach:
- Keeps related pricing options together under one offer
- Prevents duplicate configuration errors
- Makes offer management cleaner and more organized
Example: Instead of creating two separate "Solar PPA Upstream" offers with different start dates, create one offer with multiple contracts in the priceMatrix array, each with its own start period and pricing schedule.
Fees Object
Default fees that apply to all pricing periods unless overridden:
| Field | Type | Required | Description |
|---|---|---|---|
guaranteeOfOriginFeeEurPerMWh |
decimal | No | Default Guarantee of Origin fee (EUR/MWh) |
basicFeePerYear |
decimal | No | Default annual basic fee (EUR) |
Price Matrix (Array of Contracts)
The priceMatrix is an array where each element represents a contract with a start period, duration (tenor), and pricing schedule.
Important: You can mix different time resolutions within the same priceMatrix. For example, you can have:
- One contract with yearly pricing ("2026", "2027", "2028")
- Another contract with quarterly pricing ("2026Q1", "2026Q2", "2026Q3", "2026Q4")
- Another contract with monthly pricing ("2026M01", "2026M02", ...)
- All in the same offer
This allows you to provide multiple contract options with different pricing granularities.
Contract Object:
| Field | Type | Required | Description |
|---|---|---|---|
start |
string | Yes | Start period: "YYYY" (yearly), "YYYYQN" (quarterly), or "YYYYMNN" (monthly) |
tenor |
string | No | Contract duration: "3Y", "4Q", "12M", etc. (auto-calculated if omitted) |
prices |
object | Yes | Pricing schedule with period keys |
Start Period Formats:
- Yearly:
"2026","2027" - Quarterly:
"2026Q1"(Q1 2026),"2027Q3"(Q3 2027) - Monthly:
"2026M03"(March 2026),"2027M01"(January 2027)
Note: PPA supports yearly, quarterly, and monthly resolutions.
Tenor Formats:
- Years:
"1Y","2Y","3Y" - Quarters:
"2Q","4Q","8Q" - Months:
"6M","12M","24M"
Prices Object:
Keys are period identifiers (matching the start format). Each period contains pricing fields:
| Field | Type | Required | Description |
|---|---|---|---|
priceEurPerMWh |
decimal | Yes | PPA price per MWh (EUR) |
guaranteeOfOriginFeeEurPerMWh |
decimal | No | Override default GOO fee for this period |
Note: priceEurPerMWh is required for each period.
Complete JSON Examples - All Combinations
1. Solar Upstream + PayAsForecasted + Quarterly + Multiple Capacity Tiers
Most common scenario: Creates 3 separate offers with capacity-based pricing.
{
"offer": {
"name": "Solar PPA Q2-Q4 2026",
"tariffType": 5,
"countryCode": "DE",
"description": "Solar PPA with quarterly pricing and capacity tiers",
"configuration": {
"technology": "Solar",
"ppaStructure": "PayAsForecasted",
"guaranteeOfOrigin": "Provider",
"negativePrices": "Included",
"hedgeSharePercent": 75,
"capacityTiers": [
{ "min": 0, "max": 499 },
{ "min": 500, "max": 999 },
{ "min": 1000, "max": null }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.5,
"basicFeePerYear": 1200
},
"priceMatrix": [
{
"start": "2026Q2",
"tenor": "3Q",
"prices": {
"2026Q2": {
"priceEurPerMWh": 64.0,
"guaranteeOfOriginFeeEurPerMWh": 0.5
},
"2026Q3": {
"priceEurPerMWh": 65.0,
"guaranteeOfOriginFeeEurPerMWh": 0.5
},
"2026Q4": {
"priceEurPerMWh": 66.0,
"guaranteeOfOriginFeeEurPerMWh": 0.5
}
}
}
]
}
}
Result: Creates 3 database offers:
- "Solar PPA Q2-Q4 2026 (0-500kW)"
- "Solar PPA Q2-Q4 2026 (500-1000kW)"
- "Solar PPA Q2-Q4 2026 (>1000kW)"
Each offer has the same quarterly pricing schedule.
2. Wind Upstream + PayAsProduced + Yearly + No Capacity Tiers
Single offer without capacity restrictions: Creates 1 offer with yearly pricing.
{
"offer": {
"name": "Wind PPA 2027-2028",
"tariffType": 5,
"countryCode": "DE",
"description": "Wind PPA with yearly pricing",
"configuration": {
"technology": "Wind",
"ppaStructure": "PayAsProduced",
"guaranteeOfOrigin": "Customer",
"negativePrices": "Excluded",
"hedgeSharePercent": 80
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.3,
"basicFeePerYear": 1500
},
"priceMatrix": [
{
"start": "2027",
"tenor": "2Y",
"prices": {
"2027": {
"priceEurPerMWh": 62.5
},
"2028": {
"priceEurPerMWh": 63.2
}
}
}
]
}
}
Result: Creates 1 offer with no capacity restrictions.
3. Solar Downstream + PayAsForecasted + Monthly Pricing
Monthly granularity: 12-month contract with monthly price variations.
{
"offer": {
"name": "Solar PPA Monthly 2026",
"tariffType": 6,
"countryCode": "DE",
"description": "Downstream solar PPA with monthly pricing",
"configuration": {
"technology": "Solar",
"ppaStructure": "PayAsForecasted",
"guaranteeOfOrigin": "Provider",
"negativePrices": "Included",
"hedgeSharePercent": 70,
"capacityTiers": [
{ "min": 100, "max": 500 }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.5,
"basicFeePerYear": 1200
},
"priceMatrix": [
{
"start": "2026M01",
"tenor": "12M",
"prices": {
"2026M01": { "priceEurPerMWh": 62.5 },
"2026M02": { "priceEurPerMWh": 63.0 },
"2026M03": { "priceEurPerMWh": 63.5 },
"2026M04": { "priceEurPerMWh": 64.0 },
"2026M05": { "priceEurPerMWh": 64.5 },
"2026M06": { "priceEurPerMWh": 65.0 },
"2026M07": { "priceEurPerMWh": 65.5 },
"2026M08": { "priceEurPerMWh": 66.0 },
"2026M09": { "priceEurPerMWh": 65.5 },
"2026M10": { "priceEurPerMWh": 65.0 },
"2026M11": { "priceEurPerMWh": 64.5 },
"2026M12": { "priceEurPerMWh": 64.0 }
}
}
]
}
}
Result: Creates 1 offer with monthly pricing for the entire year 2026.
4. Biomass Upstream + Multiple Contracts (Mixed Time Resolutions)
Different time resolutions in the same priceMatrix: This example demonstrates quarterly and yearly contracts in one offer.
{
"offer": {
"name": "Biomass PPA 2026-2029",
"tariffType": 5,
"countryCode": "DE",
"description": "Biomass PPA with mixed quarterly and yearly pricing",
"configuration": {
"technology": "Biomass",
"ppaStructure": "PayAsProduced",
"guaranteeOfOrigin": "None",
"negativePrices": "Included",
"hedgeSharePercent": 100,
"capacityTiers": [
{ "min": 500, "max": null }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0,
"basicFeePerYear": 2000
},
"priceMatrix": [
{
"start": "2026Q3",
"tenor": "2Q",
"prices": {
"2026Q3": { "priceEurPerMWh": 70.0 },
"2026Q4": { "priceEurPerMWh": 71.0 }
}
},
{
"start": "2027",
"tenor": "3Y",
"prices": {
"2027": { "priceEurPerMWh": 68.0 },
"2028": { "priceEurPerMWh": 69.0 },
"2029": { "priceEurPerMWh": 70.0 }
}
}
]
}
}
Result: Creates 1 offer with two contract options at different time resolutions:
- Contract 1: 2-quarter contract with quarterly pricing (Q3-Q4 2026)
- Contract 2: 3-year contract with yearly pricing (2027-2029)
5. Wind Downstream + PayAsProduced + Full Year Quarterly
All 4 quarters for a full year:
{
"offer": {
"name": "Wind PPA Full Year 2027",
"tariffType": 6,
"countryCode": "DE",
"description": "Downstream wind PPA covering all quarters of 2027",
"configuration": {
"technology": "Wind",
"ppaStructure": "PayAsProduced",
"guaranteeOfOrigin": "Customer",
"negativePrices": "Excluded",
"hedgeSharePercent": 85
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.4,
"basicFeePerYear": 1800
},
"priceMatrix": [
{
"start": "2027Q1",
"tenor": "4Q",
"prices": {
"2027Q1": { "priceEurPerMWh": 60.0 },
"2027Q2": { "priceEurPerMWh": 61.0 },
"2027Q3": { "priceEurPerMWh": 62.0 },
"2027Q4": { "priceEurPerMWh": 63.0 }
}
}
]
}
}
Result: Creates 1 offer with all 4 quarters of 2027.
6. Solar Upstream + No Hedge + Single Capacity Tier
100% hedged or 0% hedged scenarios:
{
"offer": {
"name": "Solar PPA Unhedged Large Scale",
"tariffType": 5,
"countryCode": "DE",
"description": "Large-scale solar with no hedging",
"configuration": {
"technology": "Solar",
"ppaStructure": "PayAsForecasted",
"guaranteeOfOrigin": "Provider",
"negativePrices": "Included",
"hedgeSharePercent": 0,
"capacityTiers": [
{ "min": 2000, "max": null }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.2,
"basicFeePerYear": 3000
},
"priceMatrix": [
{
"start": "2026",
"tenor": "3Y",
"prices": {
"2026": { "priceEurPerMWh": 58.0 },
"2027": { "priceEurPerMWh": 58.5 },
"2028": { "priceEurPerMWh": 59.0 }
}
}
]
}
}
Result: Creates 1 offer named "Solar PPA Unhedged Large Scale (>2000kW)" with 0% hedging.
7. Wind Upstream + Auto-Calculated Tenor
No tenor specified: System calculates tenor from the number of price periods.
{
"offer": {
"name": "Wind PPA Auto-Tenor",
"tariffType": 5,
"countryCode": "DE",
"description": "Contract with automatically calculated tenor",
"configuration": {
"technology": "Wind",
"ppaStructure": "PayAsProduced",
"guaranteeOfOrigin": "None",
"negativePrices": "Included"
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0,
"basicFeePerYear": 1500
},
"priceMatrix": [
{
"start": "2026Q2",
"prices": {
"2026Q2": { "priceEurPerMWh": 62.0 },
"2026Q3": { "priceEurPerMWh": 63.0 },
"2026Q4": { "priceEurPerMWh": 64.0 },
"2027Q1": { "priceEurPerMWh": 65.0 }
}
}
]
}
}
Result: Creates 1 offer. Tenor is calculated as "4Q" (4 quarterly price periods).
8. Batch Upload - Multiple Offers at Once
Upload multiple offers in one request:
{
"offers": [
{
"name": "Solar PPA Small Scale",
"tariffType": 5,
"countryCode": "DE",
"description": "Small solar installations",
"configuration": {
"technology": "Solar",
"ppaStructure": "PayAsForecasted",
"guaranteeOfOrigin": "Provider",
"negativePrices": "Included",
"hedgeSharePercent": 75,
"capacityTiers": [
{ "min": 0, "max": 200 }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.5,
"basicFeePerYear": 800
},
"priceMatrix": [
{
"start": "2026",
"tenor": "1Y",
"prices": {
"2026": { "priceEurPerMWh": 66.0 }
}
}
]
},
{
"name": "Wind PPA Large Scale",
"tariffType": 5,
"countryCode": "DE",
"description": "Large wind installations",
"configuration": {
"technology": "Wind",
"ppaStructure": "PayAsProduced",
"guaranteeOfOrigin": "Customer",
"negativePrices": "Excluded",
"hedgeSharePercent": 90,
"capacityTiers": [
{ "min": 5000, "max": null }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.3,
"basicFeePerYear": 5000
},
"priceMatrix": [
{
"start": "2027Q1",
"tenor": "8Q",
"prices": {
"2027Q1": { "priceEurPerMWh": 60.0 },
"2027Q2": { "priceEurPerMWh": 61.0 },
"2027Q3": { "priceEurPerMWh": 62.0 },
"2027Q4": { "priceEurPerMWh": 63.0 },
"2028Q1": { "priceEurPerMWh": 62.5 },
"2028Q2": { "priceEurPerMWh": 63.5 },
"2028Q3": { "priceEurPerMWh": 64.5 },
"2028Q4": { "priceEurPerMWh": 65.5 }
}
}
]
}
]
}
Result: Creates 2 separate offers. Both are validated and imported in one request.
9. Solar Downstream + Mixed Yearly/Quarterly/Monthly
All three time resolutions in one offer:
{
"offer": {
"name": "Solar PPA Multi-Resolution",
"tariffType": 6,
"countryCode": "DE",
"description": "Demonstrates yearly, quarterly, and monthly contracts",
"configuration": {
"technology": "Solar",
"ppaStructure": "PayAsForecasted",
"guaranteeOfOrigin": "Provider",
"negativePrices": "Included",
"hedgeSharePercent": 75,
"capacityTiers": [
{ "min": 500, "max": 1500 }
]
},
"fees": {
"guaranteeOfOriginFeeEurPerMWh": 0.5,
"basicFeePerYear": 1500
},
"priceMatrix": [
{
"start": "2026",
"tenor": "2Y",
"prices": {
"2026": { "priceEurPerMWh": 64.0 },
"2027": { "priceEurPerMWh": 65.0 }
}
},
{
"start": "2028Q1",
"tenor": "4Q",
"prices": {
"2028Q1": { "priceEurPerMWh": 66.0 },
"2028Q2": { "priceEurPerMWh": 67.0 },
"2028Q3": { "priceEurPerMWh": 68.0 },
"2028Q4": { "priceEurPerMWh": 69.0 }
}
},
{
"start": "2029M01",
"tenor": "6M",
"prices": {
"2029M01": { "priceEurPerMWh": 70.0 },
"2029M02": { "priceEurPerMWh": 70.5 },
"2029M03": { "priceEurPerMWh": 71.0 },
"2029M04": { "priceEurPerMWh": 71.5 },
"2029M05": { "priceEurPerMWh": 72.0 },
"2029M06": { "priceEurPerMWh": 72.5 }
}
}
]
}
}
Result: Creates 1 offer with three contract options at different time resolutions:
- Contract 1: 2-year contract with yearly pricing (2026-2027)
- Contract 2: 4-quarter contract with quarterly pricing (2028)
- Contract 3: 6-month contract with monthly pricing (Jan-Jun 2029)
10. Biomass Upstream + Minimal Fields
Minimum required fields only:
{
"offer": {
"name": "Biomass PPA Minimal",
"tariffType": 5,
"countryCode": "DE",
"configuration": {
"technology": "Biomass",
"ppaStructure": "PayAsProduced",
"guaranteeOfOrigin": "None",
"negativePrices": "Included"
},
"fees": {},
"priceMatrix": [
{
"start": "2027",
"prices": {
"2027": { "priceEurPerMWh": 72.0 }
}
}
]
}
}
Result: Creates 1 offer with minimal configuration. No hedge percentage, no fees, single year pricing.
How to Upload
Using cURL (Command Line)
curl -X POST "https://your-api-domain.com/tariff-management/ppa/upload" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "file=@your-ppa-offer.json"
Using PowerShell
$filePath = 'C:\path\to\your-ppa-offer.json'
$uri = 'https://your-api-domain.com/tariff-management/ppa/upload'
$headers = @{ Authorization = 'Bearer YOUR_TOKEN' }
$form = @{ file = Get-Item $filePath }
Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Form $form
Using Postman
- Method: POST
- URL:
https://your-api-domain.com/tariff-management/ppa/upload - Headers:
Authorization: Bearer YOUR_TOKEN
- Body:
- Select
form-data - Key:
file(change type toFile) - Value: Select your JSON file
- Select
- Send
Using JavaScript (Fetch API)
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('https://your-api-domain.com/tariff-management/ppa/upload', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN'
},
body: formData
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));
Response Format
Success Response
When using capacityTiers, multiple results are returned - one per tier:
{
"success": true,
"results": [
{
"offerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"success": true,
"message": "Imported successfully"
},
{
"offerId": "7bc12d89-8a23-4c71-9def-5e432a1b8c92",
"success": true,
"message": "Imported successfully"
},
{
"offerId": "9de45c01-2f34-4a87-8bcd-4d567e8f9a01",
"success": true,
"message": "Imported successfully"
}
]
}
Without Capacity Tiers
Single result when no tiers are specified:
{
"success": true,
"results": [
{
"offerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"success": true,
"message": "Imported successfully"
}
]
}
Batch Upload Response
Multiple results for batch uploads:
{
"success": true,
"results": [
{
"offerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"success": true,
"message": "Imported successfully"
},
{
"offerId": "7bc12d89-8a23-4c71-9def-5e432a1b8c92",
"success": true,
"message": "Imported successfully"
}
]
}
Error Response
If validation fails:
{
"success": false,
"results": [
{
"offerId": null,
"success": false,
"message": "Validation failed: TariffType must be 5 (Upstream) or 6 (Downstream) for PPA"
}
]
}
Validation Rules
Required Fields
✓ offer or offers must be present
✓ name, tariffType, countryCode required for each offer
✓ configuration with all required fields: technology, ppaStructure, guaranteeOfOrigin, negativePrices
✓ fees object (can be empty {})
✓ priceMatrix with at least one contract
✓ Each contract must have start and prices
✓ Each price entry must have priceEurPerMWh
Field Validation
✓ tariffType must be 5 (Upstream) or 6 (Downstream)
✓ countryCode must be valid ISO 3166-1 alpha-2 (2 letters)
✓ Enum values must match exactly (case-sensitive): "Solar", "Wind", "Biomass", "PayAsForecasted", "PayAsProduced", "None", "Provider", "Customer", "Included", "Excluded"
✓ Period keys in prices must match start format (yearly: "YYYY", quarterly: "YYYYQN", monthly: "YYYYMNN")
✓ hedgeSharePercent must be between 0 and 100 (if provided)
Capacity Tiers
✓ If provided, min must be less than max (when both are non-null)
✓ min and max must be non-negative
✓ Tiers can be omitted entirely (creates single offer without capacity restrictions)
Pricing
✓ priceEurPerMWh is required for each period entry
✓ Decimal values must be valid numbers
Contract Logic
✓ tenor is optional (auto-calculated from price periods if omitted)
✓ Multiple contracts can have overlapping or different time ranges
Common Mistakes
Wrong tariffType
"tariffType": 3 // WRONG - 3 is Direct Marketing, not PPA
Fix:
"tariffType": 5 // Correct for PPA Upstream (selling)
// OR
"tariffType": 6 // Correct for PPA Downstream (buying)
Invalid quarter format
"prices": {
"2026-Q2": { "priceEurPerMWh": 64.0 } // WRONG - has a dash
}
Fix:
"prices": {
"2026Q2": { "priceEurPerMWh": 64.0 } // Correct - no dash
}
Invalid hedge percentage
"hedgeSharePercent": 120 // WRONG - must be 0-100
Fix:
"hedgeSharePercent": 75 // Correct - between 0 and 100
Missing required price field
"prices": {
"2026Q2": { "guaranteeOfOriginFeeEurPerMWh": 0.5 } // WRONG - missing priceEurPerMWh
}
Fix:
"prices": {
"2026Q2": {
"priceEurPerMWh": 64.0, // Required
"guaranteeOfOriginFeeEurPerMWh": 0.5
}
}
Mismatched period keys
{
"start": "2026", // Yearly format
"prices": {
"2026Q1": { ... } // WRONG - Quarterly format doesn't match
}
}
Fix:
{
"start": "2026",
"prices": {
"2026": { ... }, // Match yearly format
"2027": { ... }
}
}
Using both offer and offers
{
"offer": { ... }, // WRONG - Can't use both
"offers": [ ... ]
}
Fix (choose one):
// For single offer:
{
"offer": { ... }
}
// For batch:
{
"offers": [ ... ]
}
Invalid month or quarter number
"start": "2026Q5" // WRONG - Quarter must be 1-4
"start": "2026M13" // WRONG - Month must be 01-12
Fix:
"start": "2026Q4" // Correct
"start": "2026M12" // Correct
Can I mix yearly, quarterly, and monthly contracts in the same offer?
Yes! You can have multiple contracts with different time resolutions in the same priceMatrix:
"priceMatrix": [
{
"start": "2026",
"tenor": "2Y",
"prices": {
"2026": { ... }, // Yearly
"2027": { ... } // Yearly
}
},
{
"start": "2028Q1",
"tenor": "4Q",
"prices": {
"2028Q1": { ... }, // Quarterly
"2028Q2": { ... }, // Quarterly
"2028Q3": { ... }, // Quarterly
"2028Q4": { ... } // Quarterly
}
},
{
"start": "2029M01",
"tenor": "6M",
"prices": {
"2029M01": { ... }, // Monthly
"2029M02": { ... }, // Monthly
"2029M03": { ... } // Monthly
// ...
}
}
]
This creates one offer with three contract options at different time granularities.
Troubleshooting
Issue: "TariffType must be 5 or 6"
Cause: You used a different tariff type number.
Fix: Set "tariffType": 5 (Upstream/selling) or "tariffType": 6 (Downstream/buying)
Issue: "Invalid enumeration value"
Cause: Misspelled enum value or used wrong case.
Fix: Use exact strings: "Solar", "Wind", "Biomass", "PayAsForecasted", "PayAsProduced", "None", "Provider", "Customer", "Included", "Excluded"
Issue: "HedgeSharePercent must be between 0 and 100"
Cause: Value outside valid range. Fix: Use a value between 0 and 100, or omit the field entirely.
Issue: "priceEurPerMWh is required"
Cause: Missing price for a period.
Fix: Add priceEurPerMWh for each price entry.
Issue: "Invalid JSON format"
Cause: Syntax error in JSON (missing comma, bracket, etc.). Fix: Validate JSON at jsonlint.com or use a JSON validator.
Issue: Multiple offers created unexpectedly
Cause: You provided capacityTiers in correct format.
Explanation: This is expected behavior. Each tier creates a separate offer.
Fix (if unwanted): Remove capacityTiers to create single offer without capacity restrictions.
Issue: "Tenor calculation failed"
Cause: Provided invalid or inconsistent price periods.
Fix: Ensure price period keys are sequential and match the start format. Or explicitly provide tenor.
Summary Checklist
Before uploading:
- JSON file is valid (use validator)
-
tariffTypeis5(Upstream) or6(Downstream) - All configuration fields use string values (not numbers)
-
capacityTiersinconfiguration(not elsewhere) - correct format - Each price entry has
priceEurPerMWh - Period keys match
startformat (yearly, quarterly, or monthly) -
hedgeSharePercentis between 0 and 100 (if provided) - File encoding is UTF-8
- Authentication token is ready
Last Updated: December 2025
Endpoint: /tariff-management/ppa/upload