PPA Upload API Documentation

Overview

The PPA (Power Purchase Agreement) Upload API allows you to upload energy purchase and sales agreements with detailed pricing structures. You can upload offers for both Upstream (selling energy) and Downstream (buying energy) contracts.

Endpoint: POST /tariff-management/ppa/upload


Understanding the Structure

Before uploading PPA offers, it's crucial to understand how contracts are organized:

┌─────────────────────────────────────────────────────────────┐
│ OFFER: "Solar PPA Upstream"                                 │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐ │
│  │ CONFIGURATION                                         │ │
│  │  - Technology: Solar                                  │ │
│  │  - PPA Structure: PayAsForecasted                     │ │
│  │  - Guarantee of Origin: Provider                      │ │
│  │  - Negative Prices: Included                          │ │
│  │  - Hedge Share: 75%                                   │ │
│  └───────────────────────────────────────────────────────┘ │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐ │
│  │ PRICE MATRIX (Array of Contracts)                    │ │
│  │                                                       │ │
│  │  Yearly Contracts (36 entries):                      │ │
│  │    Start 2026: 1Y, 2Y, 3Y, 4Y, 5Y, 6Y  ─────┐        │ │
│  │    Start 2027: 1Y, 2Y, 3Y, 4Y, 5Y, 6Y  ─────┤        │ │
│  │    Start 2028: 1Y, 2Y, 3Y, 4Y, 5Y, 6Y  ─────┤        │ │
│  │    ... (2029, 2030, 2031)               ─────┤        │ │
│  │                                              │        │ │
│  │  Quarterly Contracts (32 entries):           │        │ │
│  │    Start 2026Q1: 1Q, 2Q, 3Q, 4Q  ───────────┤        │ │
│  │    Start 2026Q2: 1Q, 2Q, 3Q, 4Q  ───────────┤        │ │
│  │    ... (2026Q3, Q4, 2027Q1-Q4)   ───────────┘        │ │
│  │                                                       │ │
│  │  ⚠️  All different tenors (quarterly AND yearly)     │ │
│  │     must be in THIS array - 68+ entries total        │ │
│  └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Key Concepts

IMPORTANT: All contract tenors and start dates for a PPA configuration must be within the same offer's priceMatrix array. This means you can have 1 entry or 100+ entries in a single priceMatrix, mixing quarterly contracts (1Q-4Q) and yearly contracts (1Y-12Y).

What this means:


Quick Start

  1. Create a JSON file with your PPA offer data
  2. Choose tariff type: 5 for Upstream (selling) or 6 for Downstream (buying)
  3. Upload the file using the API endpoint
  4. Receive confirmation with offer IDs

What is a PPA Offer?

A PPA (Power Purchase Agreement) offer defines:

Critical Concept: A PPA offer defines a pricing configuration, and all possible contract start dates and durations for that configuration must be included in a single priceMatrix array. This array can contain 1 entry or 100+ entries, mixing quarterly contracts (1Q-4Q) and yearly contracts (1Y-12Y).


JSON File Structure

Basic Structure

{
  "offers": [
    {
      // Offer details
    }
  ]
}

Field Reference

Offer Object

Field Type Required Description
name string Yes Descriptive name for the PPA offer
tariffType integer Yes 5 for Upstream (selling), 6 for Downstream (buying)
countryCode string Yes ISO country code (e.g., "DE")
description string No Optional description
configuration object Yes Technical configuration
fees object Yes Fee structure
priceMatrix array Yes Contract periods with pricing

Configuration Object

Field Type Required Options 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" Treatment of negative price hours
hedgeSharePercent decimal No 0-100 Percentage of production hedged (optional)

Configuration Examples:

Pay As Forecasted - Payment based on forecasted production:

"configuration": {
  "technology": "Solar",
  "ppaStructure": "PayAsForecasted",
  "guaranteeOfOrigin": "Provider",
  "negativePrices": "Included",
  "hedgeSharePercent": 75
}

Pay As Produced - Payment based on actual production:

"configuration": {
  "technology": "Wind",
  "ppaStructure": "PayAsProduced",
  "guaranteeOfOrigin": "Customer",
  "negativePrices": "Excluded",
  "hedgeSharePercent": 80
}

Fees Object

Field Type Required Description
guaranteeOfOriginFeeEurPerMWh decimal No Default GOO fee per MWh (can be overridden per period)
basicFeePerYear decimal No Annual basic fee in EUR

