Skip to content

Guide: Creating a Promoter-based Community

This guide walks through the full API call sequence to create a community based on the Promoter-Anchor business model, where a Promoter owns a generation asset (PV) installed behind an Anchor member's CPE and sells energy to the community.

Payloads may change

Specific endpoint payloads may change as DSO data expectations are clarified. Read the earlier concept pages before continuing, and consult the API Reference for authoritative field definitions.

Scenario Overview

We will create:

  • 1 Community — Dynamic allocation with Tree Dynamic Allocation (TREE_DNAC) market pricing
  • 4 Members — Anchor (Host), Promoter, Consumer 1, Consumer 2
  • 3 CPEs — one for the Anchor (prosumer/IAC), two for consumers (IC)
  • 2 Internal Meters — both behind the Anchor CPE: one for house consumption, one for PV generation
  • 3 Contracts — one per CPE
  • 4 Resources/Assets — Anchor (IC), Promoter PV (SCPU), Consumer 1 (IC), Consumer 2 (IC)
graph TD
    subgraph CPE_C1["CPE Consumer1 — PT000...1AA (IC)"]
        RC1["Consumer1 Resource (IC)"]
    end
    subgraph CPE_A["CPE Anchor HOST — PT000...1BB (IAC)"]
        subgraph INT_A["Anchor Internal Meter"]
            RA["Anchor Resource (IC)"]
        end
        subgraph INT_P["Promoter PV Internal Meter"]
            RP["Promoter PV Resource (SCPU)"]
        end
    end
    subgraph CPE_C2["CPE Consumer2 — PT000...1CC (IC)"]
        RC2["Consumer2 Resource (IC)"]
    end
    RP -->|"Sells at 70 €/MWh"| INT_A
    RP -->|"Sells at 80 €/MWh"| CPE_C1
    RP -->|"Sells at 80 €/MWh"| CPE_C2

Every API call returns the created object alongside its UUID, which you will need for subsequent calls.


Step 1 — Create the Community

POST /core/api/communities

This uses DYNAMIC allocation coefficients and TREE_DNAC — a decision-tree algorithm for computing dynamic allocation coefficients per interval.

Simpler alternative

For a proof-of-concept integration you may set method_alloc_coeff to PROPORTIONAL, which requires no dynamic coefficient submission to the DSO.

{
  "name": "communityname",
  "community_identifier": "111ACC",
  "type": "PROD",
  "method_alloc_coeff": "DYNAMIC",
  "market_rate": "TREE_DNAC"
}

Step 1 (alternative) — Create Full Community in One Call

POST /core/api/communities

See the dedicated guide: Creating a Community in One Call

The preload approach creates the entire community structure (members, meters, contracts, resources, and bilateral prices) in a single API call using *_ref forward references, instead of the multi-step sequence above.


Step 2 — Create the Anchor/Host Member

POST /core/api/communities/{community_id}/users

Terminology: Anchor = Host

Anchor and Host are used interchangeably throughout this documentation and the API. Both refer to the same member role: the priority member who typically hosts the generation asset behind their CPE.

Set is_host to true. This designates the member as an Anchor (also called Host) — a member with priority in the business model who typically hosts the generation asset behind their CPE.

{
  "name": "Anchor Client XXX",
  "role": "MEMBER",
  "status": "ACTIVE",
  "is_host": true,
  "is_promoter": false
}

Save the returned UUID as anchor_user_id.


Step 3 — Create the Promoter

POST /core/api/communities/{community_id}/users

Set is_promoter to true. The Promoter is the entity that owns the generation asset (e.g. the PV panels) and sells that energy to community members.

{
  "name": "Promoter",
  "role": "MEMBER",
  "status": "ACTIVE",
  "is_host": false,
  "is_promoter": true
}

Save the returned UUID as promoter_user_id.


Step 4 — Create Consumer Members (×2)

POST /core/api/communities/{community_id}/users

Terminology: Consumer = OffTaker = NonHost

Consumer, OffTaker, and NonHost all refer to the same member type: a member that consumes energy from the community without owning production assets.

For each consumer, set both is_host and is_promoter to false.

{
  "name": "Consumer1",
  "role": "MEMBER",
  "status": "ACTIVE",
  "is_host": false,
  "is_promoter": false
}

Repeat for Consumer 2. Save the returned UUIDs as consumer1_user_id and consumer2_user_id.


Step 5 — Create the Anchor CPE

POST /core/api/communities/{community_id}/meters

The Anchor CPE is a Prosumer installation (IAC) because the Promoter's PV sits behind it. This requires both identifier (consumption point) and production_identifier (injection point), as Prosumers are metered separately for consumption and generation by the DSO.

{
  "identifier": "PT002XXXXXXX",
  "production_identifier": "PT002XXXXXXX",
  "type": "CPE",
  "installation_type": "IAC",
  "status": "ACTIVE"
}

Save the returned UUID as anchor_cpe_id.


Step 6 — Create the Anchor Internal Meter

POST /core/api/communities/{community_id}/meters

This internal meter measures the Anchor member's house consumption behind the CPE. The identifier can be any common name or internal ID.

cpe_id vs identifier

The cpe_id must be the UUID returned in Step 5 — the internal database ID of the CPE meter — not the CPE's identifier string.

{
  "identifier": "HouseMeter1",
  "type": "INTERNAL",
  "status": "ACTIVE",
  "cpe_id": "<anchor_cpe_id>"
}

Save the returned UUID as anchor_internal_meter_id.


Step 7 — Create the Promoter PV Internal Meter

POST /core/api/communities/{community_id}/meters

This internal meter measures the PV generation from the Promoter's solar panels, also located behind the Anchor CPE. Use the same cpe_id as Step 6.

{
  "identifier": "PVMeter",
  "type": "INTERNAL",
  "status": "ACTIVE",
  "cpe_id": "<anchor_cpe_id>"
}

Save the returned UUID as promoter_pv_meter_id.


Step 8 — Create Consumer CPEs (×2)

POST /core/api/communities/{community_id}/meters

Consumer CPEs use installation_type: IC (Consumption Installation) since they have no local generation.

{
  "identifier": "PT002XXXXXXX",
  "type": "CPE",
  "installation_type": "IC",
  "status": "ACTIVE"
}

Repeat for Consumer 2. Save the returned UUIDs as consumer1_cpe_id and consumer2_cpe_id.


Step 9 — Create Contracts (×3, one per CPE)

POST /core/api/communities/{community_id}/meters/{meter_id}/contracts

Create one contract per CPE. The user_id is the member responsible for the CPE (Anchor for the Anchor CPE, each Consumer for their own). The meter_id in the path is the CPE UUID.

This scenario uses FIXED buy/sell types. Define peak, mid_peak, off_peak, and super_off_peak values per your retailer contracts. Multipliers can be left at 1 or adjusted:

Buy Price  = Period_Price + (MultiplierPMD × Network_Access_Tariff)
           + (MultiplierERSE × Peak_Hour_Power_Tariff × 4 × Days_In_Month / N_Peak_Periods)
Sell Price = Period_Price_Sell + (MultiplierPMD × Network_Access_Tariff)
{
  "buy_type": "FIXED",
  "sell_type": "FIXED",
  "voltage_level": "BTN simples",
  "tariff_cycle": "TETRA_SEMANAL",
  "with_holidays": true,
  "contracted_power": 6.9,
  "validity": "2026-01-01",
  "user_id": "<anchor_user_id>",
  "meter_id": "<anchor_cpe_id>",
  "buy_payload": {
    "buy_or_sell_type": "CONTRACT_BUY_VALUES",
    "peak_value": 0,
    "mid_peak_value": 0,
    "off_peak_value": 0,
    "super_off_peak_value": 0,
    "multiplierPMD": 1,
    "multiplierERSE": 1,
    "contract_id": "<contract_uuid>"
  },
  "sell_payload": {
    "buy_or_sell_type": "CONTRACT_SELL_VALUES",
    "peak_value": 0,
    "mid_peak_value": 0,
    "off_peak_value": 0,
    "super_off_peak_value": 0,
    "multiplierPMD": 1,
    "multiplierERSE": 1,
    "contract_id": "<contract_uuid>"
  }
}