Price Matrix Structure

IMPORTANT: All tenors for a PPA configuration must be defined in the same offer's priceMatrix array, even if they have different runtimes (Quarter, Year). You can have 1Q, 4Q, 1Y, and 12Y all in the same priceMatrix array.

The priceMatrix is an array of contract objects:

"priceMatrix": [
  {
    "start": "2026Q2",         // Start period
    "tenor": "3Q",             // Contract duration
    "prices": {
      "2026Q2": { "priceEurPerMWh": 64.0 },
      "2026Q3": { "priceEurPerMWh": 65.0 },
      "2026Q4": { "priceEurPerMWh": 66.0 }
    }
  }
]

Contract Object

Field Type Required Description
start string Yes Start period (quarterly: "2026Q2", yearly: "2027")
tenor string Yes Contract duration (e.g., "1Q" for 1 quarter, "4Q" for 4 quarters, "1Y" for 1 year, "6Y" for 6 years)
prices object Yes Period-based pricing dictionary

Understanding Start Periods and Tenors

Quarterly Start Periods: Format YYYYQN where N is 1-4

Yearly Start Periods: Format YYYY

Quarterly Tenors: Format NQ where N is duration in quarters

Yearly Tenors: Format NY where N is duration in years

Price Key Format Requirements

CRITICAL: Price keys in the prices object must match the tenor format:

Tenor Format Required Price Key Format Example
Quarterly (1Q, 4Q) Quarterly ("YYYYQN") "2026Q1", "2026Q2", "2026Q3"
Yearly (1Y, 3Y) Yearly ("YYYY") "2026", "2027", "2028"

Examples:

Price Entry Fields

Field Type Required Description
priceEurPerMWh decimal Yes PPA price in EUR per MWh for this period
guaranteeOfOriginFeeEurPerMWh decimal No Override default GOO fee for this period

Complete Examples

Example 1: Simplified Example - Basic Concept

This simplified example shows 4 different contracts under ONE configuration, demonstrating how quarterly and yearly tenors mix in a single priceMatrix:

{
  "offers": [
    {
      "name": "Solar PPA - Basic Example",
      "tariffType": 5,
      "countryCode": "DE",
      "configuration": {
        "technology": "Solar",
        "ppaStructure": "PayAsForecasted",
        "guaranteeOfOrigin": "Provider",
        "negativePrices": "Included",
        "hedgeSharePercent": 75
      },
      "fees": {
        "guaranteeOfOriginFeeEurPerMWh": 0.5,
        "basicFeePerYear": 1200
      },
      "priceMatrix": [
        {
          "start": "2026Q1",
          "tenor": "1Q",
          "prices": {
            "2026Q1": {
              "priceEurPerMWh": 64.0,
              "guaranteeOfOriginFeeEurPerMWh": 0.5
            }
          }
        },
        {
          "start": "2026Q1",
          "tenor": "4Q",
          "prices": {
            "2026Q1": { "priceEurPerMWh": 64.0, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q2": { "priceEurPerMWh": 65.0, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q3": { "priceEurPerMWh": 66.0, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q4": { "priceEurPerMWh": 67.0, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026",
          "tenor": "1Y",
          "prices": {
            "2026": {
              "priceEurPerMWh": 65.5,
              "guaranteeOfOriginFeeEurPerMWh": 0.5
            }
          }
        },
        {
          "start": "2026",
          "tenor": "3Y",
          "prices": {
            "2026": { "priceEurPerMWh": 65.5, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2027": { "priceEurPerMWh": 66.0, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2028": { "priceEurPerMWh": 66.5, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        }
      ]
    }
  ]
}

What this shows:


Example 2: Real-World Upstream Example (Solar)

This example is based on a real production upload showing 68+ priceMatrix entries in a single offer. We show a representative subset to illustrate the pattern:

{
  "offers": [
    {
      "name": "Solar PPA Upstream - Comprehensive Pricing",
      "tariffType": 5,
      "countryCode": "DE",
      "description": "Solar PPA with extensive quarterly and yearly options",
      "configuration": {
        "technology": "Solar",
        "ppaStructure": "PayAsForecasted",
        "guaranteeOfOrigin": "Provider",
        "negativePrices": "Included",
        "hedgeSharePercent": 75
      },
      "fees": {
        "guaranteeOfOriginFeeEurPerMWh": 0.5,
        "basicFeePerYear": 1200
      },
      "priceMatrix": [
        // Quarterly Contracts - 8 starts × 4 tenors = 32 entries
        // 2026Q1 start with 4 tenor options
        {
          "start": "2026Q1",
          "tenor": "1Q",
          "prices": {
            "2026Q1": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026Q1",
          "tenor": "2Q",
          "prices": {
            "2026Q1": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q2": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026Q1",
          "tenor": "3Q",
          "prices": {
            "2026Q1": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q2": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q3": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026Q1",
          "tenor": "4Q",
          "prices": {
            "2026Q1": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q2": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q3": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2026Q4": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        // ... (2026Q2, 2026Q3, 2026Q4, 2027Q1, 2027Q2, 2027Q3, 2027Q4 - same pattern, 28 more entries)

        // Yearly Contracts - 6 starts × 6 tenors = 36 entries
        // 2026 start with 6 tenor options
        {
          "start": "2026",
          "tenor": "1Y",
          "prices": {
            "2026": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026",
          "tenor": "2Y",
          "prices": {
            "2026": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2027": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026",
          "tenor": "3Y",
          "prices": {
            "2026": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2027": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2028": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026",
          "tenor": "4Y",
          "prices": {
            "2026": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2027": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2028": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2029": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026",
          "tenor": "5Y",
          "prices": {
            "2026": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2027": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2028": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2029": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2030": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        },
        {
          "start": "2026",
          "tenor": "6Y",
          "prices": {
            "2026": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2027": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2028": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2029": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2030": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 },
            "2031": { "priceEurPerMWh": 64.33, "guaranteeOfOriginFeeEurPerMWh": 0.5 }
          }
        }
        // ... (2027, 2028, 2029, 2030, 2031 - same pattern, 30 more entries)
        // Total: 68+ priceMatrix entries in ONE offer
      ]
    }
  ]
}

Real-World Pattern Explained:


Example 3: Real-World Downstream Example (Biomass)

This example shows a Downstream (buying) PPA with Biomass technology. The structure is identical to Upstream, only the tariffType differs:

{
  "offers": [
    {
      "name": "Biomass PPA Downstream - Comprehensive Pricing",
      "tariffType": 6,
      "countryCode": "DE",
      "description": "Biomass PPA for energy purchase with flexible terms",
      "configuration": {
        "technology": "Biomass",
        "ppaStructure": "PayAsProduced",
        "guaranteeOfOrigin": "Customer",
        "negativePrices": "Excluded",
        "hedgeSharePercent": 80
      },
      "fees": {
        "guaranteeOfOriginFeeEurPerMWh": 0.3,
        "basicFeePerYear": 1500
      },
      "priceMatrix": [
        // Same pattern as Upstream example
        // Quarterly contracts: 32 entries
        {
          "start": "2026Q1",
          "tenor": "1Q",
          "prices": {
            "2026Q1": { "priceEurPerMWh": 70.0, "guaranteeOfOriginFeeEurPerMWh": 0.3 }
          }
        },
        // ... (more quarterly entries)

        // Yearly contracts: 36 entries
        {
          "start": "2026",
          "tenor": "1Y",
          "prices": {
            "2026": { "priceEurPerMWh": 70.0, "guaranteeOfOriginFeeEurPerMWh": 0.3 }
          }
        }
        // ... (more yearly entries)
        // Total: 68+ entries
      ]
    }
  ]
}

Key Differences from Upstream:


Example 4: Batch Upload (Multiple Offers)

You can upload multiple PPA offers (Upstream and Downstream) in one file:

{
  "offers": [
    {
      "name": "Solar PPA Upstream",
      "tariffType": 5,
      "countryCode": "DE",
      "configuration": {
        "technology": "Solar",
        "ppaStructure": "PayAsForecasted",
        "guaranteeOfOrigin": "Provider",
        "negativePrices": "Included",
        "hedgeSharePercent": 75
      },
      "fees": {
        "guaranteeOfOriginFeeEurPerMWh": 0.5,
        "basicFeePerYear": 1200
      },
      "priceMatrix": [
        // ... priceMatrix entries
      ]
    },
    {
      "name": "Wind PPA Downstream",
      "tariffType": 6,
      "countryCode": "DE",
      "configuration": {
        "technology": "Wind",
        "ppaStructure": "PayAsProduced",
        "guaranteeOfOrigin": "Customer",
        "negativePrices": "Excluded",
        "hedgeSharePercent": 80
      },
      "fees": {
        "guaranteeOfOriginFeeEurPerMWh": 0.3,
        "basicFeePerYear": 1500
      },
      "priceMatrix": [
        // ... priceMatrix entries
      ]
    }
  ]
}

Common Patterns

Here are typical patterns for structuring your PPA priceMatrix:

Pattern 1: Comprehensive Quarterly Coverage

Scenario: Offer customers flexibility to start contracts in any quarter with various duration options.

Structure:

Example:

2026Q1 start → 1Q, 2Q, 3Q, 4Q tenors (4 contracts)
2026Q2 start → 1Q, 2Q, 3Q, 4Q tenors (4 contracts)
2026Q3 start → 1Q, 2Q, 3Q, 4Q tenors (4 contracts)
2026Q4 start → 1Q, 2Q, 3Q, 4Q tenors (4 contracts)
2027Q1 start → 1Q, 2Q, 3Q, 4Q tenors (4 contracts)
... (continues for all quarters)
= 32 total priceMatrix entries in ONE offer

Pattern 2: Long-term Yearly Contracts

Scenario: Multi-year contracts with different start dates, offering flexibility in contract length.

Structure:

Example:

2026 start → 1Y, 2Y, 3Y, 4Y, 5Y, 6Y tenors (6 contracts)
2027 start → 1Y, 2Y, 3Y, 4Y, 5Y, 6Y tenors (6 contracts)
2028 start → 1Y, 2Y, 3Y, 4Y, 5Y, 6Y tenors (6 contracts)
... (continues through 2031)
= 36 total priceMatrix entries in ONE offer

Pattern 3: Mixed Quarterly and Yearly (Maximum Flexibility)

Scenario: Combine short-term quarterly options with long-term yearly options for maximum customer choice.

Structure:

Example:

Quarterly Coverage:
  2026Q1 → 1Q, 2Q, 3Q, 4Q
  2026Q2 → 1Q, 2Q, 3Q, 4Q
  ... (through 2027Q4)

Yearly Coverage:
  2026 → 1Y, 2Y, 3Y, 4Y, 5Y, 6Y
  2027 → 1Y, 2Y, 3Y, 4Y, 5Y, 6Y
  ... (through 2031)

= 68 total priceMatrix entries in ONE offer

Note: This is the pattern used in real production uploads, giving customers the most comprehensive set of contract options.


Pattern 4: Simple Fixed-Term Contract

Scenario: Single contract with fixed start and duration (simplest case).

Structure:

Example:

"priceMatrix": [
  {
    "start": "2026Q1",
    "tenor": "4Q",
    "prices": {
      "2026Q1": { "priceEurPerMWh": 64.0 },
      "2026Q2": { "priceEurPerMWh": 65.0 },
      "2026Q3": { "priceEurPerMWh": 66.0 },
      "2026Q4": { "priceEurPerMWh": 67.0 }
    }
  }
]

How to Upload

Using cURL

curl -X POST \
  https://api.trace.com/tariff-management/ppa/upload \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@ppa_offers.json"

Using Postman

  1. Set request type to POST
  2. Enter URL: https://api.trace.com/tariff-management/ppa/upload
  3. Go to Headers tab, add: Authorization: Bearer YOUR_TOKEN
  4. Go to Body tab, select form-data
  5. Add key named file, change type to File
  6. Select your JSON file
  7. Click Send

Using PowerShell

$filePath = 'C:\path\to\ppa_offers.json'
$headers = @{ Authorization = 'Bearer YOUR_TOKEN' }
$form = @{ file = Get-Item $filePath }

Invoke-RestMethod -Uri 'https://api.trace.com/tariff-management/ppa/upload' `
  -Method Post `
  -Headers $headers `
  -Form $form

Response Format

Success Response

{
  "results": [
    {
      "offerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "success": true,
      "message": "✓ PPA Offer 'Solar PPA Q2-Q4 2026' imported successfully with 3 price periods"
    }
  ]
}

Error Response

{
  "results": [
    {
      "offerId": null,
      "success": false,
      "message": "PPA Import validation failed:\nOffer 1 (Solar PPA): Hedge share percent must be between 0 and 100"
    }
  ]
}

Validation Rules

  1. Required Fields:

    • All required fields must be present
    • offers array must contain at least one offer
    • Each price period must have priceEurPerMWh
  2. Value Constraints:

    • tariffType must be 5 (Upstream) or 6 (Downstream)
    • hedgeSharePercent must be between 0 and 100
    • Quarterly periods: format YYYYQN (N = 1-4)
    • Yearly periods: format YYYY
  3. Data Validation:

    • All offers validated before import
    • If any offer fails validation, entire upload is rejected
    • Duplicate offers create new versions (history preserved)
  4. Unique Tenor Combinations:

    • You cannot upload the same start + tenor combination twice within the same offer
    • Each priceMatrix entry must be unique
    • ✅ Valid: {"start": "2026Q1", "tenor": "1Q"} and {"start": "2026Q2", "tenor": "1Q"}
    • ✅ Valid: {"start": "2026Q1", "tenor": "1Q"} and {"start": "2026Q1", "tenor": "4Q"}
    • ❌ Invalid: Two entries with {"start": "2026Q1", "tenor": "1Q"}
  5. Configuration Grouping:

    • All tenors for a PPA configuration must be within the same offer's priceMatrix array
    • You cannot split tenors across multiple offers with the same configuration
    • ✅ Valid: One offer with 68+ priceMatrix entries covering all start dates and tenors
    • ❌ Invalid: Multiple offers with same configuration, each with subset of tenors
  6. Price Key Format Consistency:

    • Quarterly tenors (e.g., "1Q", "4Q") MUST use quarterly price keys ("2026Q1", "2026Q2")
    • Yearly tenors (e.g., "1Y", "6Y") MUST use yearly price keys ("2026", "2027")
    • Each price period in the prices object must match the tenor format
    • ✅ Valid: Tenor "4Q" with price keys "2026Q1", "2026Q2", "2026Q3", "2026Q4"
    • ❌ Invalid: Tenor "1Y" with price keys "2026Q1", "2026Q2", "2026Q3", "2026Q4"
  7. Tenor Duration Coverage:

    • The number of price entries must match the tenor duration
    • 1Q tenor → 1 price entry
    • 4Q tenor → 4 price entries
    • 1Y tenor → 1 price entry
    • 3Y tenor → 3 price entries
    • ✅ Valid: Tenor "3Y" starting "2026" with price keys "2026", "2027", "2028" (3 entries)
    • ❌ Invalid: Tenor "3Y" starting "2026" with only price keys "2026", "2027" (2 entries - missing 2028)

Frequently Asked Questions (FAQ)

Q: Can I mix quarterly 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. A single offer can contain both quarterly contracts (1Q-4Q) and yearly contracts (1Y-12Y). This is demonstrated in the real-world examples with 68+ entries combining quarterly and yearly contracts.


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 68+ entries in one offer mixing quarterly and yearly contracts. You could theoretically have even more if your business requires it.


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": "2026Q1", "tenor": "1Q"}.


Q: Can I use quarterly prices for a yearly tenor?

A: No. Price key format must match the tenor format:

Mixing formats will result in a validation error.


Q: What's the difference between Upstream and Downstream PPAs?

A:

The JSON structure is identical; only the tariffType value differs.


Q: Can I combine Upstream and Downstream in one upload?

A: Yes, you can include multiple offers in the "offers" array, some with tariffType: 5 (Upstream) and others with tariffType: 6 (Downstream). See Example 4 for batch upload.


Q: How long can a PPA contract be?

A:

The actual limit depends on your business requirements. The API supports extended durations for long-term PPA agreements.


Common Issues

❌ Wrong quarter format

"2026-Q2": { ... }  // Wrong - has a dash

Fix: Remove the dash → "2026Q2": { ... }

❌ Invalid hedge percentage

"hedgeSharePercent": 120  // Wrong - must be 0-100

Fix: Use value between 0-100 → "hedgeSharePercent": 75

❌ Missing required price

"2026Q2": {
  "guaranteeOfOriginFeeEurPerMWh": 0.5
  // Missing priceEurPerMWh!
}

Fix: Add the price → "priceEurPerMWh": 64.0

❌ Wrong tariff type for PPA

"tariffType": 3  // Wrong - must be 5 or 6

Fix: Use 5 (Upstream) or 6 (Downstream)


Quick Reference: Allowed Values

tariffType

technology

ppaStructure

guaranteeOfOrigin

negativePrices


Upstream vs. Downstream Guide

When to use Upstream (tariffType: 5)

When to use Downstream (tariffType: 6)


Need Help?