Repeat for Consumer 1 and Consumer 2 CPEs, substituting the respective user_id and meter_id.


Step 10 — Create the Anchor Resource

POST /core/api/communities/{community_id}/resources

The Anchor resource represents the house consumption. Use type IC. The meter_id is the Anchor Internal Meter UUID from Step 6 — always the meter directly above the resource in the structure tree.

ownerships_payload assigns ownership shares. Multiple members can own fractional percentages.

{
  "name": "RESOURCE AAA",
  "type": "IC",
  "status": "ACTIVE",
  "meter_id": "<anchor_internal_meter_id>",
  "ownerships_payload": [
    {
      "user_id": "<anchor_user_id>",
      "perc_ownership": 100
    }
  ],
  "ic_payload": {
    "description": "Anchor house",
    "sum_certified_power": 0,
    "ic_voltage_level": "BTN simples"
  }
}

Step 11 — Create the Promoter PV Resource

POST /core/api/communities/{community_id}/resources

The Promoter's PV resource uses type SCPU (Self-Consumption Production Unit). The meter_id is the Promoter PV Internal Meter UUID from Step 7.

{
  "name": "RESOURCE PV",
  "type": "SCPU",
  "status": "ACTIVE",
  "meter_id": "<promoter_pv_meter_id>",
  "ownerships_payload": [
    {
      "user_id": "<promoter_user_id>",
      "perc_ownership": 100
    }
  ],
  "scpu_payload": {
    "generation_capacity": 0
  }
}

Step 12 — Create Consumer Resources (×2)

POST /core/api/communities/{community_id}/resources

Each consumer resource uses type IC. The meter_id is the respective Consumer CPE UUID (the consumer CPE is directly above the resource in the tree — no internal meter is needed).

{
  "name": "RESOURCE AAA",
  "type": "IC",
  "status": "ACTIVE",
  "meter_id": "<consumer1_cpe_id>",
  "ownerships_payload": [
    {
      "user_id": "<consumer1_user_id>",
      "perc_ownership": 100
    }
  ],
  "ic_payload": {
    "description": "Consumer house",
    "sum_certified_power": 0,
    "ic_voltage_level": "BTN simples"
  }
}

Repeat for Consumer 2, substituting consumer2_cpe_id and consumer2_user_id.


Step 13 — Upload DSO Measurements for each CPE

POST /core/api/communities/{community_id}/dso

Upload one record per 15-minute interval per CPE. The meter_id here refers to CPEs only, not internal meters. Repeat for all three CPEs.

Field DSO Code Description
energy_surplus 413 Surplus energy allocated to this meter (kWh)
imputed_energy 415 Share of total injected energy allocated to this meter (kWh)
grid_sc 418 Self-consumed energy from the public grid (kWh)
consumption 423 Energy consumed from the public grid (kWh)
grid_injection 424 Energy injected into the public grid (kWh)
{
  "datetime_timestamp": "2026-03-19T16:47:41.201Z",
  "energy_surplus": 0,
  "imputed_energy": 0,
  "grid_sc": 0,
  "grid_injection": 0,
  "consumption": 0,
  "meter_id": "<cpe_uuid>"
}

Aggregator CPEs

Aggregator-type CPEs are not covered in this scenario. Contact INESC TEC if your integration requires them.


Step 14 — Upload Internal Meter Measurements

POST /core/api/communities/{community_id}/loads

Upload 15-minute measurements for each Internal Meter (Anchor Internal Meter and Promoter PV Internal Meter). These are measurements not observed by the DSO, installed behind the CPE.

{
  "datetime_timestamp": "2026-03-19T16:47:41.201Z",
  "generation": 0,
  "consumption": 0,
  "meter_id": "<internal_meter_uuid>"
}

Repeat for both internal meters.


Step 15 — Upload Bilateral Prices

POST /core/api/communities/{community_id}/bilateral-prices

Upload the price for each provider → receiver pair for every 15-minute interval. In this scenario the Promoter sells at different prices depending on the buyer:

  • Promoter → Anchor: 70 €/MWh (behind the same CPE — INTRA_CPE transaction)
  • Promoter → Consumer 1: 80 €/MWh
  • Promoter → Consumer 2: 80 €/MWh

Prices may change dynamically per interval in other scenarios.

All possible pairs

If you cannot guarantee that every member strictly produces or strictly consumes in every interval, you may need to provide prices for all possible provider–receiver combinations.

[
  {
    "datetime_timestamp": "2026-04-10T09:03:50.986Z",
    "receiver_user_id": "<anchor_user_id>",
    "provider_user_id": "<promoter_user_id>",
    "price": 70
  },
  {
    "datetime_timestamp": "2026-04-10T09:03:50.986Z",
    "receiver_user_id": "<consumer1_user_id>",
    "provider_user_id": "<promoter_user_id>",
    "price": 80
  },
  {
    "datetime_timestamp": "2026-04-10T09:03:50.986Z",
    "receiver_user_id": "<consumer2_user_id>",
    "provider_user_id": "<promoter_user_id>",
    "price": 80
  }
]

Step 16 — Run Operations and Check Status

POST /core/api/communities/{community_id}/operations/run

GET /core/api/communities/{community_id}/tasks/{task_id}

Each operation call returns a task_id you can poll to check its status.

Phase 1 — Market Clearing

{ "task_name": "clear_market" }

clear_market generates transactions and, for DYNAMIC communities, the bilateral energy allocation coefficients (dynamic ACs) to be submitted to the DSO.

Phase 2 — Settlement

Once market clearing is complete:

{ "task_name": "run_settlement" }

run_settlement generates billing information and financial settlement results.

Dynamic coefficient flow (DYNAMIC communities)

After clear_market, the integrator fetches the dynamic ACs (Step 17) and submits them to the DSO for validation. The DSO either approves (returns final dynamic allocation) or rejects (falls back to proportional allocation). Final settlement must be run with the DSO-approved allocation.


Step 17 — Get Bilateral Energy Allocations

GET /core/api/communities/{community_id}/bilateral_energy_allocations/data

Returns the dynamic allocation coefficients generated by clear_market, to be submitted to the DSO. Only pairs where the coefficient is non-zero are returned, in 15-minute intervals.

Query parameters: start_date (YYYY-MM-DD), end_date (YYYY-MM-DD)

[
  {
    "datetime_timestamp": "2026-04-23T09:54:51.770Z",
    "receiver_identifier": "PT002...",
    "provider_identifier": "PT002...",
    "coefficient_value": 0
  }
]

An optional /export endpoint is available to download a DSO-compliant ZIP file with CSVs.


Step 18 — Get Transactions

GET /core/api/communities/{community_id}/sessions/transactions

Returns all transactions in the date range. Transactions are made between Member-Resource pairs. If a transaction is behind-the-meter (INTRA_CPE), provider_meter_id and receiver_meter_id will be the same.

Query parameters: start_date (YYYY-MM-DD), end_date (YYYY-MM-DD)


Step 19 — Get Settlement Outputs

POST /core/api/communities/{community_id}/sessions/settlement/outputs/query

A POST is used here because the query accepts a JSON body for specifying outputs, fields, and filters. You can filter by date range, member, resource, or meter, and select which output categories to return.

{
  "start_date": "2026-03-01",
  "end_date": "2026-03-31",
  "outputs": ["cpes", "cpes_bilateral", "members", "rec"],
  "fields": {
    "cpes": ["e_lem", "e_pur", "e_alc", "rev_total"],
    "cpes_bilateral": "ALL",
    "members": ["e_sup", "e_pur", "rev_total", "rev_total_no_csc"],
    "rec": ["e_inj", "e_con", "rev_sur"]
  },
  "meters": "ALL",
  "resources": "ALL",
  "members": ["<member_uuid>"]
}

See the Settlement Guide for a full description of all available output fields.